Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Cross-merge networking fixes after downstream PR (net-7.2-rc6).

No conflicts.

Adjacent changes:

net/ipv4/route.c
  dbc3791e3b ("net: do not send ICMP/NDISC Redirects when peer allocation fails")
  7804eaa057 ("ipv4: snapshot dst.dev in ip_rt_send_redirect() and ip_rt_get_source()")

drivers/net/tun.c
  23dad2d088 ("tun: no longer rely on RTNL in tun_fill_info()")
  c3da92af07 ("Revert "tun/tap: add ptr_ring consume helper with netdev queue wakeup"")

drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
  3bd438a58e ("octeontx2-af: Block VFs from clobbering special CGX PKIND state")
  5ba5611ef9 ("octeontx2-af: reserve 4 PKINDs for skip-size custom use")

drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/peer.c
  469d7e6077 ("wifi: ath12k: resolve PENDING ML peer ID from MLO_PEER_MAP HTT event")
  378e659029 ("wifi: ath12k: introduce host_alloc_ml_id hardware parameter")
  c42b27336e ("wifi: ath12k: fix survey indexing across bands")

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-07-23 14:04:37 -07:00
commit 5c45807355
476 changed files with 6691 additions and 2783 deletions

View File

@ -72,6 +72,7 @@ Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maxim@isovalent.com>
Alice Mikityanska <alice.kernel@fastmail.im> <alice@isovalent.com>
Aloka Dixit <quic_alokad@quicinc.com> <alokad@codeaurora.org>
Alvin Šipraga <alvin.sipraga@analog.com> <alsi@bang-olufsen.dk>
Al Viro <viro@ftp.linux.org.uk>
Al Viro <viro@zenIV.linux.org.uk>
Amit Blay <quic_ablay@quicinc.com> <ablay@codeaurora.org>
@ -296,6 +297,7 @@ Frank Rowand <frowand.list@gmail.com> <frank.rowand@sony.com>
Frank Rowand <frowand.list@gmail.com> <frank.rowand@sonymobile.com>
Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com>
Frank Zago <fzago@systemfabricworks.com>
Fuad Tabba <fuad.tabba@linux.dev> <tabba@google.com>
Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
@ -545,6 +547,7 @@ Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
Maciej W. Rozycki <macro@orcam.me.uk> <macro@linux-mips.org>
Maharaja Kennadyrajan <quic_mkenna@quicinc.com> <mkenna@codeaurora.org>
Maheshwar Ajja <quic_majja@quicinc.com> <majja@codeaurora.org>
Maíra Canal <mairacanal@riseup.net> <maira.canal@usp.br>
Malathi Gottam <quic_mgottam@quicinc.com> <mgottam@codeaurora.org>
Manikanta Pubbisetty <quic_mpubbise@quicinc.com> <mpubbise@codeaurora.org>
Manivannan Sadhasivam <mani@kernel.org> <manivannanece23@gmail.com>

View File

@ -55,10 +55,14 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne | AC03_CPU_38 | AMPERE_ERRATUM_AC03_CPU_38 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne | AC03_CPU_57 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_10 | AMPERE_ERRATUM_AC03_CPU_38 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_23 | AMPERE_ERRATUM_AC04_CPU_23 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_29 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A510 | #2457168 | ARM64_ERRATUM_2457168 |
+----------------+-----------------+-----------------+-----------------------------+

View File

@ -24,7 +24,11 @@ allOf:
properties:
compatible:
const: spacemit,k1-spi
oneOf:
- const: spacemit,k1-spi
- items:
- const: spacemit,k3-spi
- const: spacemit,k1-spi
reg:
maxItems: 1

View File

@ -43,12 +43,13 @@ UMEM also has two rings: the FILL ring and the COMPLETION ring. The
FILL ring is used by the application to send down addr for the kernel
to fill in with RX packet data. References to these frames will then
appear in the RX ring once each packet has been received. The
COMPLETION ring, on the other hand, contains frame addr that the
kernel has transmitted completely and can now be used again by user
space, for either TX or RX. Thus, the frame addrs appearing in the
COMPLETION ring are addrs that were previously transmitted using the
TX ring. In summary, the RX and FILL rings are used for the RX path
and the TX and COMPLETION rings are used for the TX path.
COMPLETION ring, on the other hand, contains frame addresses from Tx
descriptors that the kernel has finished processing and that can now be
used again by user space, for either Tx or Rx. This includes frames whose
transmission has completed as well as frames referenced by invalid Tx
descriptors rejected by the kernel. A completion therefore returns
ownership of a frame to user space, but does not by itself guarantee that
the packet was successfully transmitted.
The socket is then finally bound with a bind() call to a device and a
specific queue id on that device, and it is not until bind is
@ -169,14 +170,15 @@ chunks mode, then the incoming addr will be left untouched.
UMEM Completion Ring
~~~~~~~~~~~~~~~~~~~~
The COMPLETION Ring is used transfer ownership of UMEM frames from
The COMPLETION Ring is used to transfer ownership of UMEM frames from
kernel-space to user-space. Just like the FILL ring, UMEM indices are
used.
Frames passed from the kernel to user-space are frames that has been
sent (TX ring) and can be used by user-space again.
The user application consumes UMEM addrs from this ring.
used. Frames passed from the kernel to user-space are frames referenced
by Tx descriptors that the kernel has finished processing and can be
used by user-space again. This includes both frames whose transmission
has completed and frames referenced by invalid Tx descriptors that were
rejected and reclaimed by the kernel. A completion entry does not
guarantee successful packet transmission. The user application consumes
UMEM addrs from this ring.
RX Ring
@ -504,21 +506,25 @@ will be treated as an invalid descriptor.
These are the semantics for producing packets onto AF_XDP Tx ring
consisting of multiple frames:
* When an invalid descriptor is found, all the other
descriptors/frames of this packet are marked as invalid and not
completed. The next descriptor is treated as the start of a new
packet, even if this was not the intent (because we cannot guess
the intent). As before, if your program is producing invalid
descriptors you have a bug that must be fixed.
* When an invalid descriptor is found, the complete packet is treated as
invalid. The kernel consumes descriptors through the descriptor marking
the end of the packet and returns all their frame addresses through the
COMPLETION ring. A standalone invalid descriptor is treated as a
one-descriptor invalid packet. The descriptor following the end of the
invalid packet is treated as the start of a new packet. As before, if
your program is producing invalid descriptors you have a bug that must
be fixed. Rejected descriptors are reported in the ``tx_invalid_descs``
statistic.
* Zero length descriptors are treated as invalid descriptors.
* For copy mode, the maximum supported number of frames in a packet is
equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all
descriptors accumulated so far are dropped and treated as
invalid. To produce an application that will work on any system
regardless of this config setting, limit the number of frags to 18,
as the minimum value of the config is 17.
equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all descriptors
through the end of the oversized packet are consumed, treated as invalid,
and their frame addresses are returned through the COMPLETION ring. To
produce an application that will work on any system regardless of this
config setting, limit the number of frags to 18, as the minimum value of
the config is 17.
* For zero-copy mode, the limit is up to what the NIC HW
supports. Usually at least five on the NICs we have checked. We

View File

@ -8414,6 +8414,12 @@ When this capability is enabled all memory in memslots must be mapped as
attempts to create a memslot with an invalid mmap will result in an
-EINVAL return.
``guest_memfd``, even though it is an anonymous file, is not supported with MTE.
Attempting to create a memslot backed by ``guest_memfd`` when the MTE capability
is enabled, or attempting to enable the MTE capability after
``guest_memfd``-backed memslots have been created, will result in an -EINVAL
return.
When enabled the VMM may make use of the ``KVM_ARM_MTE_COPY_TAGS`` ioctl to
perform a bulk copy of tags to/from the guest.

View File

@ -112,9 +112,20 @@ Groups:
mask or unmask the adapter, as specified in mask
KVM_S390_IO_ADAPTER_MAP
This is now a no-op. The mapping is purely done by the irq route.
Map an adapter indicator or summary page for long-term pinning so that
interrupt injection can be performed in atomic context. If long-term
pinning is not possible (e.g. file-backed memory), the page is verified
via a short-term pin and the ioctl returns success; interrupt injection
will use the non-atomic irqfd path with short-term pinning on each
interrupt. In Secure Execution mode this is a no-op and the ioctl
returns success.
KVM_S390_IO_ADAPTER_UNMAP
This is now a no-op. The mapping is purely done by the irq route.
Unmap a previously mapped adapter indicator or summary page and release
the long-term pin. If the page was not long-term pinned (e.g. file-backed
memory), the map entry is removed and success is returned; if no prior
map entry exists, -ENOENT is returned. In Secure Execution mode this is
a no-op and the ioctl returns success.
KVM_DEV_FLIC_AISM
modify the adapter-interruption-suppression mode for a given isc if the

View File

@ -6492,7 +6492,7 @@ L: linux-cifs@vger.kernel.org
L: samba-technical@lists.samba.org (moderated for non-subscribers)
S: Supported
W: https://wiki.samba.org/index.php/LinuxCIFS
T: git https://git.samba.org/sfrench/cifs-2.6.git
T: git https://git.samba.org/sfrench/cifs-2.6.git for-next
F: Documentation/admin-guide/cifs/
F: fs/smb/client/
F: fs/smb/common/
@ -9626,7 +9626,7 @@ M: Chao Yu <chao@kernel.org>
R: Yue Hu <zbestahu@gmail.com>
R: Jeffle Xu <jefflexu@linux.alibaba.com>
R: Sandeep Dhavale <dhavale@google.com>
R: Hongbo Li <lihongbo22@huawei.com>
R: Hongbo Li <hongbohbli@tencent.com>
R: Chunhai Guo <guochunhai@vivo.com>
L: linux-erofs@lists.ozlabs.org
S: Maintained
@ -11117,6 +11117,7 @@ F: drivers/platform/x86/gpd-pocket-fan.c
GPIB DRIVERS
M: Dave Penkler <dpenkler@gmail.com>
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
S: Maintained
F: drivers/gpib/
F: include/uapi/linux/gpib.h
@ -14151,7 +14152,7 @@ R: Sergey Senozhatsky <senozhatsky@chromium.org>
R: Tom Talpey <tom@talpey.com>
L: linux-cifs@vger.kernel.org
S: Maintained
T: git https://git.samba.org/ksmbd.git
T: git https://git.samba.org/ksmbd.git ksmbd-for-next
F: Documentation/filesystems/smb/ksmbd.rst
F: fs/smb/common/
F: fs/smb/server/
@ -14201,7 +14202,7 @@ F: virt/kvm/*
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
M: Marc Zyngier <maz@kernel.org>
M: Oliver Upton <oupton@kernel.org>
R: Fuad Tabba <tabba@google.com>
R: Fuad Tabba <fuad.tabba@linux.dev>
R: Joey Gouly <joey.gouly@arm.com>
R: Steffen Eiden <seiden@linux.ibm.com>
R: Suzuki K Poulose <suzuki.poulose@arm.com>
@ -14895,7 +14896,7 @@ X: drivers/macintosh/via-macii.c
LINUX FOR POWERPC (32-BIT AND 64-BIT)
M: Madhavan Srinivasan <maddy@linux.ibm.com>
M: Michael Ellerman <mpe@ellerman.id.au>
R: Michael Ellerman <mpe@ellerman.id.au>
R: Nicholas Piggin <npiggin@gmail.com>
R: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
L: linuxppc-dev@lists.ozlabs.org
@ -19318,7 +19319,7 @@ F: fs/ntfs3/
NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER
M: Elizabeth Figura <zfigura@codeweavers.com>
L: wine-devel@winehq.org
L: wine-devel@list.winehq.org
S: Supported
F: Documentation/userspace-api/ntsync.rst
F: drivers/misc/ntsync.c
@ -22768,7 +22769,8 @@ F: drivers/watchdog/realtek_otto_wdt.c
REALTEK RTL83xx SMI DSA ROUTER CHIPS
M: Linus Walleij <linusw@kernel.org>
M: Alvin Šipraga <alsi@bang-olufsen.dk>
M: Luiz Angelo Daros de Luca <luizluca@gmail.com>
R: Alvin Šipraga <alvin.sipraga@analog.com>
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/realtek.yaml
F: drivers/net/dsa/realtek/*
@ -24665,8 +24667,7 @@ SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
M: D. Wythe <alibuda@linux.alibaba.com>
M: Dust Li <dust.li@linux.alibaba.com>
M: Sidraya Jayagond <sidraya@linux.ibm.com>
M: Wenjia Zhang <wenjia@linux.ibm.com>
R: Mahanta Jambigi <mjambigi@linux.ibm.com>
M: Mahanta Jambigi <mjambigi@linux.ibm.com>
R: Tony Lu <tonylu@linux.alibaba.com>
R: Wen Gu <guwen@linux.alibaba.com>
L: linux-rdma@vger.kernel.org
@ -29433,7 +29434,7 @@ F: net/xdp/
F: tools/testing/selftests/bpf/*xsk*
XEN BLOCK SUBSYSTEM
M: Roger Pau Monné <roger.pau@citrix.com>
M: Roger Pau Monné <roger@xenproject.org>
L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
S: Supported
F: drivers/block/xen*

View File

@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 2
SUBLEVEL = 0
EXTRAVERSION = -rc4
EXTRAVERSION = -rc5
NAME = Baby Opossum Posse
# *DOCUMENTATION*
@ -475,6 +475,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
# These flags apply to all Rust code in the tree, including the kernel and
# host programs.
#
# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our
# MSRV. It can trigger depending on the optimization level.
# [1] https://github.com/rust-lang/rust-clippy/issues/17379
export rust_common_flags := --edition=2021 \
-Zbinary_dep_depinfo=y \
-Astable_features \
@ -503,6 +507,7 @@ export rust_common_flags := --edition=2021 \
-Aclippy::uninlined_format_args \
-Wclippy::unnecessary_safety_comment \
-Wclippy::unnecessary_safety_doc \
-Aclippy::unwrap_or_default \
-Wrustdoc::missing_crate_level_docs \
-Wrustdoc::unescaped_backticks

View File

@ -131,7 +131,7 @@
* Annoyingly, the negative levels for Address size faults aren't laid out
* contiguously (or in the desired order)
*/
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x25 : 0x2C)
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x29 : 0x2C)
#define ESR_ELx_FSC_ADDRSZ_L(n) ((n) < 0 ? ESR_ELx_FSC_ADDRSZ_nL(n) : \
(ESR_ELx_FSC_ADDRSZ + (n)))

