spi: Add support for StarFive JHB100 SFC

Changhuang Liang <changhuang.liang@starfivetech.com> says:

This serial add support for the StarFive JHB100 SoC SPI Flash
Controller (SFC), which is based on the Synopsys DesignWare SSI
version 2.00a but with some customizations and it also add
enhanced SPI for DesignWare SPI controllers.

I picked up some patches from series [1].
This series depends on the series [2]:

[1] https://lore.kernel.org/all/20221212180732.79167-1-sudip.mukherjee@sifive.com/
[2] https://lore.kernel.org/all/20260521012932.24163-1-changhuang.liang@starfivetech.com/

v1: https://lore.kernel.org/all/20260709055204.138168-1-changhuang.liang@starfivetech.com/

Link: https://patch.msgid.link/20260803124044.156998-1-changhuang.liang@starfivetech.com
This commit is contained in:
Mark Brown
2026-08-04 13:47:02 +01:00
530 changed files with 7465 additions and 2947 deletions

View File

@@ -72,6 +72,7 @@ Alice Mikityanska <alice.kernel@fastmail.im> <maximmi@nvidia.com>
Alice Mikityanska <alice.kernel@fastmail.im> <maxim@isovalent.com>
Alice Mikityanska <alice.kernel@fastmail.im> <alice@isovalent.com>
Aloka Dixit <quic_alokad@quicinc.com> <alokad@codeaurora.org>
Alvin Šipraga <alvin.sipraga@analog.com> <alsi@bang-olufsen.dk>
Al Viro <viro@ftp.linux.org.uk>
Al Viro <viro@zenIV.linux.org.uk>
Amit Blay <quic_ablay@quicinc.com> <ablay@codeaurora.org>
@@ -176,6 +177,7 @@ Brian Cain <bcain@kernel.org> <bcain@quicinc.com>
Brian King <brking@us.ibm.com>
Brian Silverman <bsilver16384@gmail.com> <brian.silverman@bluerivertech.com>
Bryan Tan <bryan-bt.tan@broadcom.com> <bryantan@vmware.com>
Burak Emir <burak.emir@gmail.com> <bqe@google.com>
Cai Huoqing <cai.huoqing@linux.dev> <caihuoqing@baidu.com>
Casey Connolly <casey.connolly@linaro.org> <caleb.connolly@linaro.org>
Casey Connolly <casey.connolly@linaro.org> <caleb@connolly.tech>
@@ -296,6 +298,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>
@@ -648,6 +651,7 @@ Nicholas Piggin <npiggin@gmail.com> <npiggin@suse.de>
Nicholas Piggin <npiggin@gmail.com> <nickpiggin@yahoo.com.au>
Nicholas Piggin <npiggin@gmail.com> <piggin@cyberone.com.au>
Nicolas Ferre <nicolas.ferre@microchip.com> <nicolas.ferre@atmel.com>
Nico Pache <nico.pache@linux.dev> <npache@redhat.com>
Nicolas Pitre <nico@fluxnic.net> <nicolas.pitre@linaro.org>
Nicolas Pitre <nico@fluxnic.net> <nico@linaro.org>
Nicolas Saenz Julienne <nsaenz@kernel.org> <nsaenzjulienne@suse.de>
@@ -695,6 +699,7 @@ Paulo Alcantara <pc@manguebit.org> <palcantara@suse.com>
Paulo Alcantara <pc@manguebit.org> <pc@manguebit.com>
Pavankumar Kondeti <quic_pkondeti@quicinc.com> <pkondeti@codeaurora.org>
Peter A Jonsson <pj@ludd.ltu.se>
Peter Collingbourne <peter@pcc.me.uk> <pcc@google.com>
Peter Hilber <peter.hilber@oss.qualcomm.com> <quic_philber@quicinc.com>
Peter Oruba <peter.oruba@amd.com>
Peter Oruba <peter@oruba.de>

View File

@@ -10,3 +10,4 @@ Description:
0 no adjustment of input current limit. This
helps for more unusual power sources like
solar modules.
============ ===========================================

View File

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

View File

@@ -135,7 +135,6 @@ properties:
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false

View File

@@ -33,6 +33,17 @@ allOf:
else:
properties:
amd,pensando-elba-syscon: false
- if:
properties:
compatible:
contains:
const: starfive,jhb100-sfc
then:
required:
- starfive,sfc-filter-syscon
else:
properties:
starfive,sfc-filter-syscon: false
properties:
compatible:
@@ -67,6 +78,8 @@ properties:
const: amd,pensando-elba-spi
- description: Canaan Kendryte K210 SoS SPI Controller
const: canaan,k210-spi
- description: StarFive JHB100 SoC SPI Flash Controller
const: starfive,jhb100-sfc
- description: Renesas RZ/N1 SPI Controller
items:
- const: renesas,r9a06g032-spi # RZ/N1D
@@ -141,6 +154,15 @@ properties:
Block address to control SPI chip-selects. The Elba SoC system controller
provides an interface to override the native DWC SSI CS control.
starfive,sfc-filter-syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
Phandle to the system controller register that controls the SPI NOR flash
address mode filter. This system controller interface provides additional
configuration to switch between 3-byte and 4-byte addressing modes, which
is required when accessing SPI NOR flash devices with different address
width requirements.
patternProperties:
"@[0-9a-f]$":
type: object

View File

@@ -18,7 +18,14 @@ properties:
- const: qcom,sa8255p-ufshc
reg:
maxItems: 1
minItems: 1
maxItems: 2
reg-names:
minItems: 1
items:
- const: std
- const: mcq
interrupts:
maxItems: 1

View File

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

View File

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

View File

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

View File

