mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
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.cdbc3791e3b("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.c23dad2d088("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.c3bd438a58e("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.c469d7e6077("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:
commit
5c45807355
3
.mailmap
3
.mailmap
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
21
MAINTAINERS
21
MAINTAINERS
|
|
@ -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*
|
||||
|
|
|
|||
7
Makefile
7
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 2
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
@ -475,6 +475,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
|
|||
|
||||
# These flags apply to all Rust code in the tree, including the kernel and
|
||||
# host programs.
|
||||
#
|
||||
# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our
|
||||
# MSRV. It can trigger depending on the optimization level.
|
||||
# [1] https://github.com/rust-lang/rust-clippy/issues/17379
|
||||
export rust_common_flags := --edition=2021 \
|
||||
-Zbinary_dep_depinfo=y \
|
||||
-Astable_features \
|
||||
|
|
@ -503,6 +507,7 @@ export rust_common_flags := --edition=2021 \
|
|||
-Aclippy::uninlined_format_args \
|
||||
-Wclippy::unnecessary_safety_comment \
|
||||
-Wclippy::unnecessary_safety_doc \
|
||||
-Aclippy::unwrap_or_default \
|
||||
-Wrustdoc::missing_crate_level_docs \
|
||||
-Wrustdoc::unescaped_backticks
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@
|
|||
* Annoyingly, the negative levels for Address size faults aren't laid out
|
||||
* contiguously (or in the desired order)
|
||||
*/
|
||||
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x25 : 0x2C)
|
||||
#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x29 : 0x2C)
|
||||
#define ESR_ELx_FSC_ADDRSZ_L(n) ((n) < 0 ? ESR_ELx_FSC_ADDRSZ_nL(n) : \
|
||||
(ESR_ELx_FSC_ADDRSZ + (n)))
|
||||
|
||||
|
|
|
|||
|
|
@ -78,8 +78,12 @@ enum fixed_addresses {
|
|||
/*
|
||||
* Temporary boot-time mappings, used by early_ioremap(),
|
||||
* before ioremap() is functional.
|
||||
*
|
||||
* Reserve one extra page so a 256K mapping may start at any
|
||||
* offset within a page. early_ioremap() maps the page-aligned
|
||||
* physical range, so the initial offset can consume an extra page.
|
||||
*/
|
||||
#define NR_FIX_BTMAPS (SZ_256K / PAGE_SIZE)
|
||||
#define NR_FIX_BTMAPS ((SZ_256K / PAGE_SIZE) + 1)
|
||||
#define FIX_BTMAPS_SLOTS 7
|
||||
#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@
|
|||
struct prev_kprobe {
|
||||
struct kprobe *kp;
|
||||
unsigned int status;
|
||||
|
||||
/*
|
||||
* The original DAIF state of the outer kprobe, saved here before
|
||||
* a nested kprobe overwrites kcb->saved_irqflag during reentry.
|
||||
*/
|
||||
unsigned long saved_irqflag;
|
||||
};
|
||||
|
||||
/* per-cpu kprobe control block */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ static void data_abort_decode(unsigned long esr)
|
|||
pr_alert(" SF = %lu, AR = %lu\n",
|
||||
(esr & ESR_ELx_SF) >> ESR_ELx_SF_SHIFT,
|
||||
(esr & ESR_ELx_AR) >> ESR_ELx_AR_SHIFT);
|
||||
pr_alert(" Xs = %llu\n",
|
||||
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
|
||||
} else {
|
||||
pr_alert(" ISV = 0, ISS = 0x%08lx, ISS2 = 0x%08lx\n",
|
||||
esr & ESR_ELx_ISS_MASK, iss2);
|
||||
|
|
@ -87,11 +89,10 @@ static void data_abort_decode(unsigned long esr)
|
|||
(iss2 & ESR_ELx_TnD) >> ESR_ELx_TnD_SHIFT,
|
||||
(iss2 & ESR_ELx_TagAccess) >> ESR_ELx_TagAccess_SHIFT);
|
||||
|
||||
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu, Xs = %llu\n",
|
||||
pr_alert(" GCS = %ld, Overlay = %lu, DirtyBit = %lu\n",
|
||||
(iss2 & ESR_ELx_GCS) >> ESR_ELx_GCS_SHIFT,
|
||||
(iss2 & ESR_ELx_Overlay) >> ESR_ELx_Overlay_SHIFT,
|
||||
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT,
|
||||
(iss2 & ESR_ELx_Xs_MASK) >> ESR_ELx_Xs_SHIFT);
|
||||
(iss2 & ESR_ELx_DirtyBit) >> ESR_ELx_DirtyBit_SHIFT);
|
||||
}
|
||||
|
||||
static void mem_abort_decode(unsigned long esr)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr,
|
|||
p4dp = p4d_offset(pgdp, addr);
|
||||
pudp = pud_offset(p4dp, addr);
|
||||
pmdp = pmd_offset(pudp, addr);
|
||||
if ((pte_t *)pmdp == ptep) {
|
||||
if ((pte_t *)PTR_ALIGN_DOWN(pmdp, sizeof(*pmdp) * CONT_PMDS) == ptep) {
|
||||
*pgsize = PMD_SIZE;
|
||||
return CONT_PMDS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2194,7 +2194,7 @@ static int prevent_memory_remove_notifier(struct notifier_block *nb,
|
|||
}
|
||||
}
|
||||
|
||||
if (!can_unmap_without_split(pfn, arg->nr_pages))
|
||||
if (!can_unmap_without_split(arg->start_pfn, arg->nr_pages))
|
||||
return NOTIFY_BAD;
|
||||
|
||||
return NOTIFY_OK;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#ifdef CONFIG_64BIT
|
||||
#define TASK_STRUCT_OFFSET 0
|
||||
#else
|
||||
#define TASK_STRUCT_OFFSET 2000
|
||||
#define TASK_STRUCT_OFFSET 2040
|
||||
#endif
|
||||
|
||||
.macro cpu_save_nonscratch thread
|
||||
|
|
|
|||
|
|
@ -201,10 +201,12 @@ static void __init acpi_process_madt(void)
|
|||
}
|
||||
|
||||
int pptt_enabled;
|
||||
static int acpi_nr_packages;
|
||||
static int acpi_package_ids[MAX_PACKAGES];
|
||||
|
||||
int __init parse_acpi_topology(void)
|
||||
{
|
||||
int cpu, topology_id;
|
||||
int i, cpu, topology_id;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
topology_id = find_acpi_cpu_topology(cpu, 0);
|
||||
|
|
@ -222,6 +224,29 @@ int __init parse_acpi_topology(void)
|
|||
|
||||
cpu_data[cpu].core = topology_id;
|
||||
}
|
||||
|
||||
topology_id = find_acpi_cpu_topology_package(cpu);
|
||||
if (topology_id < 0) {
|
||||
pr_warn("Invalid BIOS PPTT\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
for (i = 0; i < acpi_nr_packages; i++)
|
||||
if (acpi_package_ids[i] == topology_id)
|
||||
break;
|
||||
|
||||
if (i == acpi_nr_packages)
|
||||
acpi_package_ids[acpi_nr_packages++] = topology_id;
|
||||
|
||||
cpu_data[cpu].package = topology_id;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
for (i = 0; i < acpi_nr_packages; i++)
|
||||
if (cpu_data[cpu].package == acpi_package_ids[i]) {
|
||||
cpu_data[cpu].package = i; /* Canonicalize */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pptt_enabled = 1;
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd,
|
|||
if (atomic_read(&kgdb_active) != -1)
|
||||
kgdb_nmicallback(smp_processor_id(), regs);
|
||||
|
||||
if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
|
||||
if (kgdb_handle_exception(regs->csr_era == stepped_address ? 0 : args->trapnr,
|
||||
args->signr, cmd, regs))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (atomic_read(&kgdb_setting_breakpoint))
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static unsigned long first_ind_entry;
|
|||
int machine_kexec_prepare(struct kimage *kimage)
|
||||
{
|
||||
int i;
|
||||
char head[8];
|
||||
char *bootloader = "kexec";
|
||||
void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR;
|
||||
|
||||
|
|
@ -59,7 +60,9 @@ int machine_kexec_prepare(struct kimage *kimage)
|
|||
} else {
|
||||
/* Find the command line */
|
||||
for (i = 0; i < kimage->nr_segments; i++) {
|
||||
if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
|
||||
if (copy_from_user(head, kimage->segment[i].buf, strlen(bootloader)))
|
||||
continue;
|
||||
if (!strncmp(bootloader, head, strlen(bootloader))) {
|
||||
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
|
||||
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -71,27 +71,27 @@
|
|||
cfi_ld s7, PT_R30
|
||||
cfi_ld s8, PT_R31
|
||||
LONG_L t0, sp, PT_CRMD
|
||||
li.d t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
|
||||
LONG_LI t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
|
||||
csrxchg t0, t1, LOONGARCH_CSR_CRMD
|
||||
.endm
|
||||
|
||||
SYM_CODE_START(arch_rethook_trampoline)
|
||||
UNWIND_HINT_UNDEFINED
|
||||
addi.d sp, sp, -PT_SIZE
|
||||
PTR_ADDI sp, sp, -PT_SIZE
|
||||
save_all_base_regs
|
||||
|
||||
addi.d t0, sp, PT_SIZE
|
||||
LONG_S t0, sp, PT_R3
|
||||
PTR_ADDI t0, sp, PT_SIZE
|
||||
LONG_S t0, sp, PT_R3
|
||||
|
||||
move a0, sp /* pt_regs */
|
||||
move a0, sp /* pt_regs */
|
||||
|
||||
bl arch_rethook_trampoline_callback
|
||||
bl arch_rethook_trampoline_callback
|
||||
|
||||
/* use the result as the return-address */
|
||||
move ra, a0
|
||||
move ra, a0
|
||||
|
||||
restore_all_base_regs
|
||||
addi.d sp, sp, PT_SIZE
|
||||
PTR_ADDI sp, sp, PT_SIZE
|
||||
|
||||
jr ra
|
||||
jr ra
|
||||
SYM_CODE_END(arch_rethook_trampoline)
|
||||
|
|
|
|||
|
|
@ -603,6 +603,7 @@ void __init setup_arch(char **cmdline_p)
|
|||
memblock_init();
|
||||
pagetable_init();
|
||||
bootcmdline_init(cmdline_p);
|
||||
jump_label_init(); /* Initialise the static keys for early params */
|
||||
parse_early_param();
|
||||
reserve_initrd_mem();
|
||||
|
||||
|
|
@ -610,8 +611,6 @@ void __init setup_arch(char **cmdline_p)
|
|||
arch_mem_init(cmdline_p);
|
||||
|
||||
resource_init();
|
||||
jump_label_init(); /* Initialise the static keys for paravirtualization */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
plat_smp_setup();
|
||||
prefill_possible_map();
|
||||
|
|
|
|||
|
|
@ -426,10 +426,10 @@ void loongson_init_secondary(void)
|
|||
numa_add_cpu(cpu);
|
||||
#endif
|
||||
per_cpu(cpu_state, cpu) = CPU_ONLINE;
|
||||
cpu_data[cpu].package =
|
||||
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core :
|
||||
cpu_logical_map(cpu) % loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].package = pptt_enabled ? cpu_data[cpu].package :
|
||||
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
|
||||
cpu_data[cpu].global_id = cpu_logical_map(cpu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -835,7 +835,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -852,7 +852,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, divd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -870,7 +870,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
move_reg(ctx, t1, src);
|
||||
emit_sext_32(ctx, t1, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -887,7 +887,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
|
|||
emit_sext_32(ctx, t1, is32);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_insn(ctx, modd, dst, dst, t1);
|
||||
emit_sext_32(ctx, dst, is32);
|
||||
emit_zext_32(ctx, dst, is32);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2361,6 +2361,7 @@ void bpf_jit_free(struct bpf_prog *prog)
|
|||
*/
|
||||
if (jit_data) {
|
||||
bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header);
|
||||
kvfree(jit_data->ctx.offset);
|
||||
kfree(jit_data);
|
||||
}
|
||||
hdr = bpf_jit_binary_pack_hdr(prog);
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ void wildfiremod_halt(void)
|
|||
printk(KERN_INFO "WildFireMod hibernating...\n");
|
||||
|
||||
/* Set portE.5 to Digital IO */
|
||||
mcf_write16(read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
|
||||
mcf_write16(mcf_read16(MCFGPIO_PEPAR) & ~(1 << (5 * 2)), MCFGPIO_PEPAR);
|
||||
|
||||
/* Make portE.5 an output */
|
||||
mcf_write8(mcf_read8(MCFGPIO_PDDR_E) | (1 << 5), MCFGPIO_PDDR_E);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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); \
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -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, ¤t_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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, ¤t->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, ¤t->mm->pinned_vm);
|
||||
if (current->mm) {
|
||||
mmgrab(current->mm);
|
||||
atomic64_add(nr_pages, ¤t->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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(); \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -43,20 +43,22 @@ struct aie2_ctx_health {
|
|||
|
||||
static inline void aie2_tdr_signal(struct amdxdna_dev *xdna)
|
||||
{
|
||||
WRITE_ONCE(xdna->dev_handle->tdr_status, AIE2_TDR_SIGNALED);
|
||||
WRITE_ONCE(xdna->dev_handle->last_signal_ts, jiffies);
|
||||
}
|
||||
|
||||
static bool aie2_tdr_detect(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
unsigned long last = READ_ONCE(ndev->last_signal_ts);
|
||||
|
||||
if (READ_ONCE(ndev->tdr_status) == AIE2_TDR_WAIT) {
|
||||
XDNA_ERR(xdna, "TDR timeout detected");
|
||||
return true;
|
||||
}
|
||||
if (!tdr_timeout_ms)
|
||||
return false;
|
||||
|
||||
WRITE_ONCE(ndev->tdr_status, AIE2_TDR_WAIT);
|
||||
return false;
|
||||
if (!time_after(jiffies, last + msecs_to_jiffies(tdr_timeout_ms)))
|
||||
return false;
|
||||
|
||||
XDNA_ERR(xdna, "TDR timeout detected");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void aie2_cmd_release(struct kref *ref)
|
||||
|
|
@ -434,6 +436,12 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
|||
mmput(job->mm);
|
||||
fence = ERR_PTR(ret);
|
||||
} else {
|
||||
/*
|
||||
* Command is successfully posted to hardware, update the
|
||||
* tdr timestamp. The total pending commands are limited.
|
||||
* So there will not be a case that driver keeps posting
|
||||
* commands without getting any hardware respond.
|
||||
*/
|
||||
aie2_tdr_signal(hwctx->client->xdna);
|
||||
}
|
||||
trace_xdna_job(sched_job, hwctx->name, "sent to device",
|
||||
|
|
@ -658,7 +666,9 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
|||
const struct drm_sched_init_args args = {
|
||||
.ops = &sched_ops,
|
||||
.credit_limit = HWCTX_MAX_CMDS,
|
||||
.timeout = msecs_to_jiffies(tdr_timeout_ms),
|
||||
.timeout = tdr_timeout_ms ?
|
||||
msecs_to_jiffies(tdr_timeout_ms) :
|
||||
MAX_SCHEDULE_TIMEOUT,
|
||||
.name = "amdxdna_js",
|
||||
.dev = xdna->ddev.dev,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
goto stop_fw;
|
||||
}
|
||||
|
||||
WRITE_ONCE(ndev->last_signal_ts, jiffies);
|
||||
ndev->dev_status = AIE2_DEV_START;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -143,11 +143,6 @@ struct aie2_exec_msg_ops {
|
|||
u32 (*get_chain_msg_op)(u32 cmd_op);
|
||||
};
|
||||
|
||||
enum aie2_tdr_status {
|
||||
AIE2_TDR_WAIT,
|
||||
AIE2_TDR_SIGNALED,
|
||||
};
|
||||
|
||||
struct amdxdna_dev_hdl {
|
||||
struct aie_device aie;
|
||||
const struct amdxdna_dev_priv *priv;
|
||||
|
|
@ -179,7 +174,7 @@ struct amdxdna_dev_hdl {
|
|||
u32 hwctx_num;
|
||||
|
||||
struct amdxdna_async_error last_async_err;
|
||||
enum aie2_tdr_status tdr_status;
|
||||
unsigned long last_signal_ts;
|
||||
};
|
||||
|
||||
struct aie2_hw_ops {
|
||||
|
|
|
|||
|
|
@ -192,9 +192,17 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
|
|||
return len;
|
||||
}
|
||||
|
||||
static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
||||
static bool feat_matrix_chained(struct ethosu_device *edev, struct feat_matrix *fm)
|
||||
{
|
||||
u32 storage = fm->precision >> 14;
|
||||
|
||||
return !ethosu_is_u65(edev) && storage == 2;
|
||||
}
|
||||
|
||||
static u64 feat_matrix_length(struct ethosu_device *edev,
|
||||
struct ethosu_validated_cmdstream_info *info,
|
||||
struct feat_matrix *fm,
|
||||
u32 x, u32 y, u32 c)
|
||||
u32 x, u32 y, u32 c, bool ofm)
|
||||
{
|
||||
u32 element_size, storage = fm->precision >> 14;
|
||||
int tile = 0;
|
||||
|
|
@ -203,6 +211,9 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
|||
if (fm->region < 0)
|
||||
return U64_MAX;
|
||||
|
||||
if (feat_matrix_chained(edev, fm))
|
||||
return 0;
|
||||
|
||||
switch (storage) {
|
||||
case 0:
|
||||
if (x >= fm->width0 + 1) {
|
||||
|
|
@ -223,6 +234,8 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
|||
tile = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return U64_MAX;
|
||||
}
|
||||
if (fm->base[tile] == U64_MAX)
|
||||
return U64_MAX;
|
||||
|
|
@ -231,10 +244,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
|
|||
|
||||
switch ((fm->precision >> 6) & 0x3) { // format
|
||||
case 0: //nhwc:
|
||||
addr += x * fm->stride_x + c;
|
||||
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
|
||||
addr += x * fm->stride_x + c * element_size;
|
||||
break;
|
||||
case 1: //nhcwb16:
|
||||
element_size = BIT((fm->precision >> 1) & 0x3);
|
||||
element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
|
||||
|
||||
addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
|
||||
break;
|
||||
|
|
@ -250,6 +264,7 @@ static int calc_sizes(struct drm_device *ddev,
|
|||
u16 op, struct cmd_state *st,
|
||||
bool ifm, bool ifm2, bool weight, bool scale)
|
||||
{
|
||||
struct ethosu_device *edev = to_ethosu_device(ddev);
|
||||
u64 len;
|
||||
|
||||
if (ifm) {
|
||||
|
|
@ -267,8 +282,8 @@ static int calc_sizes(struct drm_device *ddev,
|
|||
if (ifm_height < 0 || ifm_width < 0)
|
||||
return -EINVAL;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm, ifm_width,
|
||||
ifm_height, st->ifm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm, ifm_width,
|
||||
ifm_height, st->ifm.depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm.region, st->ifm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
|
|
@ -276,8 +291,8 @@ static int calc_sizes(struct drm_device *ddev,
|
|||
}
|
||||
|
||||
if (ifm2) {
|
||||
len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
|
||||
0, st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm2, st->ifm.depth,
|
||||
0, st->ofm.depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm2.region, st->ifm2.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
|
|
@ -308,13 +323,14 @@ static int calc_sizes(struct drm_device *ddev,
|
|||
st->scale[0].base + st->scale[0].length);
|
||||
}
|
||||
|
||||
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth, true);
|
||||
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ofm.region, st->ofm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
info->output_region[st->ofm.region] = true;
|
||||
if (!feat_matrix_chained(edev, &st->ofm))
|
||||
info->output_region[st->ofm.region] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -324,6 +340,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
|||
u16 op, struct cmd_state *st,
|
||||
bool ifm, bool ifm2)
|
||||
{
|
||||
struct ethosu_device *edev = to_ethosu_device(ddev);
|
||||
u32 height, width, depth;
|
||||
u64 len;
|
||||
|
||||
|
|
@ -332,8 +349,8 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
|||
width = st->ifm.broadcast & 0x2 ? 0 : st->ofm.width;
|
||||
depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm, width,
|
||||
height, depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm, width,
|
||||
height, depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm.region, st->ifm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
|
|
@ -345,21 +362,22 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
|
|||
width = st->ifm2.broadcast & 0x2 ? 0 : st->ofm.width;
|
||||
depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
|
||||
|
||||
len = feat_matrix_length(info, &st->ifm2, width,
|
||||
height, depth);
|
||||
len = feat_matrix_length(edev, info, &st->ifm2, width,
|
||||
height, depth, false);
|
||||
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
|
||||
op, st->ifm2.region, st->ifm2.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth);
|
||||
len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
|
||||
st->ofm.height[2], st->ofm.depth, true);
|
||||
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
|
||||
op, st->ofm.region, st->ofm.base[0], len);
|
||||
if (len == U64_MAX)
|
||||
return -EINVAL;
|
||||
info->output_region[st->ofm.region] = true;
|
||||
if (!feat_matrix_chained(edev, &st->ofm))
|
||||
info->output_region[st->ofm.region] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1273,14 +1273,14 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
|
|||
inner.extended_error =
|
||||
ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn!(
|
||||
"{}:{} transaction to {} failed: {err:?}",
|
||||
info.from_pid,
|
||||
info.from_tid,
|
||||
info.to_pid
|
||||
);
|
||||
pr_warn!(
|
||||
"{}:{} transaction to {} failed: {err:?}",
|
||||
info.from_pid,
|
||||
info.from_tid,
|
||||
info.to_pid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1950,9 +1950,14 @@ static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
|
|||
bool has_current_state;
|
||||
void *p;
|
||||
|
||||
if (osd_req->r_result)
|
||||
if (osd_req->r_result < 0)
|
||||
return osd_req->r_result;
|
||||
|
||||
/*
|
||||
* Writes aren't allowed to return a data payload.
|
||||
*/
|
||||
WARN_ON_ONCE(osd_req->r_result > 0);
|
||||
|
||||
/*
|
||||
* Nothing to do for a snapshot object map.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/wait_bit.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/swap.h>
|
||||
|
|
@ -26,7 +27,6 @@
|
|||
#include <linux/compat.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
|
@ -327,7 +327,6 @@ struct ublk_device {
|
|||
|
||||
struct ublk_params params;
|
||||
|
||||
struct completion completion;
|
||||
u32 nr_queue_ready;
|
||||
bool unprivileged_daemons;
|
||||
struct mutex cancel_mutex;
|
||||
|
|
@ -3054,12 +3053,12 @@ static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id,
|
|||
if (ublk_dev_ready(ub)) {
|
||||
/*
|
||||
* All queues ready - clear device-level canceling flag
|
||||
* and complete the recovery/initialization.
|
||||
* and wake ublk_dev_ready() waiters.
|
||||
*/
|
||||
mutex_lock(&ub->cancel_mutex);
|
||||
ub->canceling = false;
|
||||
mutex_unlock(&ub->cancel_mutex);
|
||||
complete_all(&ub->completion);
|
||||
wake_up_var(&ub->nr_queue_ready);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4273,7 +4272,6 @@ static int ublk_init_queues(struct ublk_device *ub)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
init_completion(&ub->completion);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
|
@ -4417,6 +4415,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
|
|||
return ub->ublksrv_tgid == ublksrv_pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until all queues have fetched their I/O commands, and return with
|
||||
* ub->mutex held and readiness guaranteed: then every queue's ->canceling
|
||||
* is cleared. Ready may regress between wakeup and mutex_lock() (F_BATCH
|
||||
* UNPREP, daemon death), so re-check it under the mutex and wait again.
|
||||
*/
|
||||
static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub)
|
||||
{
|
||||
while (true) {
|
||||
if (wait_var_event_interruptible(&ub->nr_queue_ready,
|
||||
ublk_dev_ready(ub)))
|
||||
return -EINTR;
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
if (ublk_dev_ready(ub))
|
||||
return 0;
|
||||
mutex_unlock(&ub->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int ublk_ctrl_start_dev(struct ublk_device *ub,
|
||||
const struct ublksrv_ctrl_cmd *header)
|
||||
{
|
||||
|
|
@ -4499,15 +4517,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
|
|||
};
|
||||
}
|
||||
|
||||
if (wait_for_completion_interruptible(&ub->completion) != 0)
|
||||
if (ublk_wait_dev_ready_and_lock(ub))
|
||||
return -EINTR;
|
||||
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
/* device may become not ready in case of F_BATCH */
|
||||
if (!ublk_dev_ready(ub)) {
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
@ -5071,7 +5084,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub)
|
|||
goto out_unlock;
|
||||
}
|
||||
pr_devel("%s: start recovery for dev id %d\n", __func__, ub->ub_number);
|
||||
init_completion(&ub->completion);
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&ub->mutex);
|
||||
|
|
@ -5087,16 +5099,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
|
|||
pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__,
|
||||
header->dev_id);
|
||||
|
||||
if (wait_for_completion_interruptible(&ub->completion))
|
||||
if (ublk_wait_dev_ready_and_lock(ub))
|
||||
return -EINTR;
|
||||
|
||||
pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
|
||||
header->dev_id);
|
||||
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid))
|
||||
return -EINVAL;
|
||||
if (!ublk_validate_user_pid(ub, ublksrv_pid)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
mutex_lock(&ub->mutex);
|
||||
if (ublk_nosrv_should_stop_dev(ub))
|
||||
goto out_unlock;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -3187,6 +3187,7 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
|
|||
|
||||
/* set volume */
|
||||
cgc->buffer = buffer + offset - 8;
|
||||
cgc->buflen -= offset - 8;
|
||||
memset(cgc->buffer, 0, 8);
|
||||
return cdrom_mode_select(cdi, cgc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(int irq, void *d)
|
|||
unsigned int ctrl;
|
||||
unsigned short val = 0;
|
||||
|
||||
/*
|
||||
* Check device is fully attached. Device interrupts should have
|
||||
* been disabled, but do this in case of bad hardware.
|
||||
*/
|
||||
if (!dev->attached)
|
||||
return IRQ_NONE;
|
||||
|
||||
ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
|
||||
if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
|
||||
return IRQ_NONE;
|
||||
|
|
@ -233,6 +240,9 @@ static int parport_attach(struct comedi_device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
outb(0, dev->iobase + PARPORT_DATA_REG);
|
||||
outb(0, dev->iobase + PARPORT_CTRL_REG);
|
||||
|
||||
if (it->options[1]) {
|
||||
ret = request_irq(it->options[1], parport_interrupt, 0,
|
||||
dev->board_name, dev);
|
||||
|
|
@ -288,9 +298,6 @@ static int parport_attach(struct comedi_device *dev,
|
|||
s->cancel = parport_intr_cancel;
|
||||
}
|
||||
|
||||
outb(0, dev->iobase + PARPORT_DATA_REG);
|
||||
outb(0, dev->iobase + PARPORT_CTRL_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -297,31 +297,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(
|
|||
if (fi->offset + fi->len == offset) {
|
||||
/* The new fragment can be tacked on to the end */
|
||||
/* Did the new fragment plug a hole? */
|
||||
fi2 = list_entry(fi->fi_link.next,
|
||||
struct fwnet_fragment_info, fi_link);
|
||||
if (fi->offset + fi->len == fi2->offset) {
|
||||
/* glue fragments together */
|
||||
fi->len += len + fi2->len;
|
||||
list_del(&fi2->fi_link);
|
||||
kfree(fi2);
|
||||
} else {
|
||||
fi->len += len;
|
||||
if (!list_is_last(&fi->fi_link, &pd->fi_list)) {
|
||||
fi2 = list_next_entry(fi, fi_link);
|
||||
if (offset + len == fi2->offset) {
|
||||
/* glue fragments together */
|
||||
fi->len += len + fi2->len;
|
||||
list_del(&fi2->fi_link);
|
||||
kfree(fi2);
|
||||
|
||||
return fi;
|
||||
}
|
||||
}
|
||||
fi->len += len;
|
||||
|
||||
return fi;
|
||||
}
|
||||
if (offset + len == fi->offset) {
|
||||
/* The new fragment can be tacked on to the beginning */
|
||||
/* Did the new fragment plug a hole? */
|
||||
fi2 = list_entry(fi->fi_link.prev,
|
||||
struct fwnet_fragment_info, fi_link);
|
||||
if (fi2->offset + fi2->len == fi->offset) {
|
||||
/* glue fragments together */
|
||||
fi2->len += fi->len + len;
|
||||
list_del(&fi->fi_link);
|
||||
kfree(fi);
|
||||
if (!list_is_first(&fi->fi_link, &pd->fi_list)) {
|
||||
fi2 = list_prev_entry(fi, fi_link);
|
||||
if (fi2->offset + fi2->len == offset) {
|
||||
/* glue fragments together */
|
||||
fi2->len += fi->len + len;
|
||||
list_del(&fi->fi_link);
|
||||
kfree(fi);
|
||||
|
||||
return fi2;
|
||||
return fi2;
|
||||
}
|
||||
}
|
||||
fi->offset = offset;
|
||||
fi->len += len;
|
||||
|
|
|
|||
|
|
@ -1499,8 +1499,9 @@ int stratix10_svc_async_poll(struct stratix10_svc_chan *chan,
|
|||
WARN_ON_ONCE(1);
|
||||
}
|
||||
return 0;
|
||||
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) {
|
||||
dev_dbg(ctrl->dev, "async message is still in progress\n");
|
||||
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY ||
|
||||
handle->res.a0 == INTEL_SIP_SMC_STATUS_NO_RESPONSE) {
|
||||
dev_dbg(ctrl->dev, "async message is not ready yet\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
|
@ -1857,14 +1858,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
|
|||
struct gen_pool *genpool = chan->ctrl->genpool;
|
||||
size_t s = roundup(size, 1 << genpool->min_alloc_order);
|
||||
|
||||
pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
|
||||
pmem = kzalloc_obj(*pmem);
|
||||
if (!pmem)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
guard(mutex)(&svc_mem_lock);
|
||||
va = gen_pool_alloc(genpool, s);
|
||||
if (!va)
|
||||
if (!va) {
|
||||
kfree(pmem);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
memset((void *)va, 0, s);
|
||||
pa = gen_pool_virt_to_phys(genpool, va);
|
||||
|
|
@ -1890,6 +1893,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
|
|||
void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
|
||||
{
|
||||
struct stratix10_svc_data_mem *pmem;
|
||||
|
||||
guard(mutex)(&svc_mem_lock);
|
||||
|
||||
list_for_each_entry(pmem, &svc_data_mem, node)
|
||||
|
|
@ -1898,10 +1902,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
|
|||
(unsigned long)kaddr, pmem->size);
|
||||
pmem->vaddr = NULL;
|
||||
list_del(&pmem->node);
|
||||
kfree(pmem);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(&svc_data_mem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
|
||||
|
||||
|
|
@ -2046,12 +2049,12 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
|
|||
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
|
||||
struct stratix10_svc *svc = ctrl->svc;
|
||||
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
|
||||
stratix10_svc_async_exit(ctrl);
|
||||
|
||||
of_platform_depopulate(ctrl->dev);
|
||||
|
||||
platform_device_unregister(svc->stratix10_svc_rsu);
|
||||
|
||||
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
|
||||
if (ctrl->chans[i].task) {
|
||||
kthread_stop(ctrl->chans[i].task);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -3324,7 +3324,8 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
|||
acrtc = get_crtc_by_otg_inst(
|
||||
adev, state->stream_status[i].primary_otg_inst);
|
||||
|
||||
if (acrtc && state->stream_status[i].plane_count != 0) {
|
||||
if (acrtc && state->stream_status[i].plane_count != 0 &&
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
|
||||
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -280,10 +280,19 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
|||
* is enabled. On DCE, vupdate is only needed in VRR mode.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
|
||||
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, enable);
|
||||
if (enable) {
|
||||
rc = amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Get vupdate_irq ret=%d\n", rc);
|
||||
} else {
|
||||
rc = amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type);
|
||||
drm_dbg_vbl(crtc->dev, "Put vupdate_irq ret=%d\n", rc);
|
||||
}
|
||||
} else if (dc_supports_vrr(dm->dc->ctx->dce_version)) {
|
||||
if (enable) {
|
||||
/* vblank irq on -> Only need vupdate irq in vrr mode */
|
||||
/* vblank irq on -> Only need vupdate irq in vrr mode
|
||||
* Not ref-counted since we need explicit enable/disable
|
||||
* for DCE VRR handling
|
||||
*/
|
||||
if (amdgpu_dm_crtc_vrr_active(acrtc_state))
|
||||
rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
|
|||
const struct dev_pagemap *other = NULL;
|
||||
int err, i;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
pfns = kvcalloc(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (!pfns)
|
||||
return DRM_GPUSVM_SCAN_UNPOPULATED;
|
||||
|
||||
|
|
@ -1753,8 +1753,10 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
|
|||
return -EFAULT;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (!pfns)
|
||||
if (!pfns) {
|
||||
mmput(mm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hmm_range.hmm_pfns = pfns;
|
||||
while (!time_after(jiffies, timeout)) {
|
||||
|
|
|
|||
|
|
@ -727,8 +727,10 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
|
|||
}
|
||||
|
||||
err = ops->populate_devmem_pfn(devmem_allocation, npages, migrate.dst);
|
||||
if (err)
|
||||
goto err_aborted_migration;
|
||||
if (err) {
|
||||
npages = 0;
|
||||
goto err_finalize;
|
||||
}
|
||||
|
||||
own_pages = 0;
|
||||
|
||||
|
|
@ -807,8 +809,11 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
|
|||
msecs_to_jiffies(mdetails->timeslice_ms);
|
||||
|
||||
err_finalize:
|
||||
if (err)
|
||||
if (err) {
|
||||
drm_pagemap_migration_unlock_put_pages(npages, migrate.dst);
|
||||
for (i = npages; i < npages_in_range(start, end); ++i)
|
||||
migrate.dst[i] = 0;
|
||||
}
|
||||
err_aborted_migration:
|
||||
migrate_vma_pages(&migrate);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
|
|||
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
|
||||
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
|
||||
u32 temp;
|
||||
int ret;
|
||||
|
||||
i2c_dev->status = I2C_STAT_INIT;
|
||||
i2c_dev->msg = pmsg;
|
||||
|
|
@ -109,9 +110,14 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
|
|||
HDMI_WRITE(HDMI_HI2CHCR, temp);
|
||||
HDMI_READ(HDMI_HI2CHCR);
|
||||
|
||||
while (i2c_dev->status != I2C_TRANSACTION_DONE)
|
||||
wait_for_completion_interruptible_timeout(&i2c_dev->complete,
|
||||
while (i2c_dev->status != I2C_TRANSACTION_DONE) {
|
||||
ret = wait_for_completion_interruptible_timeout(&i2c_dev->complete,
|
||||
10 * HZ);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -130,7 +136,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
|||
{
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
|
||||
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
mutex_lock(&i2c_dev->i2c_lock);
|
||||
|
||||
|
|
@ -142,9 +148,11 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
|||
for (i = 0; i < num; i++) {
|
||||
if (pmsg->len && pmsg->buf) {
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
xfer_read(adap, pmsg);
|
||||
ret = xfer_read(adap, pmsg);
|
||||
else
|
||||
xfer_write(adap, pmsg);
|
||||
ret = xfer_write(adap, pmsg);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
pmsg++; /* next message */
|
||||
}
|
||||
|
|
@ -154,6 +162,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
|||
|
||||
mutex_unlock(&i2c_dev->i2c_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -615,12 +615,7 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp)
|
|||
int ret;
|
||||
u8 bit_min, bit_max;
|
||||
|
||||
/*
|
||||
* Since we only support Fully AUX Based VESA Backlight interface make sure
|
||||
* backlight enable is possible via AUX along with backlight adjustment
|
||||
*/
|
||||
if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP &&
|
||||
intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
|
||||
if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP))
|
||||
return false;
|
||||
|
||||
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min);
|
||||
|
|
|
|||
|
|
@ -747,6 +747,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
|
|||
|
||||
pvr_gem_object_get(pvr_obj);
|
||||
|
||||
mutex_lock(&vm_ctx->lock);
|
||||
err = drm_gpuvm_exec_lock(&vm_exec);
|
||||
if (err)
|
||||
goto err_cleanup;
|
||||
|
|
@ -756,6 +757,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj,
|
|||
drm_gpuvm_exec_unlock(&vm_exec);
|
||||
|
||||
err_cleanup:
|
||||
mutex_unlock(&vm_ctx->lock);
|
||||
pvr_vm_bind_op_fini(&bind_op);
|
||||
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ config DRM_PANEL_HIMAX_HX83121A
|
|||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
help
|
||||
|
|
@ -332,6 +333,7 @@ config DRM_PANEL_ILITEK_ILI9882T
|
|||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
help
|
||||
Say Y if you want to enable support for panels based on the
|
||||
|
|
@ -954,6 +956,7 @@ config DRM_PANEL_SAMSUNG_S6E3HA8
|
|||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
help
|
||||
Say Y or M here if you want to enable support for the
|
||||
|
|
|
|||
|
|
@ -2562,9 +2562,12 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
|
|||
"Couldn't get our power regulator\n");
|
||||
|
||||
ctx->iovcc = devm_regulator_get_optional(&dsi->dev, "iovcc");
|
||||
if (IS_ERR(ctx->iovcc))
|
||||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
|
||||
if (IS_ERR(ctx->iovcc)) {
|
||||
if (PTR_ERR(ctx->iovcc) != -ENODEV)
|
||||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->iovcc),
|
||||
"Couldn't get our iovcc regulator\n");
|
||||
ctx->iovcc = NULL;
|
||||
}
|
||||
|
||||
ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset))
|
||||
|
|
|
|||
|
|
@ -95,13 +95,9 @@ static void drm_gem_shmem_test_obj_create_private(struct kunit *test)
|
|||
sg_init_one(sgt->sgl, buf, TEST_SIZE);
|
||||
|
||||
/*
|
||||
* Set the DMA mask to 64-bits and map the sgtables
|
||||
* otherwise drm_gem_shmem_free will cause a warning
|
||||
* on debug kernels.
|
||||
* Map the sgtables otherwise drm_gem_shmem_free will cause a warning on
|
||||
* debug kernels.
|
||||
*/
|
||||
ret = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(64));
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
ret = dma_map_sgtable(drm_dev->dev, sgt, DMA_BIDIRECTIONAL, 0);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
|
|
@ -352,11 +348,19 @@ static int drm_gem_shmem_test_init(struct kunit *test)
|
|||
{
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
int ret;
|
||||
|
||||
/* Allocate a parent device */
|
||||
dev = drm_kunit_helper_alloc_device(test);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
|
||||
|
||||
/*
|
||||
* Set the DMA mask to 64-bits to avoid intermittent failures calling
|
||||
* drm_gem_shmem_get_pages_sgt().
|
||||
*/
|
||||
ret = dma_set_mask(dev, DMA_BIT_MASK(64));
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
/*
|
||||
* The DRM core will automatically initialize the GEM core and create
|
||||
* a DRM Memory Manager object which provides an address space pool
|
||||
|
|
|
|||
|
|
@ -315,33 +315,16 @@ static const u32 appletbdrm_primary_plane_formats[] = {
|
|||
DRM_FORMAT_XRGB8888, /* emulated */
|
||||
};
|
||||
|
||||
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *state)
|
||||
static int appletbdrm_primary_plane_helper_begin_fb_access(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_plane_state)
|
||||
{
|
||||
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
||||
struct drm_crtc *new_crtc = new_plane_state->crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
struct appletbdrm_plane_state *appletbdrm_state = to_appletbdrm_plane_state(new_plane_state);
|
||||
size_t frames_size = 0;
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_rect damage;
|
||||
size_t frames_size = 0;
|
||||
size_t request_size;
|
||||
int ret;
|
||||
|
||||
if (new_crtc)
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (!new_plane_state->visible)
|
||||
return 0;
|
||||
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, new_plane_state);
|
||||
drm_atomic_helper_damage_iter_init(&iter, plane->state, new_plane_state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &damage) {
|
||||
frames_size += struct_size((struct appletbdrm_frame *)0, buf, rect_size(&damage));
|
||||
}
|
||||
|
|
@ -366,6 +349,29 @@ static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
|||
appletbdrm_state->request_size = request_size;
|
||||
appletbdrm_state->frames_size = frames_size;
|
||||
|
||||
return drm_gem_begin_shadow_fb_access(plane, new_plane_state);
|
||||
}
|
||||
|
||||
static int appletbdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||
struct drm_crtc *new_crtc = new_plane_state->crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
int ret;
|
||||
|
||||
if (new_crtc)
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
DRM_PLANE_NO_SCALING,
|
||||
false, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (!new_plane_state->visible)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +474,7 @@ static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
|
|||
}
|
||||
|
||||
static void appletbdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
|
||||
struct drm_atomic_commit *old_state)
|
||||
struct drm_atomic_commit *old_state)
|
||||
{
|
||||
struct appletbdrm_device *adev = drm_to_adev(plane->dev);
|
||||
struct drm_device *drm = plane->dev;
|
||||
|
|
@ -552,7 +558,8 @@ static void appletbdrm_primary_plane_destroy_state(struct drm_plane *plane,
|
|||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs appletbdrm_primary_plane_helper_funcs = {
|
||||
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
|
||||
.begin_fb_access = appletbdrm_primary_plane_helper_begin_fb_access,
|
||||
.end_fb_access = drm_gem_end_shadow_fb_access,
|
||||
.atomic_check = appletbdrm_primary_plane_helper_atomic_check,
|
||||
.atomic_update = appletbdrm_primary_plane_helper_atomic_update,
|
||||
.atomic_disable = appletbdrm_primary_plane_helper_atomic_disable,
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
#include <drm/ttm/ttm_backup.h>
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/page-flags.h>
|
||||
#include <linux/swap.h>
|
||||
|
||||
#include "ttm_pool_internal.h"
|
||||
|
||||
/*
|
||||
* Need to map shmem indices to handle since a handle value
|
||||
* of 0 means error, following the swp_entry_t convention.
|
||||
|
|
@ -68,17 +69,23 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
|
|||
}
|
||||
|
||||
/**
|
||||
* ttm_backup_backup_page() - Backup a page
|
||||
* ttm_backup_backup_folio() - Backup a folio
|
||||
* @backup: The struct backup pointer to use.
|
||||
* @page: The page to back up.
|
||||
* @writeback: Whether to perform immediate writeback of the page.
|
||||
* @folio: The folio to back up.
|
||||
* @order: The allocation order of @folio. Since TTM allocates higher-order
|
||||
* pages without __GFP_COMP, folio_nr_pages(@folio) would always
|
||||
* return 1; the caller must pass the true order explicitly.
|
||||
* @writeback: Whether to perform immediate writeback of the folio's pages.
|
||||
* This may have performance implications.
|
||||
* @idx: A unique integer for each page and each struct backup.
|
||||
* @idx: A unique integer for the first page of the folio and each struct backup.
|
||||
* This allows the backup implementation to avoid managing
|
||||
* its address space separately.
|
||||
* @page_gfp: The gfp value used when the page was allocated.
|
||||
* This is used for accounting purposes.
|
||||
* @folio_gfp: The gfp value used when the folio was allocated.
|
||||
* Currently unused.
|
||||
* @alloc_gfp: The gfp to be used when allocating memory.
|
||||
* @nr_pages_backed: Output. On a successful return, set to the number of
|
||||
* pages actually backed up, which may be less than (1 << @order)
|
||||
* if an -ENOMEM was encountered mid-folio.
|
||||
*
|
||||
* Context: If called from reclaim context, the caller needs to
|
||||
* assert that the shrinker gfp has __GFP_FS set, to avoid
|
||||
|
|
@ -87,53 +94,87 @@ int ttm_backup_copy_page(struct file *backup, struct page *dst,
|
|||
* that the shrinker gfp has __GFP_IO set, since without it,
|
||||
* we're not allowed to start backup IO.
|
||||
*
|
||||
* Return: A handle on success. Negative error code on failure.
|
||||
*
|
||||
* Note: This function could be extended to back up a folio and
|
||||
* implementations would then split the folio internally if needed.
|
||||
* Drawback is that the caller would then have to keep track of
|
||||
* the folio size- and usage.
|
||||
* Return: A handle for the first backed-up page on success (handles for
|
||||
* subsequent pages follow sequentially). -ENOMEM if no pages could be backed
|
||||
* up. Any other negative error code if a non-ENOMEM failure occurred; in that
|
||||
* case any pages backed up so far are truncated before returning.
|
||||
*/
|
||||
s64
|
||||
ttm_backup_backup_page(struct file *backup, struct page *page,
|
||||
bool writeback, pgoff_t idx, gfp_t page_gfp,
|
||||
gfp_t alloc_gfp)
|
||||
ttm_backup_backup_folio(struct file *backup, struct folio *folio,
|
||||
unsigned int order, bool writeback, pgoff_t idx,
|
||||
gfp_t folio_gfp, gfp_t alloc_gfp,
|
||||
pgoff_t *nr_pages_backed)
|
||||
{
|
||||
struct address_space *mapping = backup->f_mapping;
|
||||
unsigned long handle = 0;
|
||||
int nr_pages = 1 << order;
|
||||
struct folio *to_folio;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
to_folio = shmem_read_folio_gfp(mapping, idx, alloc_gfp);
|
||||
if (IS_ERR(to_folio))
|
||||
return PTR_ERR(to_folio);
|
||||
*nr_pages_backed = 0;
|
||||
|
||||
folio_mark_accessed(to_folio);
|
||||
folio_lock(to_folio);
|
||||
folio_mark_dirty(to_folio);
|
||||
copy_highpage(folio_file_page(to_folio, idx), page);
|
||||
handle = ttm_backup_shmem_idx_to_handle(idx);
|
||||
for (i = 0; i < nr_pages; ) {
|
||||
int to_nr, j;
|
||||
|
||||
if (writeback && !folio_mapped(to_folio) &&
|
||||
folio_clear_dirty_for_io(to_folio)) {
|
||||
folio_set_reclaim(to_folio);
|
||||
ret = shmem_writeout(to_folio, NULL, NULL);
|
||||
if (!folio_test_writeback(to_folio))
|
||||
folio_clear_reclaim(to_folio);
|
||||
/*
|
||||
* If writeout succeeds, it unlocks the folio. errors
|
||||
* are otherwise dropped, since writeout is only best
|
||||
* effort here.
|
||||
* Only inject past the first subpage so *nr_pages_backed is
|
||||
* always > 0 here, matching a genuine mid-compound -ENOMEM
|
||||
* and driving the caller's reactive split fallback instead
|
||||
* of an early, no-progress failure.
|
||||
*/
|
||||
if (ret)
|
||||
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && i &&
|
||||
ttm_backup_fault_inject_folio())
|
||||
to_folio = ERR_PTR(-ENOMEM);
|
||||
else
|
||||
to_folio = shmem_read_folio_gfp(mapping, idx + i, alloc_gfp);
|
||||
if (IS_ERR(to_folio)) {
|
||||
int err = PTR_ERR(to_folio);
|
||||
|
||||
if (err == -ENOMEM && *nr_pages_backed)
|
||||
return ttm_backup_shmem_idx_to_handle(idx);
|
||||
|
||||
if (*nr_pages_backed) {
|
||||
shmem_truncate_range(file_inode(backup),
|
||||
(loff_t)idx << PAGE_SHIFT,
|
||||
((loff_t)(idx + i) << PAGE_SHIFT) - 1);
|
||||
/*
|
||||
* The pages just truncated are no longer
|
||||
* backed up; don't let the caller mistake
|
||||
* them for valid handles.
|
||||
*/
|
||||
*nr_pages_backed = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
to_nr = min_t(int, nr_pages - i,
|
||||
folio_next_index(to_folio) - (idx + i));
|
||||
|
||||
folio_mark_accessed(to_folio);
|
||||
folio_lock(to_folio);
|
||||
folio_mark_dirty(to_folio);
|
||||
|
||||
for (j = 0; j < to_nr; j++)
|
||||
copy_highpage(folio_file_page(to_folio, idx + i + j),
|
||||
folio_page(folio, i + j));
|
||||
|
||||
if (writeback && !folio_mapped(to_folio) &&
|
||||
folio_clear_dirty_for_io(to_folio)) {
|
||||
folio_set_reclaim(to_folio);
|
||||
ret = shmem_writeout(to_folio, NULL, NULL);
|
||||
if (!folio_test_writeback(to_folio))
|
||||
folio_clear_reclaim(to_folio);
|
||||
if (ret == AOP_WRITEPAGE_ACTIVATE)
|
||||
folio_unlock(to_folio);
|
||||
} else {
|
||||
folio_unlock(to_folio);
|
||||
} else {
|
||||
folio_unlock(to_folio);
|
||||
}
|
||||
|
||||
folio_put(to_folio);
|
||||
i += to_nr;
|
||||
*nr_pages_backed = i;
|
||||
}
|
||||
|
||||
folio_put(to_folio);
|
||||
|
||||
return handle;
|
||||
return ttm_backup_shmem_idx_to_handle(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -53,8 +53,23 @@
|
|||
#ifdef CONFIG_FAULT_INJECTION
|
||||
#include <linux/fault-inject.h>
|
||||
static DECLARE_FAULT_ATTR(backup_fault_inject);
|
||||
|
||||
/*
|
||||
* Exposed to ttm_backup.c so a mid-compound subpage can be made to fail
|
||||
* with -ENOMEM, exercising the reactive split-and-retry fallback in
|
||||
* ttm_pool_backup() for high-order backups.
|
||||
*/
|
||||
bool ttm_backup_fault_inject_folio(void)
|
||||
{
|
||||
return should_fail(&backup_fault_inject, 1);
|
||||
}
|
||||
#else
|
||||
#define should_fail(...) false
|
||||
|
||||
bool ttm_backup_fault_inject_folio(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -487,7 +502,7 @@ static void ttm_pool_split_for_swap(struct ttm_pool *pool, struct page *p)
|
|||
/**
|
||||
* DOC: Partial backup and restoration of a struct ttm_tt.
|
||||
*
|
||||
* Swapout using ttm_backup_backup_page() and swapin using
|
||||
* Swapout using ttm_backup_backup_folio() and swapin using
|
||||
* ttm_backup_copy_page() may fail.
|
||||
* The former most likely due to lack of swap-space or memory, the latter due
|
||||
* to lack of memory or because of signal interruption during waits.
|
||||
|
|
@ -1036,12 +1051,12 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
{
|
||||
struct file *backup = tt->backup;
|
||||
struct page *page;
|
||||
unsigned long handle;
|
||||
gfp_t alloc_gfp;
|
||||
gfp_t gfp;
|
||||
int ret = 0;
|
||||
pgoff_t shrunken = 0;
|
||||
pgoff_t i, num_pages;
|
||||
pgoff_t i, j, num_pages, npages;
|
||||
pgoff_t nr_backed;
|
||||
|
||||
if (WARN_ON(ttm_tt_is_backed_up(tt)))
|
||||
return -EINVAL;
|
||||
|
|
@ -1119,9 +1134,11 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
if (IS_ENABLED(CONFIG_FAULT_INJECTION) && should_fail(&backup_fault_inject, 1))
|
||||
num_pages = DIV_ROUND_UP(num_pages, 2);
|
||||
|
||||
for (i = 0; i < num_pages; ++i) {
|
||||
s64 shandle;
|
||||
for (i = 0; i < num_pages; i += npages) {
|
||||
unsigned int order;
|
||||
s64 handle;
|
||||
|
||||
npages = 1;
|
||||
page = tt->pages[i];
|
||||
if (unlikely(!page))
|
||||
continue;
|
||||
|
|
@ -1130,19 +1147,61 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt,
|
|||
if (unlikely(ttm_backup_page_ptr_is_handle(page)))
|
||||
continue;
|
||||
|
||||
ttm_pool_split_for_swap(pool, page);
|
||||
order = ttm_pool_page_order(pool, page);
|
||||
npages = 1UL << order;
|
||||
|
||||
shandle = ttm_backup_backup_page(backup, page, flags->writeback, i,
|
||||
gfp, alloc_gfp);
|
||||
if (shandle < 0) {
|
||||
/* We allow partially shrunken tts */
|
||||
ret = shandle;
|
||||
/*
|
||||
* We don't allow dipping kernel reserves for high order backup
|
||||
*/
|
||||
if (order)
|
||||
alloc_gfp |= __GFP_NOMEMALLOC;
|
||||
else
|
||||
alloc_gfp &= ~__GFP_NOMEMALLOC;
|
||||
|
||||
/*
|
||||
* Back up the compound atomically at its native order. If
|
||||
* fault injection truncated num_pages mid-compound, skip
|
||||
* the partial tail rather than splitting.
|
||||
*/
|
||||
if (unlikely(i + npages > num_pages))
|
||||
break;
|
||||
|
||||
handle = ttm_backup_backup_folio(backup, page_folio(page),
|
||||
order, flags->writeback, i,
|
||||
gfp, alloc_gfp,
|
||||
&nr_backed);
|
||||
/*
|
||||
* Zero progress on this compound (whether order 0 or a
|
||||
* high-order compound that failed before backing up even
|
||||
* its first subpage) is unrecoverable: bail out rather than
|
||||
* looping forever with npages == nr_backed == 0 below.
|
||||
*/
|
||||
if (unlikely(handle < 0 && !nr_backed)) {
|
||||
ret = handle;
|
||||
break;
|
||||
}
|
||||
handle = shandle;
|
||||
tt->pages[i] = ttm_backup_handle_to_page_ptr(handle);
|
||||
__free_pages_gpu_account(page, 0, false);
|
||||
shrunken++;
|
||||
|
||||
for (j = 0; j < nr_backed; j++)
|
||||
tt->pages[i + j] = ttm_backup_handle_to_page_ptr(handle + j);
|
||||
|
||||
shrunken += nr_backed;
|
||||
|
||||
if (unlikely(nr_backed < npages)) {
|
||||
/*
|
||||
* Partial OOM backup: split the compound and free the
|
||||
* subpages whose content is now in shmem. Continue the
|
||||
* loop from the first un-backed order-0 page.
|
||||
*/
|
||||
ttm_pool_split_for_swap(pool, page);
|
||||
for (j = 0; j < nr_backed; j++)
|
||||
__free_pages_gpu_account(page + j, 0, false);
|
||||
npages = nr_backed;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fully backed up: free at native order. */
|
||||
page->private = 0;
|
||||
__free_pages_gpu_account(page, order, false);
|
||||
}
|
||||
|
||||
return shrunken ? shrunken : ret;
|
||||
|
|
|
|||
|
|
@ -22,4 +22,12 @@ static inline unsigned int ttm_pool_beneficial_order(struct ttm_pool *pool)
|
|||
return pool->alloc_flags & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implemented in ttm_pool.c, used by ttm_backup.c. Returns true if a fault
|
||||
* should be injected mid-compound to test the reactive split-and-retry
|
||||
* fallback in ttm_pool_backup(). Always returns false when
|
||||
* CONFIG_FAULT_INJECTION is disabled.
|
||||
*/
|
||||
bool ttm_backup_fault_inject_folio(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -571,6 +571,8 @@ extern bool super_pages;
|
|||
void v3d_init_hw_state(struct v3d_dev *v3d);
|
||||
int v3d_gem_init(struct drm_device *dev);
|
||||
void v3d_gem_destroy(struct drm_device *dev);
|
||||
void v3d_idle_axi(struct v3d_dev *v3d, int core);
|
||||
void v3d_idle_gca(struct v3d_dev *v3d);
|
||||
void v3d_reset_sms(struct v3d_dev *v3d);
|
||||
void v3d_reset(struct v3d_dev *v3d);
|
||||
void v3d_invalidate_caches(struct v3d_dev *v3d);
|
||||
|
|
|
|||
|
|
@ -36,9 +36,21 @@ v3d_init_core(struct v3d_dev *v3d, int core)
|
|||
V3D_CORE_WRITE(core, V3D_CTL_L2TFLEND, ~0);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
v3d_idle_axi(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
if (v3d->ver >= V3D_GEN_71) {
|
||||
V3D_WRITE(V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
|
||||
|
||||
if (wait_for((V3D_READ(V3D_GMP_STATUS(v3d->ver)) &
|
||||
(V3D_GMP_STATUS_RD_COUNT_MASK |
|
||||
V3D_GMP_STATUS_WR_COUNT_MASK |
|
||||
V3D_GMP_STATUS_CFG_BUSY)) == 0, 100)) {
|
||||
drm_err(&v3d->drm, "Failed to wait for safe GMP shutdown\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
V3D_CORE_WRITE(core, V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ);
|
||||
|
||||
if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) &
|
||||
|
|
@ -49,7 +61,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int core)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
v3d_idle_gca(struct v3d_dev *v3d)
|
||||
{
|
||||
if (v3d->ver >= V3D_GEN_41)
|
||||
|
|
|
|||
|
|
@ -54,8 +54,15 @@ int v3d_power_suspend(struct device *dev)
|
|||
|
||||
v3d_clean_caches(v3d);
|
||||
|
||||
/* Wait until V3D has no active or pending AXI transactions. */
|
||||
v3d_idle_axi(v3d, 0);
|
||||
v3d_idle_gca(v3d);
|
||||
|
||||
ret = v3d_suspend_sms(v3d);
|
||||
if (ret) {
|
||||
/* Staying active: undo the GMP STOP_REQ from v3d_idle_axi(). */
|
||||
V3D_WRITE(V3D_GMP_CFG(v3d->ver),
|
||||
V3D_READ(V3D_GMP_CFG(v3d->ver)) & ~V3D_GMP_CFG_STOP_REQ);
|
||||
v3d_irq_enable(v3d);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -732,9 +732,13 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
|
|||
{
|
||||
struct vc4_bo *bo = to_vc4_bo(obj);
|
||||
|
||||
if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
|
||||
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
|
||||
return -EINVAL;
|
||||
if (bo->validated_shader) {
|
||||
if (vma->vm_flags & VM_WRITE) {
|
||||
DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vm_flags_clear(vma, VM_MAYWRITE);
|
||||
}
|
||||
|
||||
mutex_lock(&bo->madv_lock);
|
||||
|
|
@ -1044,7 +1048,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
|
|||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int i;
|
||||
|
||||
timer_delete(&vc4->bo_cache.time_timer);
|
||||
timer_shutdown_sync(&vc4->bo_cache.time_timer);
|
||||
cancel_work_sync(&vc4->bo_cache.time_work);
|
||||
|
||||
vc4_bo_cache_purge(dev);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user