View File

@ -78,8 +78,12 @@ enum fixed_addresses {
/*
* Temporary boot-time mappings, used by early_ioremap(),
* before ioremap() is functional.
*
* Reserve one extra page so a 256K mapping may start at any
* offset within a page. early_ioremap() maps the page-aligned
* physical range, so the initial offset can consume an extra page.
*/
#define NR_FIX_BTMAPS (SZ_256K / PAGE_SIZE)
#define NR_FIX_BTMAPS ((SZ_256K / PAGE_SIZE) + 1)
#define FIX_BTMAPS_SLOTS 7
#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)

View File

@ -26,6 +26,12 @@
struct prev_kprobe {
struct kprobe *kp;
unsigned int status;
/*
* The original DAIF state of the outer kprobe, saved here before
* a nested kprobe overwrites kcb->saved_irqflag during reentry.
*/
unsigned long saved_irqflag;
};
/* per-cpu kprobe control block */

View File

@ -12,6 +12,7 @@
enum hyp_enter_exit_reason {
HYP_REASON_SMC,
HYP_REASON_HVC,
HYP_REASON_SYS,
HYP_REASON_PSCI,
HYP_REASON_HOST_ABORT,
HYP_REASON_GUEST_EXIT,

View File

@ -174,12 +174,27 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kcb->prev_kprobe.kp = kprobe_running();
kcb->prev_kprobe.status = kcb->kprobe_status;
/*
* Save the outer kprobe's original DAIF flags before the nested
* kprobe calls kprobes_save_local_irqflag() and overwrites
* kcb->saved_irqflag. Without this, the outer kprobe will restore
* the wrong DAIF state and leave interrupts permanently masked.
*/
kcb->prev_kprobe.saved_irqflag = kcb->saved_irqflag;
}
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
kcb->kprobe_status = kcb->prev_kprobe.status;
/*
* Restore the outer kprobe's saved_irqflag so that when its
* single-step completes, kprobes_restore_local_irqflag() uses
* the correct original DAIF value.
*/
kcb->saved_irqflag = kcb->prev_kprobe.saved_irqflag;
}
static void __kprobes set_current_kprobe(struct kprobe *p)
@ -240,10 +255,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
switch (kcb->kprobe_status) {
case KPROBE_HIT_SSDONE:
case KPROBE_HIT_ACTIVE:
case KPROBE_HIT_SS:
/*
* A probe can be hit while another kprobe is preparing or
* executing its XOL single-step instruction. This is still a
* recoverable one-level reentry, so handle it in the same way as
* reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
*/
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs, kcb, 1);
break;
case KPROBE_HIT_SS:
case KPROBE_REENTER:
pr_warn("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
@ -282,9 +303,31 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
/*
* Simulated kprobes execute in the debug trap context and have no
* XOL slot. Any page fault taken while a simulated kprobe is in
* progress cannot have been caused by kprobe single-stepping and
* must be left alone for the normal page fault handler, including
* fixup_exception.
*/
if (cur && !cur->ainsn.xol_insn)
return 0;
switch (kcb->kprobe_status) {
case KPROBE_HIT_SS:
case KPROBE_REENTER:
/*
* A page fault taken while in KPROBE_HIT_SS or
* KPROBE_REENTER state is only attributable to kprobe
* single-stepping if the faulting PC points to the
* current kprobe's XOL instruction. If the fault occurred
* elsewhere (e.g. in perf or tracing code invoked from the
* debug exception path), leave it for the normal page fault
* handler to process.
*/
if (instruction_pointer(regs) != (unsigned long)cur->ainsn.xol_insn)
break;
/*
* We are here because the instruction being single
* stepped caused a page fault. We reset the current

View File

@ -149,14 +149,27 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
set_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
&kvm->arch.flags);
break;
case KVM_CAP_ARM_MTE:
mutex_lock(&kvm->lock);
if (system_supports_mte() && !kvm->created_vcpus) {
r = 0;
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
case KVM_CAP_ARM_MTE: {
struct kvm_memory_slot *memslot;
int bkt;
guard(mutex)(&kvm->lock);
if (!system_supports_mte() || kvm->created_vcpus)
break;
r = 0;
guard(mutex)(&kvm->slots_lock);
kvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm)) {
if (kvm_slot_has_gmem(memslot)) {
r = -EINVAL;
break;
}
}
mutex_unlock(&kvm->lock);
if (r == 0)
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
break;
}
case KVM_CAP_ARM_SYSTEM_SUSPEND:
r = 0;
set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);

View File

@ -932,6 +932,7 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
handle_host_mem_abort(host_ctxt);
break;
case ESR_ELx_EC_SYS64:
trace_hyp_enter(host_ctxt, HYP_REASON_SYS);
if (handle_host_mte(esr))
break;
fallthrough;

View File

@ -37,8 +37,6 @@ static struct hyp_trace_clock {
u32 shift;
struct delayed_work work;
struct completion ready;
struct mutex lock;
bool running;
} hyp_clock;
static void __hyp_clock_work(struct work_struct *work)
@ -110,12 +108,9 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
{
struct system_time_snapshot snap;
if (hyp_clock->running == enable)
return;
if (!enable) {
cancel_delayed_work_sync(&hyp_clock->work);
hyp_clock->running = false;
return;
}
ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
@ -128,7 +123,6 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
INIT_DELAYED_WORK(&hyp_clock->work, __hyp_clock_work);
schedule_delayed_work(&hyp_clock->work, msecs_to_jiffies(CLOCK_INIT_MS));
wait_for_completion(&hyp_clock->ready);
hyp_clock->running = true;
}
/* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
@ -160,6 +154,7 @@ static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_
int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
size_t backing_size;
void *start;
int ret;
backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages *
num_possible_cpus());
@ -168,10 +163,16 @@ static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_
if (!start)
return -ENOMEM;
ret = __map_hyp(start, backing_size);
if (ret) {
free_pages_exact(start, backing_size);
return ret;
}
trace_buffer->desc->bpages_backing_start = (unsigned long)start;
trace_buffer->desc->bpages_backing_size = backing_size;
return __map_hyp(start, backing_size);
return ret;
}
static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer)
@ -228,18 +229,22 @@ static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
{
struct hyp_trace_buffer *trace_buffer = priv;
size_t desc_size, tb_desc_size;
struct hyp_trace_desc *desc;
size_t desc_size;
int ret;
if (WARN_ON(trace_buffer->desc))
return ERR_PTR(-EINVAL);
desc_size = trace_buffer_desc_size(size, num_possible_cpus());
tb_desc_size = trace_buffer_desc_size(size, num_possible_cpus());
desc_size = size_add(tb_desc_size, offsetof(struct hyp_trace_desc, trace_buffer_desc));
if (desc_size == SIZE_MAX)
return ERR_PTR(-E2BIG);
desc_size = PAGE_ALIGN(desc_size);
if (!desc_size)
return ERR_PTR(-E2BIG);
desc = (struct hyp_trace_desc *)alloc_pages_exact(desc_size, GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
@ -255,7 +260,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
if (ret)
goto err_free_desc;
ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, desc_size, size,
ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, tb_desc_size, size,
cpu_possible_mask);
if (ret)
goto err_free_backing;
@ -304,9 +309,15 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
static int hyp_trace_enable_tracing(bool enable, void *priv)
{
int ret;
hyp_trace_clock_enable(&hyp_clock, enable);
return kvm_call_hyp_nvhe(__tracing_enable, enable);
ret = kvm_call_hyp_nvhe(__tracing_enable, enable);
if (ret)
hyp_trace_clock_enable(&hyp_clock, !enable);
return ret;
}
static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
@ -398,6 +409,7 @@ static const char *__hyp_enter_exit_reason_str(u8 reason)
static const char strs[][12] = {
"smc",
"hvc",
"sys",
"psci",
"host_abort",
"guest_exit",

View File

@ -2652,6 +2652,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new))
return -EINVAL;
/* guest_memfd is incompatible with MTE. */
if (kvm_slot_has_gmem(new) && kvm_has_mte(kvm))
return -EINVAL;
hva = new->userspace_addr;
reg_end = hva + (new->npages << PAGE_SHIFT);

View File

@ -116,18 +116,27 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
kfree(irq);
irq = oldirq;
} else {
ret = xa_err(__xa_store(&dist->lpi_xa, intid, irq, 0));
/*
* The entry is either empty or contains a dead LPI (refcount=0)
* from the deferred release path, pending cleanup by
* vgic_release_deleted_lpis(). Evict and free it if present.
*/
oldirq = __xa_store(&dist->lpi_xa, intid, irq,
GFP_NOWAIT | __GFP_ACCOUNT);
ret = xa_err(oldirq);
if (ret) {
xa_unlock_irqrestore(&dist->lpi_xa, flags);
kfree(irq);
return ERR_PTR(ret);
}
if (oldirq && !WARN_ON_ONCE(refcount_read(&oldirq->refcount)))
kfree_rcu(oldirq, rcu);
}
xa_unlock_irqrestore(&dist->lpi_xa, flags);
if (ret) {
xa_release(&dist->lpi_xa, intid);
kfree(irq);
return ERR_PTR(ret);
}
/*
* We "cache" the configuration table entries in our struct vgic_irq's.
* However we only have those structs for mapped IRQs, so we read in

View File

@ -275,7 +275,13 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
}
if (lr & ICH_LR_HW)
/*
* In the nested state, the irq has already been deactivated via the HW
* bit in the LR. Deactivating again would be harmless except AmpereOne
* errata AC03_CPU_57, AC04_CPU_29 could cause irq delivery to break if
* the deactivation hits the highest priority pending irq.
*/
if ((lr & ICH_LR_HW) && !vgic_state_is_nested(vcpu))
vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
vgic_v3_fold_lr(vcpu, lr);

View File

@ -146,11 +146,7 @@ static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
static __must_check bool vgic_put_irq_norelease(struct kvm *kvm, struct vgic_irq *irq)
{
if (!__vgic_put_irq(kvm, irq))
return false;
irq->pending_release = true;
return true;
return __vgic_put_irq(kvm, irq);
}
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
@ -167,12 +163,14 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
}
if (!__vgic_put_irq(kvm, irq))
if (!irq_is_lpi(kvm, irq->intid))
return;
xa_lock_irqsave(&dist->lpi_xa, flags);
vgic_release_lpi_locked(dist, irq);
xa_unlock_irqrestore(&dist->lpi_xa, flags);
if (refcount_dec_and_lock_irqsave(&irq->refcount,
&dist->lpi_xa.xa_lock, &flags)) {
vgic_release_lpi_locked(dist, irq);
xa_unlock_irqrestore(&dist->lpi_xa, flags);
}
}
static void vgic_release_deleted_lpis(struct kvm *kvm)
@ -184,7 +182,7 @@ static void vgic_release_deleted_lpis(struct kvm *kvm)
xa_lock_irqsave(&dist->lpi_xa, flags);
xa_for_each(&dist->lpi_xa, intid, irq) {
if (irq->pending_release)
if (!refcount_read(&irq->refcount))
vgic_release_lpi_locked(dist, irq);
}

View File

@ -76,6 +76,8 @@ static void data_abort_decode(unsigned long esr)
pr_alert(" SF = %lu, AR = %lu\n",
(esr & ESR_ELx_SF) >> ESR_ELx_SF_SHIFT,
(esr & ESR_ELx_AR) >> ESR_ELx_AR_SHIFT);
pr_alert(" Xs = %llu\n",
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
} else {
pr_alert(" ISV = 0, ISS = 0x%08lx, ISS2 = 0x%08lx\n",
esr & ESR_ELx_ISS_MASK, iss2);
@ -87,11 +89,10 @@ static void data_abort_decode(unsigned long esr)
(iss2 & ESR_ELx_TnD) >> ESR_ELx_TnD_SHIFT,
(iss2 & ESR_ELx_TagAccess) >> ESR_ELx_TagAccess_SHIFT);
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu, Xs = %llu\n",
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu\n",
(iss2 & ESR_ELx_GCS) >> ESR_ELx_GCS_SHIFT,
(iss2 & ESR_ELx_Overlay) >> ESR_ELx_Overlay_SHIFT,
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT,
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT);
}
static void mem_abort_decode(unsigned long esr)

View File

@ -87,7 +87,7 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
p4dp = p4d_offset(pgdp, addr);
pudp = pud_offset(p4dp, addr);
pmdp = pmd_offset(pudp, addr);
if ((pte_t *)pmdp == ptep) {
if ((pte_t *)PTR_ALIGN_DOWN(pmdp, sizeof(*pmdp) * CONT_PMDS) == ptep) {
*pgsize = PMD_SIZE;
return CONT_PMDS;
}

View File

@ -2194,7 +2194,7 @@ static int prevent_memory_remove_notifier(struct notifier_block *nb,
}
}
if (!can_unmap_without_split(pfn, arg->nr_pages))
if (!can_unmap_without_split(arg->start_pfn, arg->nr_pages))
return NOTIFY_BAD;
return NOTIFY_OK;

View File

@ -14,7 +14,7 @@
#ifdef CONFIG_64BIT
#define TASK_STRUCT_OFFSET 0
#else
#define TASK_STRUCT_OFFSET 2000
#define TASK_STRUCT_OFFSET 2040
#endif
.macro cpu_save_nonscratch thread

View File