@@ -4634,7 +4634,7 @@ F: rust/helpers/cpumask.c
BITMAP API [RUST]
M: Alice Ryhl <aliceryhl@google.com>
M: Burak Emir <bqe@google.com>
M: Burak Emir <burak.emir@gmail.com>
R: Yury Norov <yury.norov@gmail.com>
S: Maintained
F: lib/find_bit_benchmark_rust.rs
@@ -9617,7 +9617,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
@@ -14193,7 +14193,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>
@@ -14887,7 +14887,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
@@ -17253,7 +17253,7 @@ M: Lorenzo Stoakes <ljs@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
R: Liam R. Howlett <liam@infradead.org>
R: Nico Pache <npache@redhat.com>
R: Nico Pache <nico.pache@linux.dev>
R: Ryan Roberts <ryan.roberts@arm.com>
R: Dev Jain <dev.jain@arm.com>
R: Barry Song <baohua@kernel.org>
@@ -20692,7 +20692,6 @@ F: include/linux/switchtec.h
F: include/uapi/linux/switchtec_ioctl.h
PCI DRIVER FOR MOBIVEIL PCIE IP
M: Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
M: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
L: linux-pci@vger.kernel.org
S: Supported
@@ -22736,7 +22735,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/*
@@ -24633,8 +24633,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

View File

@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 2
SUBLEVEL = 0
EXTRAVERSION = -rc5
EXTRAVERSION = -rc6
NAME = Baby Opossum Posse
# *DOCUMENTATION*
@@ -700,13 +700,11 @@ filechk_makefile = { \
echo "include $(abs_srctree)/Makefile"; \
}
$(objtree)/Makefile: FORCE
PHONY += $(CURDIR)/Makefile
$(CURDIR)/Makefile: FORCE
$(call filechk,makefile)
# Prevent $(srcroot)/Makefile from inhibiting the rule to run.
PHONY += $(objtree)/Makefile
outputmakefile: $(objtree)/Makefile
outputmakefile: $(CURDIR)/Makefile
ifeq ($(KBUILD_EXTMOD),)
@if [ -f $(srctree)/.config -o \
-d $(srctree)/include/config -o \

View File

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

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2023 Google LLC
// Authors: Ard Biesheuvel <ardb@google.com>
// Peter Collingbourne <pcc@google.com>
// Peter Collingbourne <peter@pcc.me.uk>
#include <linux/elf.h>
#include <linux/init.h>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -168,7 +168,7 @@ vdso_prepare: prepare0
endif
endif
vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_MMU) += arch/riscv/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_RISCV_USER_CFI) += arch/riscv/kernel/vdso_cfi/vdso-cfi.so.dbg
vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg

View File

@@ -93,10 +93,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
for (alt = begin; alt < end; alt++) {
if (alt->vendor_id != SIFIVE_VENDOR_ID)
continue;
if (alt->patch_id >= ERRATA_SIFIVE_NUMBER) {
WARN(1, "This errata id:%d is not in kernel errata list", alt->patch_id);
if (alt->patch_id >= ERRATA_SIFIVE_NUMBER)
continue;
}
tmp = (1U << alt->patch_id);
if (cpu_req_errata & tmp) {

View File

@@ -22,13 +22,13 @@ static inline cycles_t get_cycles(void)
#else /* !CONFIG_64BIT */
static inline u32 get_cycles(void)
{
return readl_relaxed(((u32 *)clint_time_val));
return readl_relaxed(((u32 __iomem *)clint_time_val));
}
#define get_cycles get_cycles
static inline u32 get_cycles_hi(void)
{
return readl_relaxed(((u32 *)clint_time_val) + 1);
return readl_relaxed(((u32 __iomem *)clint_time_val) + 1);
}
#define get_cycles_hi get_cycles_hi
#endif /* CONFIG_64BIT */

View File

@@ -289,7 +289,7 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus
}
/* Measure unaligned access speed on all CPUs present at boot in parallel. */
static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
{
schedule_on_each_cpu(check_vector_unaligned_access);
riscv_hwprobe_complete_async_probe();
@@ -297,7 +297,7 @@ static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __alway
return 0;
}
#else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */
static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
{
return 0;
}

View File