@ -201,10 +201,12 @@ static void __init acpi_process_madt(void)
}
int pptt_enabled;
static int acpi_nr_packages;
static int acpi_package_ids[MAX_PACKAGES];
int __init parse_acpi_topology(void)
{
int cpu, topology_id;
int i, cpu, topology_id;
for_each_possible_cpu(cpu) {
topology_id = find_acpi_cpu_topology(cpu, 0);
@ -222,6 +224,29 @@ int __init parse_acpi_topology(void)
cpu_data[cpu].core = topology_id;
}
topology_id = find_acpi_cpu_topology_package(cpu);
if (topology_id < 0) {
pr_warn("Invalid BIOS PPTT\n");
return -ENOENT;
}
for (i = 0; i < acpi_nr_packages; i++)
if (acpi_package_ids[i] == topology_id)
break;
if (i == acpi_nr_packages)
acpi_package_ids[acpi_nr_packages++] = topology_id;
cpu_data[cpu].package = topology_id;
}
for_each_possible_cpu(cpu) {
for (i = 0; i < acpi_nr_packages; i++)
if (cpu_data[cpu].package == acpi_package_ids[i]) {
cpu_data[cpu].package = i; /* Canonicalize */
break;
}
}
pptt_enabled = 1;

View File

@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd,
if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(smp_processor_id(), regs);
if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
if (kgdb_handle_exception(regs->csr_era == stepped_address ? 0 : args->trapnr,
args->signr, cmd, regs))
return NOTIFY_DONE;
if (atomic_read(&kgdb_setting_breakpoint))

View File

@ -42,6 +42,7 @@ static unsigned long first_ind_entry;
int machine_kexec_prepare(struct kimage *kimage)
{
int i;
char head[8];
char *bootloader = "kexec";
void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR;
@ -59,7 +60,9 @@ int machine_kexec_prepare(struct kimage *kimage)
} else {
/* Find the command line */
for (i = 0; i < kimage->nr_segments; i++) {
if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
if (copy_from_user(head, kimage->segment[i].buf, strlen(bootloader)))
continue;
if (!strncmp(bootloader, head, strlen(bootloader))) {
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
break;

View File

@ -71,27 +71,27 @@
cfi_ld s7, PT_R30
cfi_ld s8, PT_R31
LONG_L t0, sp, PT_CRMD
li.d t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
LONG_LI t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
csrxchg t0, t1, LOONGARCH_CSR_CRMD
.endm
SYM_CODE_START(arch_rethook_trampoline)
UNWIND_HINT_UNDEFINED
addi.d sp, sp, -PT_SIZE
PTR_ADDI sp, sp, -PT_SIZE
save_all_base_regs
addi.d t0, sp, PT_SIZE
LONG_S t0, sp, PT_R3
PTR_ADDI t0, sp, PT_SIZE
LONG_S t0, sp, PT_R3
move a0, sp /* pt_regs */
move a0, sp /* pt_regs */
bl arch_rethook_trampoline_callback
bl arch_rethook_trampoline_callback
/* use the result as the return-address */
move ra, a0
move ra, a0
restore_all_base_regs
addi.d sp, sp, PT_SIZE
PTR_ADDI sp, sp, PT_SIZE
jr ra
jr ra
SYM_CODE_END(arch_rethook_trampoline)

View File

@ -603,6 +603,7 @@ void __init setup_arch(char **cmdline_p)
memblock_init();
pagetable_init();
bootcmdline_init(cmdline_p);
jump_label_init(); /* Initialise the static keys for early params */
parse_early_param();
reserve_initrd_mem();
@ -610,8 +611,6 @@ void __init setup_arch(char **cmdline_p)
arch_mem_init(cmdline_p);
resource_init();
jump_label_init(); /* Initialise the static keys for paravirtualization */
#ifdef CONFIG_SMP
plat_smp_setup();
prefill_possible_map();

View File

@ -426,10 +426,10 @@ void loongson_init_secondary(void)
numa_add_cpu(cpu);
#endif
per_cpu(cpu_state, cpu) = CPU_ONLINE;
cpu_data[cpu].package =
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core :
cpu_logical_map(cpu) % loongson_sysconf.cores_per_package;
cpu_data[cpu].package = pptt_enabled ? cpu_data[cpu].package :
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
cpu_data[cpu].global_id = cpu_logical_map(cpu);
}

View File

@ -835,7 +835,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
move_reg(ctx, t1, src);
emit_sext_32(ctx, t1, is32);
emit_insn(ctx, divd, dst, dst, t1);
emit_sext_32(ctx, dst, is32);
emit_zext_32(ctx, dst, is32);
}
break;
@ -852,7 +852,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
emit_sext_32(ctx, t1, is32);
emit_sext_32(ctx, dst, is32);
emit_insn(ctx, divd, dst, dst, t1);
emit_sext_32(ctx, dst, is32);
emit_zext_32(ctx, dst, is32);
}
break;
@ -870,7 +870,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
move_reg(ctx, t1, src);
emit_sext_32(ctx, t1, is32);
emit_insn(ctx, modd, dst, dst, t1);
emit_sext_32(ctx, dst, is32);
emit_zext_32(ctx, dst, is32);
}
break;
@ -887,7 +887,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
emit_sext_32(ctx, t1, is32);
emit_sext_32(ctx, dst, is32);
emit_insn(ctx, modd, dst, dst, t1);
emit_sext_32(ctx, dst, is32);
emit_zext_32(ctx, dst, is32);
}
break;
@ -2361,6 +2361,7 @@ void bpf_jit_free(struct bpf_prog *prog)
*/
if (jit_data) {
bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header);
kvfree(jit_data->ctx.offset);
kfree(jit_data);
}
hdr = bpf_jit_binary_pack_hdr(prog);

View File

@ -110,7 +110,7 @@ void wildfiremod_halt(void)
printk(KERN_INFO "WildFireMod hibernating...\n");
/* Set portE.5 to Digital IO */
mcf_write16(read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
mcf_write16(mcf_read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
/* Make portE.5 an output */
mcf_write8(mcf_read8(MCFGPIO_PDDR_E) | (1 << 5), MCFGPIO_PDDR_E);

View File

@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
/* finally, setup the timebase */
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -146,7 +146,7 @@ void platform_init(char *userdata)
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -102,7 +102,7 @@ void platform_init(void)
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -66,6 +66,13 @@ static inline void srr_regs_clobbered(void)
static inline void nap_adjust_return(struct pt_regs *regs)
{
#ifdef CONFIG_PPC_970_NAP
/*
* Adjust the nap return address before irq_exit_rcu(). irq_exit_rcu()
* may invoke softirqs with interrupts re-enabled, allowing a nested
* async interrupt to arrive. If _TLF_NAPPING is still set at that
* point, the nested interrupt would erroneously redirect its own
* return address to power4_idle_nap_return, corrupting the stack.
*/
if (unlikely(test_thread_local_flags(_TLF_NAPPING))) {
/* Can avoid a test-and-clear because NMIs do not call this */
clear_thread_local_flags(_TLF_NAPPING);
@ -286,14 +293,6 @@ static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs)
static inline void arch_interrupt_async_exit_prepare(struct pt_regs *regs)
{
/*
* Adjust at exit so the main handler sees the true NIA. This must
* come before irq_exit() because irq_exit can enable interrupts, and
* if another interrupt is taken before nap_adjust_return has run
* here, then that interrupt would return directly to idle nap return.
*/
nap_adjust_return(regs);
arch_interrupt_exit_prepare(regs);
}

View File

@ -246,6 +246,7 @@ interrupt_handler void func(struct pt_regs *regs) \
instrumentation_begin(); \
irq_enter_rcu(); \
____##func (regs); \
nap_adjust_return(regs); \
irq_exit_rcu(); \
instrumentation_end(); \
arch_interrupt_async_exit_prepare(regs); \

View File

@ -53,9 +53,6 @@ struct pt_regs
unsigned long esr;
};
unsigned long result;
unsigned long exit_flags;
/* Maintain 16 byte interrupt stack alignment */
unsigned long __pt_regs_pad[3];
};
};
#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_KUAP)

View File

@ -1,6 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*/
#ifndef _ASM_POWERPC_SERIAL_H
#define _ASM_POWERPC_SERIAL_H
@ -18,4 +16,4 @@ extern void find_legacy_serial_ports(void);
#define find_legacy_serial_ports() do { } while (0)
#endif
#endif /* _PPC64_SERIAL_H */
#endif /* _ASM_POWERPC_SERIAL_H */

View File

@ -57,6 +57,7 @@ struct thread_info {
#ifdef CONFIG_SMP
unsigned int cpu;
#endif
unsigned long exit_flags; /* Exit Flags for entry/exit */
unsigned long syscall_work; /* SYSCALL_WORK_ flags */
unsigned long local_flags; /* private flags for thread */
#ifdef CONFIG_LIVEPATCH_64

View File

@ -55,8 +55,6 @@ struct pt_regs
unsigned long dar; /* Fault registers */
unsigned long dsisr; /* on 4xx/Book-E used for ESR */
unsigned long result; /* Result of a system call */
unsigned long exit_flags; /* System call exit flags */
unsigned long __pt_regs_pad[3]; /* Maintain 16 byte interrupt stack alignment */
};
#endif /* __ASSEMBLER__ */
@ -116,12 +114,10 @@ struct pt_regs
#define PT_DAR 41
#define PT_DSISR 42
#define PT_RESULT 43
#define PT_EXIT_FLAGS 44
#define PT_PAD 47 /* 3 times */
#define PT_DSCR 48
#define PT_REGS_COUNT 48
#define PT_DSCR 44
#define PT_REGS_COUNT 44
#define PT_FPR0 (PT_REGS_COUNT + 4) /* each FP reg occupies 2 slots in this space */
#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
#ifndef __powerpc64__
@ -133,7 +129,7 @@ struct pt_regs
#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */
#define PT_VR0 (PT_FPSCR + 2) /* <82> each Vector reg occupies 2 slots in 64-bit */
#define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */
#define PT_VSCR (PT_VR0 + 32*2 + 1)
#define PT_VRSAVE (PT_VR0 + 33*2)
@ -141,7 +137,7 @@ struct pt_regs
/*
* Only store first 32 VSRs here. The second 32 VSRs in VR0-31
*/
#define PT_VSR0 (PT_VRSAVE + 2) /* each VSR reg occupies 2 slots in 64-bit */
#define PT_VSR0 150 /* each VSR reg occupies 2 slots in 64-bit */
#define PT_VSR31 (PT_VSR0 + 2*31)
#endif /* __powerpc64__ */

View File

@ -89,15 +89,17 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
long scv)
{
unsigned long ti_flags;
unsigned long ret = 0;
bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv;
kuap_assert_locked();
regs->result = r3;
regs->exit_flags = 0;
/* Clear exit_flags so only flags set during this exit are visible */
current->thread_info.exit_flags = 0;
ti_flags = read_thread_flags();
if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) {
if (likely(!(ti_flags & (_TIF_NOERROR | _TIF_RESTOREALL)))) {
r3 = -r3;
@ -107,7 +109,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) {
if (ti_flags & _TIF_RESTOREALL)
regs->exit_flags = _TIF_RESTOREALL;
ret = _TIF_RESTOREALL;
else
regs->gpr[3] = r3;
clear_bits(_TIF_PERSYSCALL_MASK, &current_thread_info()->flags);
@ -116,7 +118,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
}
if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {
regs->exit_flags |= _TIF_RESTOREALL;
ret |= _TIF_RESTOREALL;
}
syscall_exit_to_user_mode(regs);
@ -132,17 +134,19 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
/* Restore user access locks last */
kuap_user_restore(regs);
ret |= current->thread_info.exit_flags;
#ifdef CONFIG_PPC64
regs->exit_result = regs->exit_flags;
regs->exit_result = ret;
#endif
return regs->exit_flags;
return ret;
}
#ifdef CONFIG_PPC64
notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs)
{
unsigned long ret;
/*
* This is called when detecting a soft-pending interrupt as well as
* an alternate-return interrupt. So we can't just have the alternate
@ -167,9 +171,11 @@ notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *reg
}
kuap_user_restore(regs);
regs->exit_result |= regs->exit_flags;
ret = current_thread_info()->exit_flags & _TIF_RESTOREALL;
current_thread_info()->exit_flags &= ~_TIF_RESTOREALL;
regs->exit_result |= ret;
return regs->exit_result;
return ret;
}
#endif
@ -186,8 +192,10 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
*/
kuap_assert_locked();
/* Clear exit_flags so only flags set during this exit are visible */
current_thread_info()->exit_flags = 0;
local_irq_disable();
regs->exit_flags = 0;
again:
check_return_regs_valid(regs);
user_enter_irqoff();
@ -200,9 +208,7 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
/* Restore user access locks last */
kuap_user_restore(regs);
ret = regs->exit_flags;
ret = current_thread_info()->exit_flags & _TIF_RESTOREALL;
#ifdef CONFIG_PPC64
regs->exit_result = ret;
#endif

View File

@ -291,7 +291,6 @@ void __init pt_regs_check(void)
CHECK_REG(PT_DAR, dar);
CHECK_REG(PT_DSISR, dsisr);
CHECK_REG(PT_RESULT, result);
CHECK_REG(PT_EXIT_FLAGS, exit_flags);
#undef CHECK_REG
BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long));

View File