@@ -63,7 +63,8 @@ EXPORT_SYMBOL(phys_ram_base);
#ifdef CONFIG_SPARSEMEM_VMEMMAP
#define VMEMMAP_ADDR_ALIGN max(1ULL << SECTION_SIZE_BITS, \
MAX_FOLIO_VMEMMAP_ALIGN)
PFN_PHYS(MAX_FOLIO_VMEMMAP_ALIGN / \
sizeof(struct page)))
unsigned long vmemmap_start_pfn __ro_after_init;
EXPORT_SYMBOL(vmemmap_start_pfn);
@@ -164,7 +165,9 @@ static void print_vm_layout(void) { }
void __init arch_mm_preinit(void)
{
bool swiotlb = max_pfn > PFN_DOWN(dma32_phys_limit);
bool swiotlb = max_pfn > PFN_DOWN(dma32_phys_limit) &&
memblock_start_of_DRAM() < dma32_phys_limit;
unsigned int swiotlb_flags = SWIOTLB_VERBOSE;
#ifdef CONFIG_FLATMEM
BUG_ON(!mem_map);
#endif /* CONFIG_FLATMEM */
@@ -172,17 +175,22 @@ void __init arch_mm_preinit(void)
if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb &&
dma_cache_alignment != 1) {
/*
* If no bouncing needed for ZONE_DMA, allocate 1MB swiotlb
* buffer per 1GB of RAM for kmalloc() bouncing on
* non-coherent platforms.
* No 32-bit DMA bouncing needed (either all DRAM is within
* the 32-bit limit, or it all starts above it), but
* kmalloc() buffers whose sizes are not cache-line-aligned
* still require bouncing for non-coherent DMA. Use
* SWIOTLB_ANY so that the buffer can be allocated from high
* memory when DRAM starts above dma32_phys_limit. Allocate
* ~1 MB per 1 GB of RAM.
*/
unsigned long size =
DIV_ROUND_UP(memblock_phys_mem_size(), 1024);
swiotlb_adjust_size(min(swiotlb_size_or_default(), size));
swiotlb = true;
swiotlb_flags |= SWIOTLB_ANY;
}
swiotlb_init(swiotlb, SWIOTLB_VERBOSE);
swiotlb_init(swiotlb, swiotlb_flags);
print_vm_layout();
}
@@ -1618,7 +1626,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un
for (; addr < end; addr = next) {
next = pud_addr_end(addr, end);
pudp = pud_base + pud_index(addr);
pudp = pgtable_l4_enabled ? pud_base + pud_index(addr) : pud_base;
pud = pudp_get(pudp);
if (!pud_present(pud))
continue;
@@ -1649,7 +1657,7 @@ static void __meminit remove_p4d_mapping(p4d_t *p4d_base, unsigned long addr, un
for (; addr < end; addr = next) {
next = p4d_addr_end(addr, end);
p4dp = p4d_base + p4d_index(addr);
p4dp = pgtable_l5_enabled ? p4d_base + p4d_index(addr) : p4d_base;
p4d = p4dp_get(p4dp);
if (!p4d_present(p4d))
continue;

View File

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

View File

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

View File

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

View File

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

View File

@@ -188,6 +188,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
goto out_unlock_mmap;
}
ret = -EFAULT;
io_addr = (void __iomem *)((args.pfn << PAGE_SHIFT) |
(mmio_addr & ~PAGE_MASK));

View File

@@ -995,6 +995,9 @@ static int vector_mmsg_rx(struct vector_private *vp, int budget)
*/
dev_kfree_skb_irq(skb);
vp->estats.rx_encaps_errors++;
(*skbuff_vector) = NULL;
mmsg_vector++;
skbuff_vector++;
continue;
}
if (header_check > 0) {

View File

@@ -32,8 +32,15 @@
int memcmp(const void *s1, const void *s2, size_t len)
{
bool diff;
asm("repe cmpsb"
: "=@ccnz" (diff), "+D" (s1), "+S" (s2), "+c" (len));
/*
* Make sure ZF is properly set in the len==0 case because in it,
* RCX==0 and the REPE; CMPSB won't get executed.
*/
asm volatile("test %3, %3\n\t"
"repe cmpsb"
: "=@ccnz" (diff), "+D" (s1), "+S" (s2), "+c" (len)
: : "cc", "memory");
return diff;
}

View File

@@ -515,11 +515,13 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
case 0x00 ... 0x2f:
case 0x40 ... 0x4f:
case 0x60 ... 0x7f:
case 0xd0 ... 0xd7:
setup_force_cpu_cap(X86_FEATURE_ZEN5);
break;
case 0x50 ... 0x5f:
case 0x80 ... 0xaf:
case 0xc0 ... 0xef:
case 0xc0 ... 0xcf:
case 0xd8 ... 0xef:
setup_force_cpu_cap(X86_FEATURE_ZEN6);
break;
default:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1281,14 +1281,18 @@ static void disk_release(struct device *dev)
/*
* To undo the all initialization from blk_mq_init_allocated_queue in
* case of a probe failure where add_disk is never called we have to
* call blk_mq_exit_queue here. We can't do this for the more common
* teardown case (yet) as the tagset can be gone by the time the disk
* is released once it was added.
* call blk_mq_exit_queue here, after stopping the timer and work items
* that I/O issued before add_disk may have left pending. We can't do
* this for the more common teardown case (yet) as the tagset can be
* gone by the time the disk is released once it was added.
*/
if (queue_is_mq(disk->queue) &&
test_bit(GD_OWNS_QUEUE, &disk->state) &&
!test_bit(GD_ADDED, &disk->state))
!test_bit(GD_ADDED, &disk->state)) {
blk_sync_queue(disk->queue);
blk_mq_cancel_work_sync(disk->queue);
blk_mq_exit_queue(disk->queue);
}
blkcg_exit_disk(disk);

View File

@@ -786,7 +786,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
break;
}
trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
if (trans_hdr->len < sizeof(trans_hdr) ||
if (trans_hdr->len < sizeof(*trans_hdr) ||
size_add(user_len, trans_hdr->len) > user_msg->len) {
ret = -EINVAL;
break;

View File

@@ -475,17 +475,29 @@ bool acpi_cpc_valid(void)
}
EXPORT_SYMBOL_GPL(acpi_cpc_valid);
bool cppc_allow_fast_switch(void)
bool cppc_allow_fast_switch(const struct cpumask *cpus)
{
struct cpc_register_resource *desired_reg;
struct cpc_register_resource *desired_reg, *min_reg, *max_reg;
struct cpc_desc *cpc_ptr;
int cpu;
for_each_online_cpu(cpu) {
for_each_cpu(cpu, cpus) {
cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
if (!cpc_ptr)
return false;
desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF];
if (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
!CPC_IN_SYSTEM_IO(desired_reg))
min_reg = &cpc_ptr->cpc_regs[MIN_PERF];
max_reg = &cpc_ptr->cpc_regs[MAX_PERF];
if (!CPC_SUPPORTED(desired_reg) ||
(!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
!CPC_IN_SYSTEM_IO(desired_reg)) ||
(CPC_SUPPORTED(min_reg) &&
!CPC_IN_SYSTEM_MEMORY(min_reg) &&
!CPC_IN_SYSTEM_IO(min_reg)) ||
(CPC_SUPPORTED(max_reg) &&
!CPC_IN_SYSTEM_MEMORY(max_reg) &&
!CPC_IN_SYSTEM_IO(max_reg)))
return false;
}
@@ -1951,16 +1963,17 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
cpc_desc->write_cmd_status = 0;
}
cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
if (CPC_SUPPORTED(desired_reg))
cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
/*
* Only write if min_perf and max_perf not zero. Some drivers pass zero
* value to min and max perf, but they don't mean to set the zero value,
* they just don't want to write to those registers.
*/
if (perf_ctrls->min_perf)
if (perf_ctrls->min_perf && CPC_SUPPORTED(min_perf_reg))
cpc_write(cpu, min_perf_reg, perf_ctrls->min_perf);
if (perf_ctrls->max_perf)
if (perf_ctrls->max_perf && CPC_SUPPORTED(max_perf_reg))
cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf);
if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg))

View File