@ -356,6 +356,6 @@ void signal_fault(struct task_struct *tsk, struct pt_regs *regs,
void arch_do_signal_or_restart(struct pt_regs *regs)
{
BUG_ON(regs != current->thread.regs);
regs->exit_flags |= _TIF_RESTOREALL;
current_thread_info()->exit_flags |= _TIF_RESTOREALL;
do_signal(current);
}

View File

@ -1023,10 +1023,7 @@ static int thread_imc_event_init(struct perf_event *event)
static bool is_thread_imc_pmu(struct perf_event *event)
{
if (!strncmp(event->pmu->name, "thread_imc", strlen("thread_imc")))
return true;
return false;
return strstarts(event->pmu->name, "thread_imc");
}
static __be64 *get_event_base_addr(struct perf_event *event)

View File

@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
fail_map:
for (iopage--; 0 <= iopage; iopage--) {
offset = (1 << r->page_size) * iopage;
lv1_put_iopte(0,
c->bus_addr + offset,
c->lpar_addr + offset,

View File

@ -191,8 +191,6 @@ static void spu_unmap(struct spu *spu)
static int __init setup_areas(struct spu *spu)
{
struct table {char* name; unsigned long addr; unsigned long size;};
spu_pdata(spu)->shadow = ioremap_prot(spu_pdata(spu)->shadow_addr,
sizeof(struct spe_shadow),
pgprot_noncached_wc(PAGE_KERNEL_RO));

View File

@ -20,12 +20,15 @@
void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
{
/*
* Don't risk a hypervisor call if we're crashing
* XXX: Why? The hypervisor is not crashing. It might be better
* to at least attempt unregister to avoid the hypervisor stepping
* on our memory.
* Ensure vpa/slb_shadow/dtl cleanup even while we are crashing.
* Why? The hypervisor is not crashing so at least attempt unregister to
* avoid the hypervisor stepping on our memory. If hypervisor or kexec
* kernel steps on the old memory allocated to these areas before the
* new kexec-kernel happens to allocate and register new areas,
* the hypervisor will see invalid content which may cause
* unexpected behavior.
*/
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
int ret;
int cpu = smp_processor_id();
int hwcpu = hard_smp_processor_id();

View File

@ -128,7 +128,12 @@ static void smp_setup_cpu(int cpu)
else if (cpu != boot_cpuid)
xics_setup_cpu();
if (firmware_has_feature(FW_FEATURE_SPLPAR))
/*
* Initialize VPA on non-boot cpus since boot-cpu vpa was
* already initialized in pSeries_setup_arch()
*/
if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
cpu != boot_cpuid)
vpa_init(cpu);
cpumask_clear_cpu(cpu, of_spin_mask);

View File

@ -476,6 +476,11 @@ struct s390_map_info {
__u64 guest_addr;
__u64 addr;
struct page *page;
/*
* True if the page is long-term pinned. False if long-term pinning
* failed and this entry exists only to preserve MAP/UNMAP symmetry.
*/
bool pinned;
};
struct s390_io_adapter {

View File

@ -2520,8 +2520,22 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
map->addr = host_addr;
map->page = pin_map_page(kvm, host_addr, FOLL_LONGTERM);
if (!map->page) {
ret = -EINVAL;
goto out;
/*
* Long-term pinning may fail for memory types such as file-backed
* memory. Verify that short-term pinning succeeds so that the
* non-atomic irqfd path can handle interrupt injection.
*/
map->page = pin_map_page(kvm, host_addr, 0);
if (!map->page) {
ret = -EINVAL;
goto out;
}
unpin_user_page(map->page);
map->page = NULL;
map->pinned = false;
/* Add an entry to preserve MAP/UNMAP symmetry. */
} else {
map->pinned = true;
}
spin_lock_irqsave(&adapter->maps_lock, flags);
if (adapter->nr_maps < MAX_S390_ADAPTER_MAPS) {
@ -2532,7 +2546,7 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
ret = -EINVAL;
}
spin_unlock_irqrestore(&adapter->maps_lock, flags);
if (ret)
if (ret && map->page)
unpin_user_page(map->page);
out:
if (ret)
@ -2546,6 +2560,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
struct s390_map_info *map, *tmp, *map_to_free;
struct page *map_page_to_put = NULL;
u64 map_addr_to_mark = 0;
bool map_pinned = false;
unsigned long flags;
int found = 0, idx;
@ -2560,6 +2575,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
list_del(&map->list);
map_page_to_put = map->page;
map_addr_to_mark = map->guest_addr;
map_pinned = map->pinned;
map_to_free = map;
break;
}
@ -2568,11 +2584,18 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
if (found) {
kfree(map_to_free);
idx = srcu_read_lock(&kvm->srcu);
mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
set_page_dirty_lock(map_page_to_put);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(map_page_to_put);
if (map_pinned) {
/*
* Only long-term pinned pages need to be marked dirty
* and released. Fallback entries exist only for
* MAP/UNMAP symmetry.
*/
idx = srcu_read_lock(&kvm->srcu);
mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
set_page_dirty_lock(map_page_to_put);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(map_page_to_put);
}
}
return found ? 0 : -ENOENT;
@ -2598,11 +2621,13 @@ void kvm_s390_unmap_all_adapters(struct kvm *kvm)
list_for_each_entry_safe(map, tmp, &local_list, list) {
list_del(&map->list);
idx = srcu_read_lock(&kvm->srcu);
mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
set_page_dirty_lock(map->page);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(map->page);
if (map->pinned) {
idx = srcu_read_lock(&kvm->srcu);
mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
set_page_dirty_lock(map->page);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(map->page);
}
kfree(map);
}
}
@ -2929,8 +2954,11 @@ static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
return NULL;
list_for_each_entry(map, &adapter->maps, list) {
if (map->addr == addr)
if (map->addr == addr) {
if (!map->pinned)
return NULL;
return map;
}
}
return NULL;
}

View File

@ -190,40 +190,61 @@ static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
return cc ? -EIO : 0;
}
static inline void unaccount_mem(unsigned long nr_pages)
static inline void unaccount_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
{
struct user_struct *user = get_uid(current_user());
struct user_struct *user = kzdev->user_account;
struct mm_struct *mm_account = kzdev->mm_account;
if (user)
if (user) {
atomic_long_sub(nr_pages, &user->locked_vm);
if (current->mm)
atomic64_sub(nr_pages, &current->mm->pinned_vm);
free_uid(user);
kzdev->user_account = NULL;
}
if (mm_account) {
atomic64_sub(nr_pages, &mm_account->pinned_vm);
mmdrop(mm_account);
kzdev->mm_account = NULL;
}
}
static inline int account_mem(unsigned long nr_pages)
static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
{
struct user_struct *user = get_uid(current_user());
unsigned long page_limit, cur_pages, new_pages;
int rc = 0;
page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
cur_pages = atomic_long_read(&user->locked_vm);
do {
new_pages = cur_pages + nr_pages;
if (new_pages > page_limit)
return -ENOMEM;
if (new_pages > page_limit) {
rc = -ENOMEM;
goto out;
}
} while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
atomic64_add(nr_pages, &current->mm->pinned_vm);
if (current->mm) {
mmgrab(current->mm);
atomic64_add(nr_pages, &current->mm->pinned_vm);
}
kzdev->user_account = user;
kzdev->mm_account = current->mm;
return 0;
out:
free_uid(user);
return rc;
}
static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
bool assist)
{
struct page *pages[1], *aibv_page, *aisb_page = NULL;
unsigned int msi_vecs, idx;
unsigned int msi_vecs, idx, size;
struct zpci_gaite *gaite;
unsigned long hva, bit;
struct kvm *kvm;
@ -237,6 +258,10 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
if (zdev->gisa == 0)
return -EINVAL;
/* AIF already enabled for the device */
if (zdev->kzdev->fib.fmt0.aibv != 0)
return -EINVAL;
kvm = zdev->kzdev->kvm;
msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
@ -246,6 +271,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
return gisc;
/* Replace AIBV address */
size = BITS_TO_LONGS(msi_vecs + fib->fmt0.aibvo) * sizeof(unsigned long);
npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
/* AIBV cannot span more than 1 page */
if (npages > 1) {
rc = -EINVAL;
goto out;
}
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
@ -261,6 +294,12 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
/* Pin the guest AISB if one was specified */
if (fib->fmt0.sum == 1) {
/* AISB must be dword aligned */
if (fib->fmt0.aisb & 0x7) {
rc = -EINVAL;
goto unpin1;
}
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
@ -275,20 +314,28 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
}
/* Account for pinned pages, roll back on failure */
if (account_mem(pcount))
rc = account_mem(zdev->kzdev, pcount);
if (rc)
goto unpin2;
/* AISB must be allocated before we can fill in GAITE */
mutex_lock(&aift->aift_lock);
bit = airq_iv_alloc_bit(aift->sbv);
if (bit == -1UL)
if (bit == -1UL) {
rc = -ENOMEM;
goto unlock;
}
zdev->aisb = bit; /* store the summary bit number */
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
AIRQ_IV_BITLOCK |
AIRQ_IV_GUESTVEC,
phys_to_virt(fib->fmt0.aibv));
if (!zdev->aibv) {
rc = -ENOMEM;
goto free_aisb;
}
spin_lock_irq(&aift->gait_lock);
gaite = aift->gait + zdev->aisb;
@ -311,21 +358,39 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
aift->kzdev[zdev->aisb] = zdev->kzdev;
spin_unlock_irq(&aift->gait_lock);
/* Update guest FIB for re-issue */
fib->fmt0.aisbo = zdev->aisb & 63;
fib->fmt0.aisb = virt_to_phys(aift->sbv->vector) + (zdev->aisb / 64) * 8;
fib->fmt0.isc = gisc;
/* Save some guest fib values in the host for later use */
zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
zdev->kzdev->fib.fmt0.isc = gisc;
zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
mutex_unlock(&aift->aift_lock);
/* Issue the clp to setup the irq now */
rc = kvm_zpci_set_airq(zdev);
return rc;
if (!rc) {
mutex_unlock(&aift->aift_lock);
return rc;
}
/* Start cleanup */
zdev->kzdev->fib.fmt0.isc = 0;
zdev->kzdev->fib.fmt0.aibv = 0;
spin_lock_irq(&aift->gait_lock);
gaite->count--;
gaite->aisb = 0;
gaite->gisc = 0;
gaite->aisbo = 0;
gaite->gisa = 0;
aift->kzdev[zdev->aisb] = NULL;
spin_unlock_irq(&aift->gait_lock);
airq_iv_release(zdev->aibv);
zdev->aibv = NULL;
free_aisb:
airq_iv_free_bit(aift->sbv, zdev->aisb);
zdev->aisb = 0;
unlock:
if (pcount > 0)
unaccount_mem(zdev->kzdev, pcount);
mutex_unlock(&aift->aift_lock);
unpin2:
if (fib->fmt0.sum == 1)
@ -396,7 +461,7 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
pcount++;
}
if (pcount > 0)
unaccount_mem(pcount);
unaccount_mem(kzdev, pcount);
out:
mutex_unlock(&aift->aift_lock);

View File

@ -22,6 +22,8 @@ struct kvm_zdev {
struct kvm *kvm;
struct zpci_fib fib;
struct list_head entry;
struct user_struct *user_account;
struct mm_struct *mm_account;
};
struct zpci_gaite {

View File

@ -27,6 +27,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
KBUILD_CFLAGS := -m$(BITS) -O2 $(CLANG_FLAGS)
KBUILD_CFLAGS += $(CC_FLAGS_DIALECT)
KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
KBUILD_CFLAGS += -fno-jump-tables
KBUILD_CFLAGS += -Wundef
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
cflags-$(CONFIG_X86_32) := -march=i386

View File

@ -722,6 +722,26 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
return &slot->arch.lpage_info[level - 2][idx];
}
static bool kvm_gfn_is_lpage_allowed(struct kvm *kvm,
const struct kvm_memory_slot *slot,
gfn_t gfn, int level)
{
const struct kvm_memory_slot *other_slot;
BUILD_BUG_ON(KVM_MAX_NR_ADDRESS_SPACES > 2);
if (lpage_info_slot(gfn, slot, level)->disallow_lpage)
return false;
if (kvm_arch_nr_memslot_as_ids(kvm) > 1) {
other_slot = __gfn_to_memslot(__kvm_memslots(kvm, slot->as_id ^ 1), gfn);
if (other_slot && lpage_info_slot(gfn, other_slot, level)->disallow_lpage)
return false;
}
return true;
}
/*
* The most significant bit in disallow_lpage tracks whether or not memory
* attributes are mixed, i.e. not identical for all gfns at the current level.
@ -2968,7 +2988,7 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot,
* write-protected (see above), thus if the gfn can be mapped with a
* hugepage and isn't write-tracked, it can't have a shadow page.
*/
if (!lpage_info_slot(gfn, slot, PG_LEVEL_2M)->disallow_lpage)
if (kvm_gfn_is_lpage_allowed(kvm, slot, gfn, PG_LEVEL_2M))
return 0;
/*

View File

@ -130,13 +130,23 @@ void __kvm_write_track_remove_gfn(struct kvm *kvm,
kvm_mmu_gfn_allow_lpage(slot, gfn);
}
/*
* check if the corresponding access on the specified guest page is tracked.
*/
static bool __kvm_gfn_is_write_tracked(const struct kvm_memory_slot *slot,
gfn_t gfn)
{
int index;
if (!slot)
return false;
index = gfn_to_index(gfn, slot->base_gfn, PG_LEVEL_4K);
return !!READ_ONCE(slot->arch.gfn_write_track[index]);
}
/* check if write access is tracked on the specified guest page. */
bool kvm_gfn_is_write_tracked(struct kvm *kvm,
const struct kvm_memory_slot *slot, gfn_t gfn)
{
int index;
const struct kvm_memory_slot *other_slot;
if (!slot)
return false;
@ -144,8 +154,18 @@ bool kvm_gfn_is_write_tracked(struct kvm *kvm,
if (!kvm_page_track_write_tracking_enabled(kvm))
return false;
index = gfn_to_index(gfn, slot->base_gfn, PG_LEVEL_4K);
return !!READ_ONCE(slot->arch.gfn_write_track[index]);
BUILD_BUG_ON(KVM_MAX_NR_ADDRESS_SPACES > 2);
if (__kvm_gfn_is_write_tracked(slot, gfn))
return true;
if (kvm_arch_nr_memslot_as_ids(kvm) > 1) {
other_slot = __gfn_to_memslot(__kvm_memslots(kvm, slot->as_id ^ 1), gfn);
if (__kvm_gfn_is_write_tracked(other_slot, gfn))
return true;
}
return false;
}
#ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING

View File

@ -240,14 +240,6 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm)
if (!is_sev_es_guest(&svm->vcpu))
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
/*
* If running nested and the guest uses its own MSR bitmap, there
* is no need to update L0's msr bitmap
*/
if (is_guest_mode(&svm->vcpu) &&
vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT))
return;
/* Enabling MSR intercept for x2APIC registers */
avic_set_x2apic_msr_interception(svm, true);
}

View File

@ -101,7 +101,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field)
: [output] "=r" (value)
: [field] "r" (field)
: "cc"
: "cc", "memory"
: do_fail, do_exception);
return value;
@ -145,7 +145,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field)
: ASM_CALL_CONSTRAINT, [output] "=&r" (value)
: [field] "r" (field)
: "cc");
: "cc", "memory");
return value;
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
@ -192,7 +192,7 @@ do { \
asm goto("1: " __stringify(insn) " %0\n\t" \
"jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \
: : op1 : "cc" : error, fault); \
: : op1 : "cc", "memory" : error, fault); \
return; \
error: \
instrumentation_begin(); \
@ -208,7 +208,7 @@ do { \
asm goto("1: " __stringify(insn) " %1, %0\n\t" \
"jna %l[error]\n\t" \
_ASM_EXTABLE(1b, %l[fault]) \
: : op1, op2 : "cc" : error, fault); \
: : op1, op2 : "cc", "memory" : error, fault);\
return; \
error: \
instrumentation_begin(); \

View File

@ -13429,9 +13429,15 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
* iterating over vCPUs in a different task while vCPUs are being freed
* is unsafe, i.e. will lead to use-after-free. The PIT also needs to
* be stopped before IRQ routing is freed.
*
* Do NOT free the in-kernel PIC or I/O APIC here (but as above, make
* sure to flush any background work), as KVM expects interrupt routing
* structures to be valid until vCPUs are destroyed.
*/
#ifdef CONFIG_KVM_IOAPIC
kvm_free_pit(kvm);
if (kvm->arch.vioapic)
cancel_delayed_work_sync(&kvm->arch.vioapic->eoi_inject);
#endif
kvm_mmu_pre_destroy_vm(kvm);

View File

@ -43,20 +43,22 @@ struct aie2_ctx_health {
static inline void aie2_tdr_signal(struct amdxdna_dev *xdna)
{
WRITE_ONCE(xdna->dev_handle->tdr_status, AIE2_TDR_SIGNALED);
WRITE_ONCE(xdna->dev_handle->last_signal_ts, jiffies);
}
static bool aie2_tdr_detect(struct amdxdna_dev *xdna)
{
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
unsigned long last = READ_ONCE(ndev->last_signal_ts);
if (READ_ONCE(ndev->tdr_status) == AIE2_TDR_WAIT) {
XDNA_ERR(xdna, "TDR timeout detected");
return true;
}
if (!tdr_timeout_ms)
return false;
WRITE_ONCE(ndev->tdr_status, AIE2_TDR_WAIT);
return false;
if (!time_after(jiffies, last + msecs_to_jiffies(tdr_timeout_ms)))
return false;
XDNA_ERR(xdna, "TDR timeout detected");
return true;
}
static void aie2_cmd_release(struct kref *ref)
@ -434,6 +436,12 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
mmput(job->mm);
fence = ERR_PTR(ret);
} else {
/*
* Command is successfully posted to hardware, update the
* tdr timestamp. The total pending commands are limited.
* So there will not be a case that driver keeps posting
* commands without getting any hardware respond.
*/
aie2_tdr_signal(hwctx->client->xdna);
}
trace_xdna_job(sched_job, hwctx->name, "sent to device",
@ -658,7 +666,9 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
const struct drm_sched_init_args args = {
.ops = &sched_ops,
.credit_limit = HWCTX_MAX_CMDS,
.timeout = msecs_to_jiffies(tdr_timeout_ms),
.timeout = tdr_timeout_ms ?
msecs_to_jiffies(tdr_timeout_ms) :
MAX_SCHEDULE_TIMEOUT,
.name = "amdxdna_js",
.dev = xdna->ddev.dev,
};

View File

@ -420,6 +420,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
goto stop_fw;
}
WRITE_ONCE(ndev->last_signal_ts, jiffies);
ndev->dev_status = AIE2_DEV_START;
return 0;

View File

@ -143,11 +143,6 @@ struct aie2_exec_msg_ops {
u32 (*get_chain_msg_op)(u32 cmd_op);
};
enum aie2_tdr_status {
AIE2_TDR_WAIT,
AIE2_TDR_SIGNALED,
};
struct amdxdna_dev_hdl {
struct aie_device aie;
const struct amdxdna_dev_priv *priv;
@ -179,7 +174,7 @@ struct amdxdna_dev_hdl {
u32 hwctx_num;
struct amdxdna_async_error last_async_err;
enum aie2_tdr_status tdr_status;
unsigned long last_signal_ts;
};
struct aie2_hw_ops {

View File

@ -192,9 +192,17 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
return len;
}
static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
static bool feat_matrix_chained(struct ethosu_device *edev, struct feat_matrix *fm)
{
u32 storage = fm->precision >> 14;
return !ethosu_is_u65(edev) && storage == 2;
}
static u64 feat_matrix_length(struct ethosu_device *edev,
struct ethosu_validated_cmdstream_info *info,
struct feat_matrix *fm,
u32 x, u32 y, u32 c)
u32 x, u32 y, u32 c, bool ofm)
{
u32 element_size, storage = fm->precision >> 14;
int tile = 0;
@ -203,6 +211,9 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
if (fm->region < 0)
return U64_MAX;
if (feat_matrix_chained(edev, fm))
return 0;
switch (storage) {
case 0:
if (x >= fm->width0 + 1) {
@ -223,6 +234,8 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
tile = 1;
}
break;
default:
return U64_MAX;
}
if (fm->base[tile] == U64_MAX)
return U64_MAX;
@ -231,10 +244,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
switch ((fm->precision >> 6) & 0x3) { // format
case 0: //nhwc:
addr += x * fm->stride_x + c;
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
addr += x * fm->stride_x + c * element_size;
break;
case 1: //nhcwb16:
element_size = BIT((fm->precision >> 1) & 0x3);
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
break;
@ -250,6 +264,7 @@ static int calc_sizes(struct drm_device *ddev,
u16 op, struct cmd_state *st,
bool ifm, bool ifm2, bool weight, bool scale)
{
struct ethosu_device *edev = to_ethosu_device(ddev);
u64 len;
if (ifm) {
@ -267,8 +282,8 @@ static int calc_sizes(struct drm_device *ddev,
if (ifm_height < 0 || ifm_width < 0)
return -EINVAL;
len = feat_matrix_length(info, &st->ifm, ifm_width,
ifm_height, st->ifm.depth);
len = feat_matrix_length(edev, info, &st->ifm, ifm_width,
ifm_height, st->ifm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
if (len == U64_MAX)
@ -276,8 +291,8 @@ static int calc_sizes(struct drm_device *ddev,
}
if (ifm2) {
len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
0, st->ofm.depth);
len = feat_matrix_length(edev, info, &st->ifm2, st->ifm.depth,
0, st->ofm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
if (len == U64_MAX)
@ -308,13 +323,14 @@ static int calc_sizes(struct drm_device *ddev,
st->scale[0].base + st->scale[0].length);
}
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth);
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
return -EINVAL;
info->output_region[st->ofm.region] = true;
if (!feat_matrix_chained(edev, &st->ofm))
info->output_region[st->ofm.region] = true;
return 0;
}
@ -324,6 +340,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
u16 op, struct cmd_state *st,
bool ifm, bool ifm2)
{
struct ethosu_device *edev = to_ethosu_device(ddev);
u32 height, width, depth;
u64 len;
@ -332,8 +349,8 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
width = st->ifm.broadcast & 0x2 ? 0 : st->ofm.width;
depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
len = feat_matrix_length(info, &st->ifm, width,
height, depth);
len = feat_matrix_length(edev, info, &st->ifm, width,
height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
if (len == U64_MAX)
@ -345,21 +362,22 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
width = st->ifm2.broadcast & 0x2 ? 0 : st->ofm.width;
depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
len = feat_matrix_length(info, &st->ifm2, width,
height, depth);
len = feat_matrix_length(edev, info, &st->ifm2, width,
height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
if (len == U64_MAX)
return -EINVAL;
}
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth);
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
return -EINVAL;
info->output_region[st->ofm.region] = true;
if (!feat_matrix_chained(edev, &st->ofm))
info->output_region[st->ofm.region] = true;
return 0;
}

View File

@ -1273,14 +1273,14 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
inner.extended_error =
ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
}
}
pr_warn!(
"{}:{} transaction to {} failed: {err:?}",
info.from_pid,
info.from_tid,
info.to_pid
);
pr_warn!(
"{}:{} transaction to {} failed: {err:?}",
info.from_pid,
info.from_tid,
info.to_pid
);
}
}
}

View File

@ -1950,9 +1950,14 @@ static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
bool has_current_state;
void *p;
if (osd_req->r_result)
if (osd_req->r_result < 0)
return osd_req->r_result;
/*
* Writes aren't allowed to return a data payload.
*/
WARN_ON_ONCE(osd_req->r_result > 0);
/*
* Nothing to do for a snapshot object map.
*/

View File

@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/wait.h>
#include <linux/wait_bit.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/swap.h>
@ -26,7 +27,6 @@
#include <linux/compat.h>
#include <linux/mutex.h>
#include <linux/writeback.h>
#include <linux/completion.h>
#include <linux/highmem.h>
#include <linux/sysfs.h>
#include <linux/miscdevice.h>
@ -327,7 +327,6 @@ struct ublk_device {
struct ublk_params params;
struct completion completion;
u32 nr_queue_ready;
bool unprivileged_daemons;
struct mutex cancel_mutex;
@ -3054,12 +3053,12 @@ static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id,
if (ublk_dev_ready(ub)) {
/*
* All queues ready - clear device-level canceling flag
* and complete the recovery/initialization.
* and wake ublk_dev_ready() waiters.
*/
mutex_lock(&ub->cancel_mutex);
ub->canceling = false;
mutex_unlock(&ub->cancel_mutex);
complete_all(&ub->completion);
wake_up_var(&ub->nr_queue_ready);
}
}
@ -4273,7 +4272,6 @@ static int ublk_init_queues(struct ublk_device *ub)
goto fail;
}
init_completion(&ub->completion);
return 0;
fail:
@ -4417,6 +4415,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
return ub->ublksrv_tgid == ublksrv_pid;
}
/*
* Wait until all queues have fetched their I/O commands, and return with
* ub->mutex held and readiness guaranteed: then every queue's ->canceling
* is cleared. Ready may regress between wakeup and mutex_lock() (F_BATCH
* UNPREP, daemon death), so re-check it under the mutex and wait again.
*/
static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)
{
while (true) {
if (wait_var_event_interruptible(&ub->nr_queue_ready,
ublk_dev_ready(ub)))
return -EINTR;
mutex_lock(&ub->mutex);
if (ublk_dev_ready(ub))
return 0;
mutex_unlock(&ub->mutex);
}
}
static int ublk_ctrl_start_dev(struct ublk_device *ub,
const struct ublksrv_ctrl_cmd *header)
{
@ -4499,15 +4517,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
};
}
if (wait_for_completion_interruptible(&ub->completion) != 0)
if (ublk_wait_dev_ready_and_lock(ub))
return -EINTR;
if (!ublk_validate_user_pid(ub, ublksrv_pid))
return -EINVAL;
mutex_lock(&ub->mutex);
/* device may become not ready in case of F_BATCH */
if (!ublk_dev_ready(ub)) {
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
ret = -EINVAL;
goto out_unlock;
}
@ -5071,7 +5084,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub)
goto out_unlock;
}
pr_devel("%s: start recovery for dev id %d\n", __func__, ub->ub_number);
init_completion(&ub->completion);
ret = 0;
out_unlock:
mutex_unlock(&ub->mutex);
@ -5087,16 +5099,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__,
header->dev_id);
if (wait_for_completion_interruptible(&ub->completion))
if (ublk_wait_dev_ready_and_lock(ub))
return -EINTR;
pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
header->dev_id);
if (!ublk_validate_user_pid(ub, ublksrv_pid))
return -EINVAL;
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
ret = -EINVAL;
goto out_unlock;
}
mutex_lock(&ub->mutex);
if (ublk_nosrv_should_stop_dev(ub))
goto out_unlock;

View File

@ -3771,6 +3771,9 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
struct intel_tlv *tlv = (void *)&skb->data[5];
if (skb->len < 5 + sizeof(*tlv) + sizeof(tlv->val[0]))
goto recv_frame;
/* The first event is always an event type TLV */
if (tlv->type != INTEL_TLV_TYPE_ID)
goto recv_frame;

View File