@@ -211,7 +211,7 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
rc = phy_init(hpriv->phys[i]);
if (rc)
goto disable_rsts;
goto exit_phys;
}
/* De-assert the controller reset */
@@ -230,14 +230,24 @@ static int ceva_ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
return 0;
disable_rsts:
ahci_platform_deassert_rsts(hpriv);
disable_phys:
while (--i >= 0) {
if (ahci_ignore_port(hpriv, i))
continue;
phy_power_off(hpriv->phys[i]);
phy_exit(hpriv->phys[i]);
}
ahci_platform_assert_rsts(hpriv);
goto disable_clks;
exit_phys:
while (--i >= 0) {
if (ahci_ignore_port(hpriv, i))
continue;
phy_exit(hpriv->phys[i]);
}
disable_clks:
ahci_platform_disable_clks(hpriv);

View File

@@ -4413,6 +4413,15 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "WDC WD3000JD-*", NULL, ATA_QUIRK_WD_BROKEN_LPM },
{ "WDC WD3200JD-*", NULL, ATA_QUIRK_WD_BROKEN_LPM },
/*
* WD drives with LPM issues (irrespective of supported SATA speeds).
* (Unlike ATA_QUIRK_WD_BROKEN_LPM, which is only applied if the drive
* exposes SATA Gen1 speed support, and SATA Gen1 speed support only.)
*/
{ "WDC WD100EFGX-68CPLN0", NULL, ATA_QUIRK_NOLPM },
{ "WDC WD102KFBX-68M95N0", NULL, ATA_QUIRK_NOLPM },
{ "WD Green 2.5 480GB", NULL, ATA_QUIRK_NOLPM },
/*
* This sata dom device goes on a walkabout when the ATA_LOG_DIRECTORY
* log page is accessed. Ensure we never ask for this log page with

View File

@@ -106,6 +106,12 @@ static const unsigned int ata_eh_flush_timeouts[] = {
UINT_MAX,
};
static const unsigned int ata_eh_standby_timeouts[] = {
15000, /* Some drives may be slow to standby */
/* but don't hold up a suspend too long waiting for them */
UINT_MAX,
};
static const unsigned int ata_eh_other_timeouts[] = {
5000, /* same rationale as identify timeout */
10000, /* ditto */
@@ -147,6 +153,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
.timeouts = ata_eh_other_timeouts, },
{ .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
.timeouts = ata_eh_flush_timeouts },
{ .commands = CMDS(ATA_CMD_STANDBYNOW1),
.timeouts = ata_eh_standby_timeouts },
{ .commands = CMDS(ATA_CMD_VERIFY),
.timeouts = ata_eh_reset_timeouts },
};
@@ -650,29 +658,12 @@ int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
set_host_byte(scmd, DID_OK);
ata_qc_for_each_raw(ap, qc, i) {
if (qc->scsicmd != scmd)
continue;
if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
qc == qc->dev->link->deferred_qc)
if (qc->scsicmd == scmd &&
qc->flags & ATA_QCFLAG_ACTIVE)
break;
}
if (i < ATA_MAX_QUEUE && qc == qc->dev->link->deferred_qc) {
/*
* This is a deferred command that timed out while
* waiting for the command queue to drain. Since the qc
* is not active yet (deferred_qc is still set, so the
* deferred qc work has not issued the command yet),
* simply signal the timeout by finishing the SCSI
* command and clear the deferred qc to prevent the
* deferred qc work from issuing this qc.
*/
WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
qc->dev->link->deferred_qc = NULL;
cancel_work(&qc->dev->link->deferred_qc_work);
set_host_byte(scmd, DID_TIME_OUT);
scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
} else if (i < ATA_MAX_QUEUE) {
if (i < ATA_MAX_QUEUE) {
/* the scmd has an associated qc */
if (!(qc->flags & ATA_QCFLAG_EH)) {
/* which hasn't failed yet, timeout */
@@ -948,10 +939,10 @@ static void ata_eh_set_pending(struct ata_port *ap, bool fastdrain)
ap->pflags |= ATA_PFLAG_EH_PENDING;
/*
* If we have a deferred qc, requeue it so that it is retried once EH
* completes.
* If we have deferred QCs, requeue them so that the SCSI EH task can
* run.
*/
ata_scsi_requeue_deferred_qc(ap);
ata_scsi_requeue_deferred_qc(ap, NULL);
if (!fastdrain)
return;

View File

@@ -913,7 +913,7 @@ static bool ata_scsi_lpm_supported(struct ata_port *ap)
return false;
ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, &ap->link, ENABLED) {
ata_for_each_dev(dev, link, ENABLED) {
if (dev->quirks & ATA_QUIRK_NOLPM)
return false;
}

View File

@@ -1685,26 +1685,80 @@ void ata_scsi_deferred_qc_work(struct work_struct *work)
spin_unlock_irqrestore(ap->lock, flags);
}
void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
struct scsi_cmnd *timedout_scmd)
{
enum scsi_timeout_action action = SCSI_EH_NOT_HANDLED;
struct ata_queued_cmd *qc;
struct ata_link *link;
u32 host_byte;
lockdep_assert_held(ap->lock);
/*
* If we have a deferred qc when a reset occurs or NCQ commands fail,
* do not try to be smart about what to do with this deferred command
* and simply requeue it by completing it with DID_REQUEUE.
* If we have deferred QCs when a reset, a timeout or an NCQ command
* fails, do not try to be smart about what to do with the deferred
* commands and simply terminate them and let the SCSI layer decide
* what to do.
*/
ata_for_each_link(link, ap, PMP_FIRST) {
struct ata_queued_cmd *qc = link->deferred_qc;
qc = link->deferred_qc;
if (!qc)
continue;
if (qc) {
link->deferred_qc = NULL;
cancel_work(&link->deferred_qc_work);
ata_scsi_qc_done(qc, true, DID_REQUEUE << 16);
/*
* Clear the deferred QC so that the deferred work does not try
* to issue it.
*/
link->deferred_qc = NULL;
cancel_work(&link->deferred_qc_work);
/*
* We are going to complete some scsi command, either with
* DID_TIME_OUT if the command timed out while waiting for being
* issued, or with DID_REQUEUE if another command timed out or
* we had a failed command. However, the block layer may re-issue
* these commands immediately, keeping the scsi host busy and
* thus preventing the SCSI EH task from running.
* So schedule EH on the port to prevent accepting new commands
* until everything is sorted out with the error or timeout that
* got us here in the first place. Note that we set EH pending
* on the port before calling ata_port_schedule_eh() so that we
* do not reenter this function from ata_eh_set_pending() with
* timedout_scmd being NULL and erroneously retry deferred QCs
* that have timed out on other links.
*/
if (!ata_port_eh_scheduled(ap)) {
ap->pflags |= ATA_PFLAG_EH_PENDING;
ata_port_schedule_eh(ap);
}
/*
* If we are being called from scsi_timeout(), then we have a
* non-NULL timedout_scmd. If the timed out command is for a
* deferred QC, terminate that deferred QC with DID_TIME_OUT and
* requeue all other deferred QCs. In this case we need to
* return SCSI_EH_DONE, because the timed out command was
* handled.
* If the timed out command is not for a deferred QC, we need to
* requeue all deferred QCs, and return SCSI_EH_NOT_HANDLED so
* that the timed out command gets added to the EH work queue
* with scsi_eh_scmd_add(), for later handling with libata EH
* ata_scsi_cmd_error_handler().
* If timedout_scmd is NULL, we simply need to requeue all
* deferred QCs and the return value does not matter as we were
* not called from scsi_timeout().
*/
if (timedout_scmd && qc->scsicmd == timedout_scmd) {
host_byte = DID_TIME_OUT;
action = SCSI_EH_DONE;
} else {
host_byte = DID_REQUEUE;
}
ata_scsi_qc_done(qc, true, host_byte << 16);
}
return action;
}
static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
@@ -1723,13 +1777,42 @@ static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
return;
if (ata_port_eh_scheduled(ap)) {
ata_scsi_requeue_deferred_qc(ap);
ata_scsi_requeue_deferred_qc(ap, NULL);
return;
}
if (!ap->ops->qc_defer(qc))
queue_work(system_highpri_wq, &link->deferred_qc_work);
}
enum scsi_timeout_action ata_scsi_retry_deferred_qc(struct ata_port *ap,
struct scsi_cmnd *scmd)
{
enum scsi_timeout_action action;
unsigned long flags;
spin_lock_irqsave(ap->lock, flags);
action = ata_scsi_requeue_deferred_qc(ap, scmd);
spin_unlock_irqrestore(ap->lock, flags);
return action;
}
EXPORT_SYMBOL_GPL(ata_scsi_retry_deferred_qc);
enum scsi_timeout_action ata_scsi_eh_timed_out(struct scsi_cmnd *scmd)
{
struct ata_port *ap = ata_shost_to_port(scmd->device->host);
/*
* ata_scsi_cmd_error_handler() takes care of commands that timed out
* while executing. However, if we have deferred QCs while a timeout
* triggers, we must requeue these commands for retry so that we do not
* unnecessarily delay starting the SCSI EH task until these deferred
* commands also time out.
*/
return ata_scsi_retry_deferred_qc(ap, scmd);
}
EXPORT_SYMBOL_GPL(ata_scsi_eh_timed_out);
static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_link *link = qc->dev->link;
@@ -2911,6 +2994,7 @@ static void atapi_fixup_inquiry(struct scsi_cmnd *cmd)
static void atapi_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_link *link = qc->dev->link;
struct scsi_cmnd *cmd = qc->scsicmd;
unsigned int err_mask = qc->err_mask;
@@ -2936,8 +3020,16 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;
ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
return;
if (cmd->result)
ata_scsi_qc_done(qc, false, 0);
else
ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
goto schedule_deferred;
}
if (cmd->result) {
ata_scsi_qc_done(qc, false, 0);
goto schedule_deferred;
}
/* successful completion path */
@@ -2945,6 +3037,9 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
atapi_fixup_inquiry(cmd);
ata_scsi_qc_done(qc, true, SAM_STAT_GOOD);
schedule_deferred:
ata_scsi_schedule_deferred_qc(link);
}
/**
* atapi_xlat - Initialize PACKET taskfile

View File

@@ -180,7 +180,8 @@ enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
struct ata_port *ap)
__must_hold(ap->lock);
void ata_scsi_deferred_qc_work(struct work_struct *work);
void ata_scsi_requeue_deferred_qc(struct ata_port *ap);
enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
struct scsi_cmnd *scmd);
/* libata-eh.c */
extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);

View File

@@ -4027,7 +4027,7 @@ static int mv_platform_probe(struct platform_device *pdev)
/*
* Simple resource validation ..
*/
if (unlikely(pdev->num_resources != 1)) {
if (unlikely(pdev->num_resources != 1 && pdev->num_resources != 2)) {
dev_err(&pdev->dev, "invalid number of resources\n");
return -EINVAL;
}

View File

@@ -4764,6 +4764,15 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
/* update device id */
ub->dev_info.dev_id = ub->ub_number;
/*
* ->state and ->ublksrv_pid are owned by the driver and only read back
* by userspace, but they come from the copied-in dev_info, so reset
* them. Otherwise a device added with ->state != DEAD looks live while
* ->ub_disk is still NULL.
*/
ub->dev_info.state = UBLK_S_DEV_DEAD;
ub->dev_info.ublksrv_pid = -1;
/*
* 64bit flags will be copied back to userspace as feature
* negotiation result, so have to clear flags which driver

View File

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

View File

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

View File

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

View File

@@ -1031,7 +1031,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
return -EINVAL;
}
if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq) {
if (lowest_nonlinear_freq < min_freq || lowest_nonlinear_freq > nominal_freq) {
pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n",
lowest_nonlinear_freq, min_freq, nominal_freq);
return -EINVAL;
@@ -2167,6 +2167,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
};
/*
* Processors without frequency scaling support can't do CPPC.
* CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F.
* show the debug message that helps to check if the CPU has CPPC support for loading issue.
*/
@@ -2175,6 +2176,11 @@ static bool amd_cppc_supported(void)
struct cpuinfo_x86 *c = &cpu_data(0);
bool warn = false;
if (!cpu_feature_enabled(X86_FEATURE_HW_PSTATE)) {
pr_debug_once("frequency scaling is not supported by the processor\n");
return false;
}
if ((boot_cpu_data.x86 == 0x17) && (boot_cpu_data.x86_model < 0x30)) {
pr_debug_once("CPPC feature is not supported by the processor\n");
return false;

View File

@@ -290,19 +290,32 @@ static inline void cppc_freq_invariance_exit(void)
}
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
static void cppc_cpufreq_get_perf_limits(struct cppc_cpudata *cpu_data,
struct cpufreq_policy *policy,
u32 *min_perf, u32 *max_perf)
{
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
unsigned int min_freq, max_freq;
u32 min, max;
min_freq = READ_ONCE(policy->min);
max_freq = READ_ONCE(policy->max);
if (unlikely(min_freq > max_freq))
min_freq = max_freq;
min = cppc_khz_to_perf(caps, min_freq);
max = cppc_khz_to_perf(caps, max_freq);
*min_perf = clamp_t(u32, min, caps->lowest_perf, caps->highest_perf);
*max_perf = clamp_t(u32, max, caps->lowest_perf, caps->highest_perf);
}
static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
struct cpufreq_policy *policy)
{
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
u32 min_perf, max_perf;
min_perf = cppc_khz_to_perf(caps, policy->min);
max_perf = cppc_khz_to_perf(caps, policy->max);
cpu_data->perf_ctrls.min_perf =
clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf);
cpu_data->perf_ctrls.max_perf =
clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf);
cppc_cpufreq_get_perf_limits(cpu_data, policy,
&cpu_data->perf_ctrls.min_perf,
&cpu_data->perf_ctrls.max_perf);
}
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -693,7 +706,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto out;
}
policy->fast_switch_possible = cppc_allow_fast_switch();
policy->fast_switch_possible = cppc_allow_fast_switch(policy->cpus);
policy->dvfs_possible_from_any_cpu = true;
/*

View File

@@ -1084,6 +1084,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
err_out_exit_acpi:
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table);
err_out:
kfree(data);

View File

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

View File

@@ -288,6 +288,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
fdev->parent = cdev_dev(idxd_cdev);
fdev->bus = &dsa_bus_type;
fdev->type = &idxd_cdev_file_type;
idxd_wq_get(wq);
rc = dev_set_name(fdev, "file%d", ctx->id);
if (rc < 0) {
@@ -301,13 +302,14 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
goto failed_dev_add;
}
idxd_wq_get(wq);
mutex_unlock(&wq->wq_lock);
return 0;
failed_dev_add:
failed_dev_name:
mutex_unlock(&wq->wq_lock);
put_device(fdev);
return rc;
failed_ida:
failed_set_pasid:
if (device_user_pasid_enabled(idxd))

View File

@@ -159,18 +159,12 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)
static void idxd_clean_wqs(struct idxd_device *idxd)
{
struct idxd_wq *wq;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_wqs; i++) {
wq = idxd->wqs[i];
if (idxd->hw.wq_cap.op_config)
bitmap_free(wq->opcap_bmap);
kfree(wq->wqcfg);
conf_dev = wq_confdev(wq);
conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
@@ -212,7 +206,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id);
if (rc < 0) {
put_device(conf_dev);
kfree(wq);
goto err_unwind;
}
@@ -227,7 +220,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
if (!wq->wqcfg) {
put_device(conf_dev);
kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -235,9 +227,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
if (idxd->hw.wq_cap.op_config) {
wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
if (!wq->opcap_bmap) {
kfree(wq->wqcfg);
put_device(conf_dev);
kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -252,13 +242,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
err_unwind:
while (--i >= 0) {
wq = idxd->wqs[i];
if (idxd->hw.wq_cap.op_config)
bitmap_free(wq->opcap_bmap);
kfree(wq->wqcfg);
conf_dev = wq_confdev(wq);
conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
@@ -270,15 +255,12 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
static void idxd_clean_engines(struct idxd_device *idxd)
{
struct idxd_engine *engine;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_engines; i++) {
engine = idxd->engines[i];
conf_dev = engine_confdev(engine);
conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
kfree(engine);
}
kfree(idxd->engines);
}
@@ -313,7 +295,6 @@ static int idxd_setup_engines(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id);
if (rc < 0) {
put_device(conf_dev);
kfree(engine);
goto err;
}
@@ -324,10 +305,8 @@ static int idxd_setup_engines(struct idxd_device *idxd)
err:
while (--i >= 0) {
engine = idxd->engines[i];
conf_dev = engine_confdev(engine);
conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
kfree(engine);
}
kfree(idxd->engines);
@@ -336,13 +315,10 @@ static int idxd_setup_engines(struct idxd_device *idxd)
static void idxd_clean_groups(struct idxd_device *idxd)
{
struct idxd_group *group;
int i;
for (i = 0; i < idxd->max_groups; i++) {
group = idxd->groups[i];
put_device(group_confdev(group));
kfree(group);
put_device(group_confdev(idxd->groups[i]));
}
kfree(idxd->groups);
}
@@ -377,7 +353,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id);
if (rc < 0) {
put_device(conf_dev);
kfree(group);
goto err;
}
@@ -402,7 +377,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
while (--i >= 0) {
group = idxd->groups[i];
put_device(group_confdev(group));
kfree(group);
}
kfree(idxd->groups);

View File

@@ -945,16 +945,13 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
spin_lock_irqsave(&vchan->vc.lock, flags);
if (vchan->cyclic) {
vchan->cyclic = false;
if (pchan && pchan->desc) {
struct virt_dma_desc *vd = &pchan->desc->vd;
struct virt_dma_chan *vc = &vchan->vc;
if (pchan && pchan->desc && pchan->desc != pchan->done) {
struct virt_dma_desc *vd = &pchan->desc->vd;
list_add_tail(&vd->node, &vc->desc_completed);
}
vchan_terminate_vdesc(vd);
}
vchan->cyclic = false;
vchan_get_all_descriptors(&vchan->vc, &head);
if (pchan) {

View File

@@ -1099,7 +1099,7 @@ static int switchtec_dma_chan_init(struct switchtec_dma_dev *swdma_dev,
dev_dbg(&pdev->dev, "Channel %d: SE buffer count %d\n", i, se_buf_len);
thresh = se_buf_len / 2;
valid_en_se |= FIELD_GET(SE_THRESH_MASK, thresh);
valid_en_se |= FIELD_PREP(SE_THRESH_MASK, thresh);
writel(valid_en_se, &swdma_chan->mmio_chan_fw->valid_en_se);
/* request irqs */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -92,7 +92,7 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f)
return NULL;
fence = container_of(f, struct amdgpu_amdkfd_fence, base);
if (f->ops == &amdkfd_fence_ops)
if (rcu_access_pointer(f->ops) == &amdkfd_fence_ops)
return fence;
return NULL;