@ -804,56 +804,44 @@ static int btmtk_usb_uhw_reg_write(struct hci_dev *hdev, u32 reg, u32 val)
static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
int pipe, err;
void *buf;
u8 buf[sizeof(u32)];
int err;
buf = kzalloc(4, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pipe = usb_rcvctrlpipe(data->udev, 0);
err = usb_control_msg(data->udev, pipe, 0x01,
0xDE,
reg >> 16, reg & 0xffff,
buf, 4, USB_CTRL_GET_TIMEOUT);
if (err < 0) {
*val = 0;
err = usb_control_msg_recv(data->udev, 0, 0x01,
0xDE,
reg >> 16, reg & 0xffff,
buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
GFP_KERNEL);
if (err) {
bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
goto err_free_buf;
return err;
}
*val = get_unaligned_le32(buf);
bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
err_free_buf:
kfree(buf);
return err;
return 0;
}
static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
int pipe, err, size = sizeof(u32);
void *buf;
u8 buf[sizeof(u32)];
int err;
buf = kzalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pipe = usb_rcvctrlpipe(data->udev, 0);
err = usb_control_msg(data->udev, pipe, 0x63,
USB_TYPE_VENDOR | USB_DIR_IN,
reg >> 16, reg & 0xffff,
buf, size, USB_CTRL_GET_TIMEOUT);
*val = 0;
err = usb_control_msg_recv(data->udev, 0, 0x63,
USB_TYPE_VENDOR | USB_DIR_IN,
reg >> 16, reg & 0xffff,
buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
GFP_KERNEL);
if (err < 0)
goto err_free_buf;
return err;
*val = get_unaligned_le32(buf);
err_free_buf:
kfree(buf);
return err;
return 0;
}
static int btmtk_usb_id_get(struct hci_dev *hdev, u32 reg, u32 *id)
@ -877,7 +865,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (dev_id == 0x7922) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
if (err < 0)
if (err)
return err;
val |= 0x00002020;
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@ -887,7 +875,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
if (err < 0)
if (err)
return err;
val |= BIT(0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@ -896,14 +884,14 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
msleep(100);
} else if (dev_id == 0x7925 || dev_id == 0x6639) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
if (err < 0)
if (err)
return err;
val |= (1 << 5);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
if (err < 0)
if (err)
return err;
val &= 0xFFFF00FF;
val |= (1 << 13);
@ -914,7 +902,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
if (err < 0)
if (err)
return err;
val |= (1 << 0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
@ -924,13 +912,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
if (err < 0)
if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
if (err < 0)
if (err)
return err;
msleep(100);
} else {
@ -940,7 +928,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
if (err < 0)
if (err)
return err;
/* Reset the bluetooth chip via USB interface. */
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
@ -950,13 +938,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
if (err < 0)
if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
if (err < 0)
if (err)
return err;
/* MT7921 need to delay 20ms between toggle reset bit */
msleep(20);
@ -964,7 +952,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
if (err < 0)
if (err)
return err;
}
@ -980,7 +968,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
}
err = btmtk_usb_id_get(hdev, 0x70010200, &val);
if (err < 0 || (!val && dev_id != 0x6639))
if (err || (!val && dev_id != 0x6639))
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
return err;
@ -1324,24 +1312,24 @@ int btmtk_usb_setup(struct hci_dev *hdev)
calltime = ktime_get();
err = btmtk_usb_id_get(hdev, 0x80000008, &dev_id);
if (err < 0) {
if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
if (!dev_id || dev_id != 0x7663) {
err = btmtk_usb_id_get(hdev, 0x70010200, &dev_id);
if (err < 0) {
if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x80021004, &fw_version);
if (err < 0) {
if (err) {
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x70010020, &fw_flavor);
if (err < 0) {
if (err) {
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
return err;
}

View File

@ -3424,28 +3424,16 @@ static const char *qca_get_fw_subdirectory(const struct qca_version *ver)
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
void *data, u16 size)
{
int pipe, err;
u8 *buf;
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
int err;
/* Found some of USB hosts have IOT issues with ours so that we should
* not wait until HCI layer is ready.
*/
pipe = usb_rcvctrlpipe(udev, 0);
err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
0, 0, buf, size, USB_CTRL_GET_TIMEOUT);
if (err < 0) {
err = usb_control_msg_recv(udev, 0, request, USB_TYPE_VENDOR | USB_DIR_IN,
0, 0, data, size, USB_CTRL_GET_TIMEOUT,
GFP_KERNEL);
if (err)
dev_err(&udev->dev, "Failed to access otp area (%d)", err);
goto done;
}
memcpy(data, buf, size);
done:
kfree(buf);
return err;
}
@ -3652,7 +3640,7 @@ static bool btusb_qca_need_patch(struct usb_device *udev)
struct qca_version ver;
if (btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver)) < 0)
sizeof(ver)))
return false;
/* only low ROM versions need patches */
return !(le32_to_cpu(ver.rom_version) & ~0xffffU);
@ -3670,7 +3658,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
if (err < 0)
if (err)
return err;
ver_rom = le32_to_cpu(ver.rom_version);
@ -3693,7 +3681,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_CHECK_STATUS, &status,
sizeof(status));
if (err < 0)
if (err)
return err;
if (!(status & QCA_PATCH_UPDATED)) {
@ -3704,7 +3692,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
if (err < 0)
if (err)
return err;
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);

View File

@ -3187,6 +3187,7 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
/* set volume */
cgc->buffer = buffer + offset - 8;
cgc->buflen -= offset - 8;
memset(cgc->buffer, 0, 8);
return cdrom_mode_select(cdi, cgc);
}

View File

@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(int irq, void *d)
unsigned int ctrl;
unsigned short val = 0;
/*
* Check device is fully attached. Device interrupts should have
* been disabled, but do this in case of bad hardware.
*/
if (!dev->attached)
return IRQ_NONE;
ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
return IRQ_NONE;
@ -233,6 +240,9 @@ static int parport_attach(struct comedi_device *dev,
if (ret)
return ret;
outb(0, dev->iobase + PARPORT_DATA_REG);
outb(0, dev->iobase + PARPORT_CTRL_REG);
if (it->options[1]) {
ret = request_irq(it->options[1], parport_interrupt, 0,
dev->board_name, dev);
@ -288,9 +298,6 @@ static int parport_attach(struct comedi_device *dev,
s->cancel = parport_intr_cancel;
}
outb(0, dev->iobase + PARPORT_DATA_REG);
outb(0, dev->iobase + PARPORT_CTRL_REG);
return 0;
}

View File

@ -118,14 +118,9 @@ static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
return rc;
}
static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
struct dibs_lo_dmb_node *dmb_node)
static void dibs_lo_free_dmb(struct dibs_lo_dev *ldev,
struct dibs_lo_dmb_node *dmb_node)
{
/* remove dmb from hash table */
write_lock_bh(&ldev->dmb_ht_lock);
hash_del(&dmb_node->list);
write_unlock_bh(&ldev->dmb_ht_lock);
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
folio_put(virt_to_folio(dmb_node->cpu_addr));
kfree(dmb_node);
@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
unsigned long flags;
bool last;
ldev = dibs->drv_priv;
/* find dmb from hash table */
read_lock_bh(&ldev->dmb_ht_lock);
write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
if (tmp_node->token == dmb->dmb_tok) {
dmb_node = tmp_node;
break;
}
}
read_unlock_bh(&ldev->dmb_ht_lock);
if (!dmb_node)
if (!dmb_node) {
write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
last = refcount_dec_and_test(&dmb_node->refcnt);
if (last)
hash_del(&dmb_node->list);
write_unlock_bh(&ldev->dmb_ht_lock);
if (refcount_dec_and_test(&dmb_node->refcnt)) {
if (last) {
spin_lock_irqsave(&dibs->lock, flags);
dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
spin_unlock_irqrestore(&dibs->lock, flags);
__dibs_lo_unregister_dmb(ldev, dmb_node);
dibs_lo_free_dmb(ldev, dmb_node);
}
return 0;
}
@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
refcount_inc(&dmb_node->refcnt);
read_unlock_bh(&ldev->dmb_ht_lock);
if (!refcount_inc_not_zero(&dmb_node->refcnt))
/* the dmb is being unregistered, but has
* not been removed from the hash table.
*/
return -EINVAL;
/* provide dmb information */
dmb->idx = dmb_node->sba_idx;
dmb->dmb_tok = dmb_node->token;
@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
{
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
bool last;
ldev = dibs->drv_priv;
/* find dmb_node according to dmb->dmb_tok */
read_lock_bh(&ldev->dmb_ht_lock);
write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
if (tmp_node->token == token) {
dmb_node = tmp_node;
@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
}
}
if (!dmb_node) {
read_unlock_bh(&ldev->dmb_ht_lock);
write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
read_unlock_bh(&ldev->dmb_ht_lock);
last = refcount_dec_and_test(&dmb_node->refcnt);
if (last)
hash_del(&dmb_node->list);
write_unlock_bh(&ldev->dmb_ht_lock);
if (last)
dibs_lo_free_dmb(ldev, dmb_node);
if (refcount_dec_and_test(&dmb_node->refcnt))
__dibs_lo_unregister_dmb(ldev, dmb_node);
return 0;
}

View File

@ -1146,6 +1146,33 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
return reg->priv;
}
/**
* dpll_pin_own_dpll_ref_first - find the first owner dpll ref of a pin
* @pin: pointer to a dpll pin
*
* Search pin's dpll_refs for a ref whose dpll matches the pin's
* (module, clock_id) tuple, i.e. the dpll registered by the driver
* that created the pin. This ensures pin-level attributes are
* reported and modified using the owner's ops even when the pin is
* also registered with dplls from other drivers.
*
* Return: pointer to the owner's dpll_pin_ref, or NULL if no
* owner ref is found.
*/
struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin)
{
struct dpll_pin_ref *ref;
unsigned long i;
xa_for_each(&pin->dpll_refs, i, ref) {
if (ref->dpll->module == pin->module &&
ref->dpll->clock_id == pin->clock_id)
return ref;
}
return NULL;
}
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
{
struct dpll_pin_registration *reg;

View File

@ -93,6 +93,7 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin);
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll);
struct dpll_device *dpll_device_get_by_id(int id);
struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin);
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref);
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
extern struct xarray dpll_device_xa;

View File

@ -699,7 +699,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref;
int ret;
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ref = dpll_pin_own_dpll_ref_first(pin);
if (!ref)
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ASSERT_NOT_NULL(ref);
ret = dpll_msg_add_pin_handle(msg, pin);
@ -1090,12 +1092,19 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->frequency_set || !ops->frequency_get) {
NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
if ((!ops->frequency_set || !ops->frequency_get) &&
ref->dpll->module == pin->module &&
ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack,
"frequency set not supported by the device");
return -EOPNOTSUPP;
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ref = dpll_pin_own_dpll_ref_first(pin);
if (!ref) {
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
return -ENODEV;
}
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@ -1109,6 +1118,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->frequency_set)
continue;
dpll = ref->dpll;
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), freq, extack);
@ -1128,6 +1139,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
if (!ops->frequency_set)
continue;
dpll = ref->dpll;
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_freq, extack))
@ -1151,13 +1164,19 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->esync_set || !ops->esync_get) {
if ((!ops->esync_set || !ops->esync_get) &&
ref->dpll->module == pin->module &&
ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack,
"embedded sync feature is not supported by this device");
return -EOPNOTSUPP;
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ref = dpll_pin_own_dpll_ref_first(pin);
if (!ref) {
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
return -ENODEV;
}
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@ -1181,6 +1200,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
void *pin_dpll_priv;
ops = dpll_pin_ops(ref);
if (!ops->esync_set)
continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@ -1204,6 +1225,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
if (!ops->esync_set)
continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@ -1238,8 +1261,11 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
NL_SET_ERR_MSG(extack, "reference sync pin not available");
return -EINVAL;
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ASSERT_NOT_NULL(ref);
ref = dpll_pin_own_dpll_ref_first(pin);
if (!ref) {
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
return -ENODEV;
}
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set || !ops->ref_sync_get) {
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
@ -1258,6 +1284,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set)
continue;
dpll = ref->dpll;
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@ -1280,6 +1308,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set)
continue;
dpll = ref->dpll;
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@ -1471,12 +1501,18 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
if ((!ops->phase_adjust_set || !ops->phase_adjust_get) &&
ref->dpll->module == pin->module &&
ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack, "phase adjust not supported");
return -EOPNOTSUPP;
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ref = dpll_pin_own_dpll_ref_first(pin);
if (!ref) {
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
return -ENODEV;
}
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
@ -1491,6 +1527,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
if (!ops->phase_adjust_set)
continue;
dpll = ref->dpll;
ret = ops->phase_adjust_set(pin,
dpll_pin_on_dpll_priv(dpll, pin),
@ -1513,6 +1551,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
if (!ops->phase_adjust_set)
continue;
dpll = ref->dpll;
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_phase_adj,

View File

@ -297,31 +297,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(
if (fi->offset + fi->len == offset) {
/* The new fragment can be tacked on to the end */
/* Did the new fragment plug a hole? */
fi2 = list_entry(fi->fi_link.next,
struct fwnet_fragment_info, fi_link);
if (fi->offset + fi->len == fi2->offset) {
/* glue fragments together */
fi->len += len + fi2->len;
list_del(&fi2->fi_link);
kfree(fi2);
} else {
fi->len += len;
if (!list_is_last(&fi->fi_link, &pd->fi_list)) {
fi2 = list_next_entry(fi, fi_link);
if (offset + len == fi2->offset) {
/* glue fragments together */
fi->len += len + fi2->len;
list_del(&fi2->fi_link);
kfree(fi2);
return fi;
}
}
fi->len += len;
return fi;
}
if (offset + len == fi->offset) {
/* The new fragment can be tacked on to the beginning */
/* Did the new fragment plug a hole? */
fi2 = list_entry(fi->fi_link.prev,
struct fwnet_fragment_info, fi_link);
if (fi2->offset + fi2->len == fi->offset) {
/* glue fragments together */
fi2->len += fi->len + len;
list_del(&fi->fi_link);
kfree(fi);
if (!list_is_first(&fi->fi_link, &pd->fi_list)) {
fi2 = list_prev_entry(fi, fi_link);
if (fi2->offset + fi2->len == offset) {
/* glue fragments together */
fi2->len += fi->len + len;
list_del(&fi->fi_link);
kfree(fi);
return fi2;
return fi2;
}
}
fi->offset = offset;
fi->len += len;

View File

@ -1499,8 +1499,9 @@ int stratix10_svc_async_poll(struct stratix10_svc_chan *chan,
WARN_ON_ONCE(1);
}
return 0;
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) {
dev_dbg(ctrl->dev, "async message is still in progress\n");
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY ||
handle->res.a0 == INTEL_SIP_SMC_STATUS_NO_RESPONSE) {
dev_dbg(ctrl->dev, "async message is not ready yet\n");
return -EAGAIN;
}
@ -1857,14 +1858,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
struct gen_pool *genpool = chan->ctrl->genpool;
size_t s = roundup(size, 1 << genpool->min_alloc_order);
pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
pmem = kzalloc_obj(*pmem);
if (!pmem)
return ERR_PTR(-ENOMEM);
guard(mutex)(&svc_mem_lock);
va = gen_pool_alloc(genpool, s);
if (!va)
if (!va) {
kfree(pmem);
return ERR_PTR(-ENOMEM);
}
memset((void *)va, 0, s);
pa = gen_pool_virt_to_phys(genpool, va);
@ -1890,6 +1893,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
{
struct stratix10_svc_data_mem *pmem;
guard(mutex)(&svc_mem_lock);
list_for_each_entry(pmem, &svc_data_mem, node)
@ -1898,10 +1902,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
(unsigned long)kaddr, pmem->size);
pmem->vaddr = NULL;
list_del(&pmem->node);
kfree(pmem);
return;
}
list_del(&svc_data_mem);
}
EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
@ -2046,12 +2049,12 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
struct stratix10_svc *svc = ctrl->svc;
platform_device_unregister(svc->stratix10_svc_rsu);
stratix10_svc_async_exit(ctrl);
of_platform_depopulate(ctrl->dev);
platform_device_unregister(svc->stratix10_svc_rsu);
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
if (ctrl->chans[i].task) {
kthread_stop(ctrl->chans[i].task);

View File

@ -27,12 +27,6 @@ static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int off
return GPIO_LINE_DIRECTION_IN;
}
static int pin_control_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int val)
{
return pinctrl_gpio_direction_output(chip, offset);
}
static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
unsigned long config;
@ -55,6 +49,18 @@ static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset,
return pinctrl_gpio_set_config(chip, offset, config);
}
static int pin_control_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int val)
{
int ret;
ret = pinctrl_gpio_direction_output(chip, offset);
if (ret)
return ret;
return pin_control_gpio_set(chip, offset, val);
}
static int pin_control_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;

View File

@ -604,20 +604,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
return 0;
}
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc,
unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = pca953x_get_bit_mask(chip, off);
guard(mutex)(&chip->i2c_lock);
if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE)
return regmap_update_bits(chip->regmap, dirreg, bit, 0);
return regmap_update_bits(chip->regmap, dirreg, bit, bit);
}
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
guard(mutex)(&chip->i2c_lock);
return pca953x_gpio_direction_input_unlocked(gc, off);
}
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
@ -855,9 +863,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
DECLARE_BITMAP(reg_direction, MAX_LINE);
int level;
guard(mutex)(&chip->i2c_lock);
if (chip->driver_data & PCA_PCAL) {
DECLARE_BITMAP(latched_inputs, MAX_LINE);
guard(mutex)(&chip->i2c_lock);
/* Enable latch on edge-triggered interrupt-enabled inputs */
bitmap_or(latched_inputs, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
@ -879,7 +888,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Look for any newly setup interrupt */
for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
pca953x_gpio_direction_input(&chip->gpio_chip, level);
pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
}
@ -1369,9 +1378,20 @@ static int pca953x_restore_context(struct pca953x_chip *chip)
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(chip);
if (ret)
return ret;
goto err;
return regcache_sync(chip->regmap);
ret = regcache_sync(chip->regmap);
if (ret)
goto err;
return 0;
err:
if (chip->client->irq > 0)
disable_irq(chip->client->irq);
regcache_cache_only(chip->regmap, true);
return ret;
}
static void pca953x_save_context(struct pca953x_chip *chip)

View File

@ -96,7 +96,7 @@ struct pch_gpio {
struct pch_gpio_reg_data pch_gpio_reg;
int irq_base;
enum pch_type_t ioh;
spinlock_t spinlock;
raw_spinlock_t spinlock;
};
static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
@ -105,7 +105,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
struct pch_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->po);
if (val)
reg_val |= BIT(nr);
@ -113,7 +113,7 @@ static int pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->po);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@ -133,7 +133,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
u32 reg_val;
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
raw_spin_lock_irqsave(&chip->spinlock, flags);
reg_val = ioread32(&chip->reg->po);
if (val)
@ -147,7 +147,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
pm |= BIT(nr);
iowrite32(pm, &chip->reg->pm);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@ -158,12 +158,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
u32 pm;
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
raw_spin_lock_irqsave(&chip->spinlock, flags);
pm = ioread32(&chip->reg->pm);
pm &= BIT(gpio_pins[chip->ioh]) - 1;
pm &= ~BIT(nr);
iowrite32(pm, &chip->reg->pm);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@ -265,7 +265,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
return 0;
}
spin_lock_irqsave(&chip->spinlock, flags);
raw_spin_lock_irqsave(&chip->spinlock, flags);
/* Set interrupt mode */
im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
@ -277,7 +277,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
else if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@ -374,7 +374,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
chip->ioh = id->driver_data;
chip->reg = chip->base;
pci_set_drvdata(pdev, chip);
spin_lock_init(&chip->spinlock);
raw_spin_lock_init(&chip->spinlock);
pch_gpio_setup(chip);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
@ -407,9 +407,9 @@ static int pch_gpio_suspend(struct device *dev)
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
raw_spin_lock_irqsave(&chip->spinlock, flags);
pch_gpio_save_reg_conf(chip);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@ -419,11 +419,11 @@ static int pch_gpio_resume(struct device *dev)
struct pch_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
raw_spin_lock_irqsave(&chip->spinlock, flags);
iowrite32(0x01, &chip->reg->reset);
iowrite32(0x00, &chip->reg->reset);
pch_gpio_restore_reg_conf(chip);
spin_unlock_irqrestore(&chip->spinlock, flags);
raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}

View File

@ -160,6 +160,13 @@ static int fops_buf_size_get(void *data, u64 *val)
return 0;
}
static void fops_buf_release(void *data)
{
struct gpio_la_poll_priv *priv = data;
vfree(priv->blob.data);
}
static int fops_buf_size_set(void *data, u64 val)
{
struct gpio_la_poll_priv *priv = data;
@ -238,6 +245,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
return ret;
fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);
ret = devm_add_action_or_reset(dev, fops_buf_release, priv);
if (ret)
return ret;
priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN);
if (IS_ERR(priv->descs))

View File

@ -999,14 +999,17 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode)
if (ret < 0)
return ret;
if (fwnode_property_present(fwnode, "input"))
if (fwnode_property_present(fwnode, "input")) {
dflags |= GPIOD_IN;
else if (fwnode_property_present(fwnode, "output-low"))
} else if (fwnode_property_present(fwnode, "output-low")) {
dflags |= GPIOD_OUT_LOW;
else if (fwnode_property_present(fwnode, "output-high"))
} else if (fwnode_property_present(fwnode, "output-high")) {
dflags |= GPIOD_OUT_HIGH;
else
return -EINVAL;
} else {
gpiochip_warn(gc, "%pfwP: no hogging state specified, bailing out\n",
fwnode);
return 0;
}
fwnode_property_read_string(fwnode, "line-name", &name);

View File

@ -3324,7 +3324,8 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
acrtc = get_crtc_by_otg_inst(
adev, state->stream_status[i].primary_otg_inst);
if (acrtc && state->stream_status[i].plane_count != 0) {
if (acrtc && state->stream_status[i].plane_count != 0 &&
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
if (rc)

View File

@ -280,10 +280,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
* is enabled. On DCE, vupdate is only needed in VRR mode.
*/
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, enable);
if (enable) {
rc = amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type);
drm_dbg_vbl(crtc->dev, "Get vupdate_irq ret=%d\n", rc);
} else {
rc = amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type);
drm_dbg_vbl(crtc->dev, "Put vupdate_irq ret=%d\n", rc);
}
} else if (dc_supports_vrr(dm->dc->ctx->dce_version)) {
if (enable) {
/* vblank irq on -> Only need vupdate irq in vrr mode */
/* vblank irq on -> Only need vupdate irq in vrr mode
* Not ref-counted since we need explicit enable/disable
* for DCE VRR handling
*/
if (amdgpu_dm_crtc_vrr_active(acrtc_state))
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true);
} else {

View File

@ -781,7 +781,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
const struct dev_pagemap *other = NULL;
int err, i;
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
pfns = kvcalloc(npages, sizeof(*pfns), GFP_KERNEL);
if (!pfns)
return DRM_GPUSVM_SCAN_UNPOPULATED;
@ -1753,8 +1753,10 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
return -EFAULT;
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
if (!pfns)
if (!pfns) {
mmput(mm);
return -ENOMEM;
}
hmm_range.hmm_pfns = pfns;
while (!time_after(jiffies, timeout)) {

View File

@ -727,8 +727,10 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
}
err = ops->populate_devmem_pfn(devmem_allocation, npages, migrate.dst);
if (err)
goto err_aborted_migration;
if (err) {
npages = 0;
goto err_finalize;
}
own_pages = 0;
@ -807,8 +809,11 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
msecs_to_jiffies(mdetails->timeslice_ms);
err_finalize:
if (err)
if (err) {
drm_pagemap_migration_unlock_put_pages(npages, migrate.dst);
for (i = npages; i < npages_in_range(start, end); ++i)
migrate.dst[i] = 0;
}
err_aborted_migration:
migrate_vma_pages(&migrate);

View File

@ -98,6 +98,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
u32 temp;
int ret;
i2c_dev->status = I2C_STAT_INIT;
i2c_dev->msg = pmsg;
@ -109,9 +110,14 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
HDMI_WRITE(HDMI_HI2CHCR, temp);
HDMI_READ(HDMI_HI2CHCR);
while (i2c_dev->status != I2C_TRANSACTION_DONE)
wait_for_completion_interruptible_timeout(&i2c_dev->complete,
while (i2c_dev->status != I2C_TRANSACTION_DONE) {
ret = wait_for_completion_interruptible_timeout(&i2c_dev->complete,
10 * HZ);
if (ret < 0)
return ret;
if (!ret)
return -ETIMEDOUT;
}
return 0;
}
@ -130,7 +136,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
{
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
int i;
int i, ret = 0;
mutex_lock(&i2c_dev->i2c_lock);
@ -142,9 +148,11 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
for (i = 0; i < num; i++) {
if (pmsg->len && pmsg->buf) {
if (pmsg->flags & I2C_M_RD)
xfer_read(adap, pmsg);
ret = xfer_read(adap, pmsg);
else
xfer_write(adap, pmsg);
ret = xfer_write(adap, pmsg);
if (ret)
break;
}
pmsg++; /* next message */
}
@ -154,6 +162,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
mutex_unlock(&i2c_dev->i2c_lock);
if (ret)
return ret;
return i;
}

View File

@ -615,12 +615,7 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp)
int ret;
u8 bit_min, bit_max;
/*
* Since we only support Fully AUX Based VESA Backlight interface make sure
* backlight enable is possible via AUX along with backlight adjustment
*/
if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP &&
intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
return false;
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min);

View File

@ -747,6 +747,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
pvr_gem_object_get(pvr_obj);
mutex_lock(&vm_ctx->lock);
err = drm_gpuvm_exec_lock(&vm_exec);
if (err)
goto err_cleanup;
@ -756,6 +757,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
drm_gpuvm_exec_unlock(&vm_exec);
err_cleanup:
mutex_unlock(&vm_ctx->lock);
pvr_vm_bind_op_fini(&bind_op);
return err;

View File

@ -232,6 +232,7 @@ config DRM_PANEL_HIMAX_HX83121A
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DSC_HELPER
select DRM_KMS_HELPER
help
@ -332,6 +333,7 @@ config DRM_PANEL_ILITEK_ILI9882T
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DSC_HELPER
help
Say Y if you want to enable support for panels based on the
@ -954,6 +956,7 @@ config DRM_PANEL_SAMSUNG_S6E3HA8
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DSC_HELPER
help
Say Y or M here if you want to enable support for the

View File

@ -2562,9 +2562,12 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
"Couldn't get our power regulator\n");
ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc");
if (IS_ERR(ctx->iovcc))
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
if (IS_ERR(ctx->iovcc)) {
if (PTR_ERR(ctx->iovcc) != -ENODEV)
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
"Couldn't get our iovcc regulator\n");
ctx->iovcc = NULL;
}
ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset))

View File