View File

@@ -3096,7 +3096,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
process_info->eviction_fence = new_fence;
replace_eviction_fence(ef, dma_fence_get(&new_fence->base));
} else {
WARN_ONCE(*ef != &process_info->eviction_fence->base,
WARN_ONCE(rcu_access_pointer(*ef) != &process_info->eviction_fence->base,
"KFD eviction fence doesn't match KGD process_info");
}

View File

@@ -1177,19 +1177,6 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.bo);
}
if (adev->debug_vm) {
/* Invalidate all BOs to test for userspace bugs */
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
struct amdgpu_bo *bo = e->bo;
/* ignore duplicates */
if (!bo)
continue;
amdgpu_vm_bo_invalidate(bo, false);
}
}
return 0;
}
@@ -1378,6 +1365,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
/* Cleanup the parser structure */
static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser)
{
struct amdgpu_device *adev = parser->adev;
struct amdgpu_bo_list_entry *e;
unsigned int i;
amdgpu_sync_free(&parser->sync);
@@ -1393,8 +1382,21 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser)
if (parser->ctx)
amdgpu_ctx_put(parser->ctx);
if (parser->bo_list)
if (parser->bo_list) {
if (adev->debug_vm) {
/* Invalidate all BOs to test for userspace bugs */
amdgpu_bo_list_for_each_entry(e, parser->bo_list) {
struct amdgpu_bo *bo = e->bo;
/* ignore duplicates */
if (!bo)
continue;
amdgpu_vm_bo_invalidate(bo, false);
}
}
amdgpu_bo_list_put(parser->bo_list);
}
for (i = 0; i < parser->nchunks; i++)
kvfree(parser->chunks[i].kdata);