@ -95,13 +95,9 @@ static void drm_gem_shmem_test_obj_create_private(struct kunit *test)
sg_init_one(sgt->sgl, buf, TEST_SIZE);
/*
* Set the DMA mask to 64-bits and map the sgtables
* otherwise drm_gem_shmem_free will cause a warning
* on debug kernels.
* Map the sgtables otherwise drm_gem_shmem_free will cause a warning on
* debug kernels.
*/
ret = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(64));
KUNIT_ASSERT_EQ(test, ret, 0);
ret = dma_map_sgtable(drm_dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
KUNIT_ASSERT_EQ(test, ret, 0);
@ -352,11 +348,19 @@ static int drm_gem_shmem_test_init(struct kunit *test)
{
struct device *dev;
struct drm_device *drm_dev;
int ret;
/* Allocate a parent device */
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
/*
* Set the DMA mask to 64-bits to avoid intermittent failures calling
* drm_gem_shmem_get_pages_sgt().
*/
ret = dma_set_mask(dev, DMA_BIT_MASK(64));
KUNIT_ASSERT_EQ(test, ret, 0);
/*
* The DRM core will automatically initialize the GEM core and create
* a DRM Memory Manager object which provides an address space pool

View File

@ -315,33 +315,16 @@ static const u32 appletbdrm_primary_plane_formats[] = {
DRM_FORMAT_XRGB8888, /* emulated */
};
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_commit *state)
static int appletbdrm_primary_plane_helper_begin_fb_access(struct drm_plane *plane,
struct drm_plane_state *new_plane_state)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_crtc *new_crtc = new_plane_state->crtc;
struct drm_crtc_state *new_crtc_state = NULL;
struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(new_plane_state);
size_t frames_size = 0;
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
size_t frames_size = 0;
size_t request_size;
int ret;
if (new_crtc)
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
false, false);
if (ret)
return ret;
else if (!new_plane_state->visible)
return 0;
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, new_plane_state);
drm_atomic_helper_damage_iter_init(&iter, plane->state, new_plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));
}
@ -366,6 +349,29 @@ static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
appletbdrm_state->request_size = request_size;
appletbdrm_state->frames_size = frames_size;
return drm_gem_begin_shadow_fb_access(plane, new_plane_state);
}
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_commit *state)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_crtc *new_crtc = new_plane_state->crtc;
struct drm_crtc_state *new_crtc_state = NULL;
int ret;
if (new_crtc)
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
false, false);
if (ret)
return ret;
else if (!new_plane_state->visible)
return 0;
return 0;
}
@ -468,7 +474,7 @@ static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
}
static void appletbdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_commit *old_state)
struct drm_atomic_commit *old_state)
{
struct appletbdrm_device *adev = drm_to_adev(plane->dev);
struct drm_device *drm = plane->dev;
@ -552,7 +558,8 @@ static void appletbdrm_primary_plane_destroy_state(struct drm_plane *plane,
}
static const struct drm_plane_helper_funcs appletbdrm_primary_plane_helper_funcs = {
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
.begin_fb_access = appletbdrm_primary_plane_helper_begin_fb_access,
.end_fb_access = drm_gem_end_shadow_fb_access,
.atomic_check = appletbdrm_primary_plane_helper_atomic_check,
.atomic_update = appletbdrm_primary_plane_helper_atomic_update,
.atomic_disable = appletbdrm_primary_plane_helper_atomic_disable,

View File

@ -6,9 +6,10 @@
#include <drm/ttm/ttm_backup.h>
#include <linux/export.h>
#include <linux/page-flags.h>
#include <linux/swap.h>
#include "ttm_pool_internal.h"
/*
* Need to map shmem indices to handle since a handle value
* of 0 means error, following the swp_entry_t convention.
@ -68,17 +69,23 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
}
/**
* ttm_backup_backup_page() - Backup a page
* ttm_backup_backup_folio() - Backup a folio
* @backup: The struct backup pointer to use.
* @page: The page to back up.
* @writeback: Whether to perform immediate writeback of the page.
* @folio: The folio to back up.
* @order: The allocation order of @folio. Since TTM allocates higher-order
* pages without __GFP_COMP, folio_nr_pages(@folio) would always
* return 1; the caller must pass the true order explicitly.
* @writeback: Whether to perform immediate writeback of the folio's pages.
* This may have performance implications.
* @idx: A unique integer for each page and each struct backup.
* @idx: A unique integer for the first page of the folio and each struct backup.
* This allows the backup implementation to avoid managing
* its address space separately.
* @page_gfp: The gfp value used when the page was allocated.
* This is used for accounting purposes.
* @folio_gfp: The gfp value used when the folio was allocated.
* Currently unused.
* @alloc_gfp: The gfp to be used when allocating memory.
* @nr_pages_backed: Output. On a successful return, set to the number of
* pages actually backed up, which may be less than (1 << @order)
* if an -ENOMEM was encountered mid-folio.
*
* Context: If called from reclaim context, the caller needs to
* assert that the shrinker gfp has __GFP_FS set, to avoid
@ -87,53 +94,87 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
* that the shrinker gfp has __GFP_IO set, since without it,
* we're not allowed to start backup IO.
*
* Return: A handle on success. Negative error code on failure.
*
* Note: This function could be extended to back up a folio and
* implementations would then split the folio internally if needed.
* Drawback is that the caller would then have to keep track of
* the folio size- and usage.
* Return: A handle for the first backed-up page on success (handles for
* subsequent pages follow sequentially). -ENOMEM if no pages could be backed
* up. Any other negative error code if a non-ENOMEM failure occurred; in that
* case any pages backed up so far are truncated before returning.
*/
s64
ttm_backup_backup_page(struct file *backup, struct page *page,
bool writeback, pgoff_t idx, gfp_t page_gfp,
gfp_t alloc_gfp)
ttm_backup_backup_folio(struct file *backup, struct folio *folio,
unsigned int order, bool writeback, pgoff_t idx,
gfp_t folio_gfp, gfp_t alloc_gfp,
pgoff_t *nr_pages_backed)
{
struct address_space *mapping = backup->f_mapping;
unsigned long handle = 0;
int nr_pages = 1 << order;
struct folio *to_folio;
int ret;
int ret, i;
to_folio = shmem_read_folio_gfp(mapping, idx, alloc_gfp);
if (IS_ERR(to_folio))
return PTR_ERR(to_folio);
*nr_pages_backed = 0;
folio_mark_accessed(to_folio);
folio_lock(to_folio);
folio_mark_dirty(to_folio);
copy_highpage(folio_file_page(to_folio, idx), page);
handle = ttm_backup_shmem_idx_to_handle(idx);
for (i = 0; i < nr_pages; ) {
int to_nr, j;
if (writeback && !folio_mapped(to_folio) &&
folio_clear_dirty_for_io(to_folio)) {
folio_set_reclaim(to_folio);
ret = shmem_writeout(to_folio, NULL, NULL);
if (!folio_test_writeback(to_folio))
folio_clear_reclaim(to_folio);
/*
* If writeout succeeds, it unlocks the folio. errors
* are otherwise dropped, since writeout is only best
* effort here.
* Only inject past the first subpage so *nr_pages_backed is
* always > 0 here, matching a genuine mid-compound -ENOMEM
* and driving the caller's reactive split fallback instead
* of an early, no-progress failure.
*/
if (ret)
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && i &&
ttm_backup_fault_inject_folio())
to_folio = ERR_PTR(-ENOMEM);
else
to_folio = shmem_read_folio_gfp(mapping, idx + i, alloc_gfp);
if (IS_ERR(to_folio)) {
int err = PTR_ERR(to_folio);
if (err == -ENOMEM && *nr_pages_backed)
return ttm_backup_shmem_idx_to_handle(idx);
if (*nr_pages_backed) {
shmem_truncate_range(file_inode(backup),
(loff_t)idx << PAGE_SHIFT,
((loff_t)(idx + i) << PAGE_SHIFT) - 1);
/*
* The pages just truncated are no longer
* backed up; don't let the caller mistake
* them for valid handles.
*/
*nr_pages_backed = 0;
}
return err;
}
to_nr = min_t(int, nr_pages - i,
folio_next_index(to_folio) - (idx + i));
folio_mark_accessed(to_folio);
folio_lock(to_folio);
folio_mark_dirty(to_folio);
for (j = 0; j < to_nr; j++)
copy_highpage(folio_file_page(to_folio, idx + i + j),
folio_page(folio, i + j));
if (writeback && !folio_mapped(to_folio) &&
folio_clear_dirty_for_io(to_folio)) {
folio_set_reclaim(to_folio);
ret = shmem_writeout(to_folio, NULL, NULL);
if (!folio_test_writeback(to_folio))
folio_clear_reclaim(to_folio);
if (ret == AOP_WRITEPAGE_ACTIVATE)
folio_unlock(to_folio);
} else {
folio_unlock(to_folio);
} else {
folio_unlock(to_folio);
}
folio_put(to_folio);
i += to_nr;
*nr_pages_backed = i;
}
folio_put(to_folio);
return handle;
return ttm_backup_shmem_idx_to_handle(idx);
}
/**

View File

@ -53,8 +53,23 @@
#ifdef CONFIG_FAULT_INJECTION
#include <linux/fault-inject.h>
static DECLARE_FAULT_ATTR(backup_fault_inject);
/*
* Exposed to ttm_backup.c so a mid-compound subpage can be made to fail
* with -ENOMEM, exercising the reactive split-and-retry fallback in
* ttm_pool_backup() for high-order backups.
*/
bool ttm_backup_fault_inject_folio(void)
{
return should_fail(&backup_fault_inject, 1);
}
#else
#define should_fail(...) false
bool ttm_backup_fault_inject_folio(void)
{
return false;
}
#endif
/**
@ -487,7 +502,7 @@ static void ttm_pool_split_for_swap(struct ttm_pool *pool, struct page *p)
/**
* DOC: Partial backup and restoration of a struct ttm_tt.
*
* Swapout using ttm_backup_backup_page() and swapin using
* Swapout using ttm_backup_backup_folio() and swapin using
* ttm_backup_copy_page() may fail.
* The former most likely due to lack of swap-space or memory, the latter due
* to lack of memory or because of signal interruption during waits.
@ -1036,12 +1051,12 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
{
struct file *backup = tt->backup;
struct page *page;
unsigned long handle;
gfp_t alloc_gfp;
gfp_t gfp;
int ret = 0;
pgoff_t shrunken = 0;
pgoff_t i, num_pages;
pgoff_t i, j, num_pages, npages;
pgoff_t nr_backed;
if (WARN_ON(ttm_tt_is_backed_up(tt)))
return -EINVAL;
@ -1119,9 +1134,11 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && should_fail(&backup_fault_inject, 1))
num_pages = DIV_ROUND_UP(num_pages, 2);
for (i = 0; i < num_pages; ++i) {
s64 shandle;
for (i = 0; i < num_pages; i += npages) {
unsigned int order;
s64 handle;
npages = 1;
page = tt->pages[i];
if (unlikely(!page))
continue;
@ -1130,19 +1147,61 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
if (unlikely(ttm_backup_page_ptr_is_handle(page)))
continue;
ttm_pool_split_for_swap(pool, page);
order = ttm_pool_page_order(pool, page);
npages = 1UL << order;
shandle = ttm_backup_backup_page(backup, page, flags->writeback, i,
gfp, alloc_gfp);
if (shandle < 0) {
/* We allow partially shrunken tts */
ret = shandle;
/*
* We don't allow dipping kernel reserves for high order backup
*/
if (order)
alloc_gfp |= __GFP_NOMEMALLOC;
else
alloc_gfp &= ~__GFP_NOMEMALLOC;
/*
* Back up the compound atomically at its native order. If
* fault injection truncated num_pages mid-compound, skip
* the partial tail rather than splitting.
*/
if (unlikely(i + npages > num_pages))
break;
handle = ttm_backup_backup_folio(backup, page_folio(page),
order, flags->writeback, i,
gfp, alloc_gfp,
&nr_backed);
/*
* Zero progress on this compound (whether order 0 or a
* high-order compound that failed before backing up even
* its first subpage) is unrecoverable: bail out rather than
* looping forever with npages == nr_backed == 0 below.
*/
if (unlikely(handle < 0 && !nr_backed)) {
ret = handle;
break;
}
handle = shandle;
tt->pages[i] = ttm_backup_handle_to_page_ptr(handle);
__free_pages_gpu_account(page, 0, false);
shrunken++;
for (j = 0; j < nr_backed; j++)
tt->pages[i + j] = ttm_backup_handle_to_page_ptr(handle + j);
shrunken += nr_backed;
if (unlikely(nr_backed < npages)) {
/*
* Partial OOM backup: split the compound and free the
* subpages whose content is now in shmem. Continue the
* loop from the first un-backed order-0 page.
*/
ttm_pool_split_for_swap(pool, page);
for (j = 0; j < nr_backed; j++)
__free_pages_gpu_account(page + j, 0, false);
npages = nr_backed;
continue;
}
/* Fully backed up: free at native order. */
page->private = 0;
__free_pages_gpu_account(page, order, false);
}
return shrunken ? shrunken : ret;

View File

@ -22,4 +22,12 @@ static inline unsigned int ttm_pool_beneficial_order(struct ttm_pool *pool)
return pool->alloc_flags & 0xff;
}
/*
* Implemented in ttm_pool.c, used by ttm_backup.c. Returns true if a fault
* should be injected mid-compound to test the reactive split-and-retry
* fallback in ttm_pool_backup(). Always returns false when
* CONFIG_FAULT_INJECTION is disabled.
*/
bool ttm_backup_fault_inject_folio(void);
#endif

View File

@ -571,6 +571,8 @@ extern bool super_pages;
void v3d_init_hw_state(struct v3d_dev *v3d);
int v3d_gem_init(struct drm_device *dev);
void v3d_gem_destroy(struct drm_device *dev);
void v3d_idle_axi(struct v3d_dev *v3d, int core);
void v3d_idle_gca(struct v3d_dev *v3d);
void v3d_reset_sms(struct v3d_dev *v3d);
void v3d_reset(struct v3d_dev *v3d);
void v3d_invalidate_caches(struct v3d_dev *v3d);

View File

@ -36,9 +36,21 @@ v3d_init_core(struct v3d_dev *v3d, int core)
V3D_CORE_WRITE(core, V3D_CTL_L2TFLEND, ~0);
}
static void
void
v3d_idle_axi(struct v3d_dev *v3d, int core)
{
if (v3d->ver >= V3D_GEN_71) {
V3D_WRITE(V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
if (wait_for((V3D_READ(V3D_GMP_STATUS(v3d->ver)) &
(V3D_GMP_STATUS_RD_COUNT_MASK |
V3D_GMP_STATUS_WR_COUNT_MASK |
V3D_GMP_STATUS_CFG_BUSY)) == 0, 100)) {
drm_err(&v3d->drm, "Failed to wait for safe GMP shutdown\n");
}
return;
}
V3D_CORE_WRITE(core, V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) &
@ -49,7 +61,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int core)
}
}
static void
void
v3d_idle_gca(struct v3d_dev *v3d)
{
if (v3d->ver >= V3D_GEN_41)

View File

@ -54,8 +54,15 @@ int v3d_power_suspend(struct device *dev)
v3d_clean_caches(v3d);
/* Wait until V3D has no active or pending AXI transactions. */
v3d_idle_axi(v3d, 0);
v3d_idle_gca(v3d);
ret = v3d_suspend_sms(v3d);
if (ret) {
/* Staying active: undo the GMP STOP_REQ from v3d_idle_axi(). */
V3D_WRITE(V3D_GMP_CFG(v3d->ver),
V3D_READ(V3D_GMP_CFG(v3d->ver)) & ~V3D_GMP_CFG_STOP_REQ);
v3d_irq_enable(v3d);
return ret;
}

View File

@ -732,9 +732,13 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
{
struct vc4_bo *bo = to_vc4_bo(obj);
if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
return -EINVAL;
if (bo->validated_shader) {
if (vma->vm_flags & VM_WRITE) {
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
return -EINVAL;
}
vm_flags_clear(vma, VM_MAYWRITE);
}
mutex_lock(&bo->madv_lock);
@ -1044,7 +1048,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
struct vc4_dev *vc4 = to_vc4_dev(dev);
int i;
timer_delete(&vc4->bo_cache.time_timer);
timer_shutdown_sync(&vc4->bo_cache.time_timer);
cancel_work_sync(&vc4->bo_cache.time_work);
vc4_bo_cache_purge(dev);

Some files were not shown because too many files have changed in this diff Show More