View File

@@ -43,6 +43,11 @@
#if defined(CONFIG_DEBUG_FS)
/* Encode milliwatts in the raw Q24.8 sensor report format used by UMR. */
#define AMDGPU_DEBUGFS_PWR_MW_TO_Q24_8(power_mw) \
DIV_ROUND_CLOSEST_ULL((u64)(power_mw) * BIT(8), \
MILLIWATT_PER_WATT)
/**
* amdgpu_debugfs_process_reg_op - Handle MMIO register reads/writes
*
@@ -1104,6 +1109,10 @@ static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf,
return r;
}
if (idx == AMDGPU_PP_SENSOR_GPU_AVG_POWER ||
idx == AMDGPU_PP_SENSOR_GPU_INPUT_POWER)
values[0] = AMDGPU_DEBUGFS_PWR_MW_TO_Q24_8(values[0]);
if (size > valuesize) {
amdgpu_virt_disable_access_debugfs(adev);
return -EINVAL;
@@ -1319,8 +1328,8 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
* @size: Number of bytes to read
* @pos: Offset to seek to
*
* Read the last residency value logged. It doesn't auto update, one needs to
* stop logging before getting the current value.
* Read a live GFXOFF residency sample from firmware. One needs to start logging
* before getting the current value.
*/
static ssize_t amdgpu_debugfs_gfxoff_residency_read(struct file *f, char __user *buf,
size_t size, loff_t *pos)

View File

@@ -2304,6 +2304,7 @@ static int amdgpu_discovery_set_psp_ip_blocks(struct amdgpu_device *adev)
amdgpu_device_ip_block_add(adev, &psp_v14_0_ip_block);
break;
case IP_VERSION(15, 0, 0):
case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 9):
amdgpu_device_ip_block_add(adev, &psp_v15_0_ip_block);
break;

View File

@@ -2908,6 +2908,19 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
return 0;
}
static void amdgpu_restore_umd_profile_pstate_after_runpm(struct amdgpu_device *adev)
{
enum amd_dpm_forced_level level;
uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
level = amdgpu_dpm_get_performance_level(adev);
if (level & profile_mode_mask)
amdgpu_asic_update_umd_stable_pstate(adev, true);
}
static int amdgpu_pmops_runtime_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2952,6 +2965,8 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
amdgpu_restore_umd_profile_pstate_after_runpm(adev);
adev->in_runpm = false;
return 0;
}

View File

@@ -1210,7 +1210,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return -EINVAL;
}
}
ui32 >>= 8;
ui32 /= MILLIWATT_PER_WATT;
break;
case AMDGPU_INFO_SENSOR_GPU_INPUT_POWER:
/* get input GPU power */
@@ -1219,7 +1219,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
(void *)&ui32, &ui32_size)) {
return -EINVAL;
}
ui32 >>= 8;
ui32 /= MILLIWATT_PER_WATT;
break;
case AMDGPU_INFO_SENSOR_VDDNB:
/* get VDDNB in millivolts */

View File

@@ -275,6 +275,7 @@ static int psp_early_init(struct amdgpu_ip_block *ip_block)
psp->boot_time_tmr = false;
break;
case IP_VERSION(15, 0, 0):
case IP_VERSION(15, 0, 5):
case IP_VERSION(15, 0, 9):
psp_v15_0_0_set_psp_funcs(psp);
psp->boot_time_tmr = false;
@@ -1222,6 +1223,33 @@ int psp_memory_partition(struct psp_context *psp, int mode)
return ret;
}
int psp_set_mmhub_eco_sec_level(struct amdgpu_device *adev)
{
int ret;
struct psp_context *psp = &adev->psp;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
cmd->cmd_id = GFX_CMD_ID_SET_MMHUB_ECO_SEC_LEVEL;
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (ret) {
dev_err(psp->adev->dev,
"PSP request failed to set mmuhub eco sec level with ret=%d\n", ret);
release_psp_cmd_buf(psp);
return ret;
}
if (cmd->resp.status) {
dev_err(psp->adev->dev,
"MMHUB ECO SEC LEVEL command 0x%x failed, PSP response status: 0x%X\n",
cmd->cmd_id, cmd->resp.status);
ret = -EIO;
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_ptl_fmt_verify(struct psp_context *psp, enum amdgpu_ptl_fmt fmt,
uint32_t *ptl_fmt)
{
@@ -3476,8 +3504,10 @@ static int psp_load_non_psp_fw(struct psp_context *psp)
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 0) ||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 8) ||
IP_VERSION(15, 0, 5) ||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 8) ||
amdgpu_ip_version(adev, MP0_HWIP, 0) ==
IP_VERSION(15, 0, 9)) &&
(ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 ||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 ||

View File

@@ -656,5 +656,6 @@ int amdgpu_psp_reg_program_no_ring(struct psp_context *psp, uint32_t val,
void amdgpu_psp_debugfs_init(struct amdgpu_device *adev);
int amdgpu_psp_get_fw_type(struct amdgpu_firmware_info *ucode,
enum psp_gfx_fw_type *type);
int psp_set_mmhub_eco_sec_level(struct amdgpu_device *adev);
#endif

View File

@@ -2173,6 +2173,18 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
gtt_size = configured_size;
}
/* Cap GTT so that it does not exceed total physical RAM. */
if (adev->flags & AMD_IS_APU) {
u64 phys_ram = (u64)totalram_pages() << PAGE_SHIFT;
if (gtt_size > phys_ram) {
gtt_size = phys_ram;
dev_info(adev->dev,
"Capping GTT to %uM to not exceed available system memory\n",
(unsigned int)(gtt_size / (1024 * 1024)));
}
}
/* Initialize GTT memory pool */
r = amdgpu_gtt_mgr_init(adev, gtt_size);
if (r) {

View File

@@ -965,6 +965,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
struct amdgpu_vm *vm = &fpriv->vm;
unsigned long key, tmp_key;
struct amdgpu_bo_va *bo_va;
struct amdgpu_usermode_queue *queue;
struct amdgpu_bo *bo;
struct drm_exec exec;
struct xarray xa;
@@ -1080,6 +1081,24 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
dma_fence_wait(bo_va->last_pt_update, false);
dma_fence_wait(vm->last_update, false);
xa_for_each(&uq_mgr->userq_xa, tmp_key, queue) {
bo = queue->wptr_obj.obj;
if (!bo) {
ret = -EINVAL;
goto unlock_all;
}
ret = amdgpu_ttm_alloc_gart(&bo->tbo);
if (unlikely(ret)) {
drm_file_err(uq_mgr->file,
"failed to bind wptr bo to gart on resume, qid=%lu ret=%d\n",
tmp_key, ret);
goto unlock_all;
}
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(bo);
}
ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
if (ret)
drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");

View File

@@ -1553,6 +1553,8 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
struct amdgpu_sync sync;
int r;
if (list_empty(&vm->freed))
return 0;
/*
* Implicitly sync to command submissions in the same VM before

View File

@@ -379,7 +379,7 @@ struct amd_sriov_msg_vf2pf_info {
struct {
uint8_t id;
uint32_t version;
} ucode_info[AMD_SRIOV_MSG_RESERVE_UCODE];
} __packed ucode_info[AMD_SRIOV_MSG_RESERVE_UCODE];
uint64_t dummy_page_addr;
/* FB allocated for guest MES to record UQ info */
uint64_t mes_info_addr;

View File

@@ -398,6 +398,25 @@ static void jpeg_v5_3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
WREG32_SOC15(JPEG, inst_idx, regUVD_JPEG_POWER_STATUS, reg_data);
}
/**
* jpeg_v5_3_0_set_mmhub_eco_sec_level - set jpeg sec lvl reg
*
* @adev: amdgpu_device pointer
*
* request psp to set secure lvl
*/
static int jpeg_v5_3_0_set_mmhub_eco_sec_level(struct amdgpu_device *adev)
{
int r = 0;
if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
/* Request to PSP to program JPEG secure lvl */
r = psp_set_mmhub_eco_sec_level(adev);
}
return r;
}
/**
* jpeg_v5_3_0_start - start JPEG block
*
@@ -423,6 +442,11 @@ static int jpeg_v5_3_0_start(struct amdgpu_device *adev)
if (r)
return r;
/* program JPEG secure lvl register */
r = jpeg_v5_3_0_set_mmhub_eco_sec_level(adev);
if (r)
return r;
/* JPEG disable CGC */
jpeg_v5_3_0_disable_clock_gating(adev);

View File

@@ -70,27 +70,23 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
ret = -EINVAL;
goto fail_map;
}
/* TODO use eviction fence instead of pinning. */
ret = amdgpu_bo_pin(wptr_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
/* Keep WPTR BO under eviction-fence control instead of pinning. */
ret = amdgpu_evf_mgr_attach_fence(&uq_mgr_to_fpriv(uq_mgr)->evf_mgr, wptr_obj->obj);
if (ret) {
DRM_ERROR("Failed to pin wptr bo. ret %d\n", ret);
DRM_ERROR("Failed to attach eviction fence to wptr bo. ret %d\n", ret);
goto fail_map;
}
ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
if (ret) {
DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
goto fail_alloc_gart;
DRM_ERROR("Failed to bind wptr bo to GART. ret %d\n", ret);
goto fail_map;
}
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
drm_exec_fini(&exec);
return 0;
fail_alloc_gart:
amdgpu_bo_unpin(wptr_obj->obj);
fail_map:
amdgpu_bo_unref(&wptr_obj->obj);
fail_lock:
@@ -468,9 +464,6 @@ static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
&queue->mqd.cpu_ptr);
amdgpu_bo_reserve(queue->wptr_obj.obj, true);
amdgpu_bo_unpin(queue->wptr_obj.obj);
amdgpu_bo_unreserve(queue->wptr_obj.obj);
amdgpu_bo_unref(&queue->wptr_obj.obj);
}

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