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

Cross-merge networking fixes after downstream PR (net-6.13-rc4).

No conflicts.

Adjacent changes:

drivers/net/ethernet/renesas/rswitch.h
  32fd46f5b6 ("net: renesas: rswitch: remove speed from gwca structure")
  922b4b955a ("net: renesas: rswitch: rework ts tags management")

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-12-05 11:48:58 -08:00
commit 07e5c4eb94
367 changed files with 4109 additions and 2059 deletions

View File

@ -113,11 +113,8 @@ allOf:
maxItems: 1 maxItems: 1
- if: - if:
properties: required:
compatible: - orientation-switch
contains:
enum:
- fsl,imx95-usb-phy
then: then:
$ref: /schemas/usb/usb-switch.yaml# $ref: /schemas/usb/usb-switch.yaml#

View File

@ -18,6 +18,7 @@ properties:
compatible: compatible:
enum: enum:
- qcom,qca6390-pmu - qcom,qca6390-pmu
- qcom,wcn6750-pmu
- qcom,wcn6855-pmu - qcom,wcn6855-pmu
- qcom,wcn7850-pmu - qcom,wcn7850-pmu
@ -27,6 +28,9 @@ properties:
vddaon-supply: vddaon-supply:
description: VDD_AON supply regulator handle description: VDD_AON supply regulator handle
vddasd-supply:
description: VDD_ASD supply regulator handle
vdddig-supply: vdddig-supply:
description: VDD_DIG supply regulator handle description: VDD_DIG supply regulator handle
@ -42,6 +46,9 @@ properties:
vddio1p2-supply: vddio1p2-supply:
description: VDD_IO_1P2 supply regulator handle description: VDD_IO_1P2 supply regulator handle
vddrfa0p8-supply:
description: VDD_RFA_0P8 supply regulator handle
vddrfa0p95-supply: vddrfa0p95-supply:
description: VDD_RFA_0P95 supply regulator handle description: VDD_RFA_0P95 supply regulator handle
@ -51,12 +58,18 @@ properties:
vddrfa1p3-supply: vddrfa1p3-supply:
description: VDD_RFA_1P3 supply regulator handle description: VDD_RFA_1P3 supply regulator handle
vddrfa1p7-supply:
description: VDD_RFA_1P7 supply regulator handle
vddrfa1p8-supply: vddrfa1p8-supply:
description: VDD_RFA_1P8 supply regulator handle description: VDD_RFA_1P8 supply regulator handle
vddrfa1p9-supply: vddrfa1p9-supply:
description: VDD_RFA_1P9 supply regulator handle description: VDD_RFA_1P9 supply regulator handle
vddrfa2p2-supply:
description: VDD_RFA_2P2 supply regulator handle
vddpcie1p3-supply: vddpcie1p3-supply:
description: VDD_PCIE_1P3 supply regulator handle description: VDD_PCIE_1P3 supply regulator handle
@ -119,6 +132,20 @@ allOf:
- vddpcie1p3-supply - vddpcie1p3-supply
- vddpcie1p9-supply - vddpcie1p9-supply
- vddio-supply - vddio-supply
- if:
properties:
compatible:
contains:
const: qcom,wcn6750-pmu
then:
required:
- vddaon-supply
- vddasd-supply
- vddpmu-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p7-supply
- vddrfa2p2-supply
- if: - if:
properties: properties:
compatible: compatible:

View File

@ -347,7 +347,9 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
`int pm_runtime_resume_and_get(struct device *dev);` `int pm_runtime_resume_and_get(struct device *dev);`
- run pm_runtime_resume(dev) and if successful, increment the device's - run pm_runtime_resume(dev) and if successful, increment the device's
usage counter; return the result of pm_runtime_resume usage counter; returns 0 on success (whether or not the device's
runtime PM status was already 'active') or the error code from
pm_runtime_resume() on failure.
`int pm_request_idle(struct device *dev);` `int pm_request_idle(struct device *dev);`
- submit a request to execute the subsystem-level idle callback for the - submit a request to execute the subsystem-level idle callback for the

View File

@ -3900,7 +3900,7 @@ W: http://www.baycom.org/~tom/ham/ham.html
F: drivers/net/hamradio/baycom* F: drivers/net/hamradio/baycom*
BCACHE (BLOCK LAYER CACHE) BCACHE (BLOCK LAYER CACHE)
M: Coly Li <colyli@suse.de> M: Coly Li <colyli@kernel.org>
M: Kent Overstreet <kent.overstreet@linux.dev> M: Kent Overstreet <kent.overstreet@linux.dev>
L: linux-bcache@vger.kernel.org L: linux-bcache@vger.kernel.org
S: Maintained S: Maintained
@ -8460,7 +8460,7 @@ F: include/video/s1d13xxxfb.h
EROFS FILE SYSTEM EROFS FILE SYSTEM
M: Gao Xiang <xiang@kernel.org> M: Gao Xiang <xiang@kernel.org>
M: Chao Yu <chao@kernel.org> M: Chao Yu <chao@kernel.org>
R: Yue Hu <huyue2@coolpad.com> R: Yue Hu <zbestahu@gmail.com>
R: Jeffle Xu <jefflexu@linux.alibaba.com> R: Jeffle Xu <jefflexu@linux.alibaba.com>
R: Sandeep Dhavale <dhavale@google.com> R: Sandeep Dhavale <dhavale@google.com>
L: linux-erofs@lists.ozlabs.org L: linux-erofs@lists.ozlabs.org

View File

@ -2,7 +2,7 @@
VERSION = 6 VERSION = 6
PATCHLEVEL = 13 PATCHLEVEL = 13
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc2 EXTRAVERSION = -rc3
NAME = Baby Opossum Posse NAME = Baby Opossum Posse
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -297,7 +297,6 @@ config ARC_PAGE_SIZE_16K
config ARC_PAGE_SIZE_4K config ARC_PAGE_SIZE_4K
bool "4KB" bool "4KB"
select HAVE_PAGE_SIZE_4KB select HAVE_PAGE_SIZE_4KB
depends on ARC_MMU_V3 || ARC_MMU_V4
endchoice endchoice
@ -474,7 +473,8 @@ config HIGHMEM
config ARC_HAS_PAE40 config ARC_HAS_PAE40
bool "Support for the 40-bit Physical Address Extension" bool "Support for the 40-bit Physical Address Extension"
depends on ISA_ARCV2 depends on ARC_MMU_V4
depends on !ARC_PAGE_SIZE_4K
select HIGHMEM select HIGHMEM
select PHYS_ADDR_T_64BIT select PHYS_ADDR_T_64BIT
help help

View File

@ -6,7 +6,7 @@
KBUILD_DEFCONFIG := haps_hs_smp_defconfig KBUILD_DEFCONFIG := haps_hs_smp_defconfig
ifeq ($(CROSS_COMPILE),) ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-) CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux- arc-linux-gnu-)
endif endif
cflags-y += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__ cflags-y += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__

View File

@ -54,7 +54,7 @@ ictl_intc: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <30>; ngpios = <30>;
reg = <0>; reg = <0>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;

View File

@ -62,7 +62,7 @@ ictl_intc: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <30>; ngpios = <30>;
reg = <0>; reg = <0>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;

View File

@ -69,7 +69,7 @@ ictl_intc: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <30>; ngpios = <30>;
reg = <0>; reg = <0>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;

View File

@ -250,7 +250,7 @@ gpio0_banka: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <32>; ngpios = <32>;
reg = <0>; reg = <0>;
}; };
@ -258,7 +258,7 @@ gpio0_bankb: gpio-controller@1 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <8>; ngpios = <8>;
reg = <1>; reg = <1>;
}; };
@ -266,7 +266,7 @@ gpio0_bankc: gpio-controller@2 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <8>; ngpios = <8>;
reg = <2>; reg = <2>;
}; };
}; };
@ -281,7 +281,7 @@ gpio1_banka: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <30>; ngpios = <30>;
reg = <0>; reg = <0>;
}; };
@ -289,7 +289,7 @@ gpio1_bankb: gpio-controller@1 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <10>; ngpios = <10>;
reg = <1>; reg = <1>;
}; };
@ -297,7 +297,7 @@ gpio1_bankc: gpio-controller@2 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <8>; ngpios = <8>;
reg = <2>; reg = <2>;
}; };
}; };

View File

@ -308,7 +308,7 @@ gpio_port_a: gpio-controller@0 {
compatible = "snps,dw-apb-gpio-port"; compatible = "snps,dw-apb-gpio-port";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
snps,nr-gpios = <24>; ngpios = <24>;
reg = <0>; reg = <0>;
}; };
}; };

View File

@ -146,7 +146,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <soc/arc/aux.h> #include <soc/arc/arc_aux.h>
/* Helpers */ /* Helpers */
#define TO_KB(bytes) ((bytes) >> 10) #define TO_KB(bytes) ((bytes) >> 10)

View File

@ -48,7 +48,7 @@
\ \
switch(sizeof((_p_))) { \ switch(sizeof((_p_))) { \
case 1: \ case 1: \
_prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \
break; \ break; \
case 4: \ case 4: \
_prev_ = __cmpxchg(_p_, _o_, _n_); \ _prev_ = __cmpxchg(_p_, _o_, _n_); \

View File

@ -9,7 +9,7 @@
#ifndef _ASM_ARC_MMU_ARCV2_H #ifndef _ASM_ARC_MMU_ARCV2_H
#define _ASM_ARC_MMU_ARCV2_H #define _ASM_ARC_MMU_ARCV2_H
#include <soc/arc/aux.h> #include <soc/arc/arc_aux.h>
/* /*
* TLB Management regs * TLB Management regs

View File

@ -2916,7 +2916,7 @@ bool check_jmp_32(u32 curr_off, u32 targ_off, u8 cond)
addendum = (cond == ARC_CC_AL) ? 0 : INSN_len_normal; addendum = (cond == ARC_CC_AL) ? 0 : INSN_len_normal;
disp = get_displacement(curr_off + addendum, targ_off); disp = get_displacement(curr_off + addendum, targ_off);
if (ARC_CC_AL) if (cond == ARC_CC_AL)
return is_valid_far_disp(disp); return is_valid_far_disp(disp);
else else
return is_valid_near_disp(disp); return is_valid_near_disp(disp);

View File

@ -233,7 +233,7 @@ pci: pci@40000000 {
#interrupt-cells = <0x1>; #interrupt-cells = <0x1>;
compatible = "pci-host-ecam-generic"; compatible = "pci-host-ecam-generic";
device_type = "pci"; device_type = "pci";
bus-range = <0x0 0x1>; bus-range = <0x0 0xff>;
reg = <0x0 0x40000000 0x0 0x10000000>; reg = <0x0 0x40000000 0x0 0x10000000>;
ranges = <0x2000000 0x0 0x50000000 0x0 0x50000000 0x0 0x10000000>; ranges = <0x2000000 0x0 0x50000000 0x0 0x50000000 0x0 0x10000000>;
interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,

View File

@ -87,7 +87,7 @@
1 << PMSCR_EL2_PA_SHIFT) 1 << PMSCR_EL2_PA_SHIFT)
msr_s SYS_PMSCR_EL2, x0 // addresses and physical counter msr_s SYS_PMSCR_EL2, x0 // addresses and physical counter
.Lskip_spe_el2_\@: .Lskip_spe_el2_\@:
mov x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT) mov x0, #MDCR_EL2_E2PB_MASK
orr x2, x2, x0 // If we don't have VHE, then orr x2, x2, x0 // If we don't have VHE, then
// use EL1&0 translation. // use EL1&0 translation.
@ -100,7 +100,7 @@
and x0, x0, TRBIDR_EL1_P and x0, x0, TRBIDR_EL1_P
cbnz x0, .Lskip_trace_\@ // If TRBE is available at EL2 cbnz x0, .Lskip_trace_\@ // If TRBE is available at EL2
mov x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT) mov x0, #MDCR_EL2_E2TB_MASK
orr x2, x2, x0 // allow the EL1&0 translation orr x2, x2, x0 // allow the EL1&0 translation
// to own it. // to own it.

View File

@ -114,8 +114,8 @@ SYM_CODE_START_LOCAL(__finalise_el2)
// Use EL2 translations for SPE & TRBE and disable access from EL1 // Use EL2 translations for SPE & TRBE and disable access from EL1
mrs x0, mdcr_el2 mrs x0, mdcr_el2
bic x0, x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT) bic x0, x0, #MDCR_EL2_E2PB_MASK
bic x0, x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT) bic x0, x0, #MDCR_EL2_E2TB_MASK
msr mdcr_el2, x0 msr mdcr_el2, x0
// Transfer the MM state from EL1 to EL2 // Transfer the MM state from EL1 to EL2

View File

@ -1462,10 +1462,33 @@ static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
struct rt_sigframe_user_layout *user, int usig) struct rt_sigframe_user_layout *user, int usig)
{ {
__sigrestore_t sigtramp; __sigrestore_t sigtramp;
int err;
if (ksig->ka.sa.sa_flags & SA_RESTORER)
sigtramp = ksig->ka.sa.sa_restorer;
else
sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
err = gcs_signal_entry(sigtramp, ksig);
if (err)
return err;
/*
* We must not fail from this point onwards. We are going to update
* registers, including SP, in order to invoke the signal handler. If
* we failed and attempted to deliver a nested SIGSEGV to a handler
* after that point, the subsequent sigreturn would end up restoring
* the (partial) state for the original signal handler.
*/
regs->regs[0] = usig; regs->regs[0] = usig;
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
regs->regs[1] = (unsigned long)&user->sigframe->info;
regs->regs[2] = (unsigned long)&user->sigframe->uc;
}
regs->sp = (unsigned long)user->sigframe; regs->sp = (unsigned long)user->sigframe;
regs->regs[29] = (unsigned long)&user->next_frame->fp; regs->regs[29] = (unsigned long)&user->next_frame->fp;
regs->regs[30] = (unsigned long)sigtramp;
regs->pc = (unsigned long)ksig->ka.sa.sa_handler; regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
/* /*
@ -1506,14 +1529,7 @@ static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
sme_smstop(); sme_smstop();
} }
if (ksig->ka.sa.sa_flags & SA_RESTORER) return 0;
sigtramp = ksig->ka.sa.sa_restorer;
else
sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
regs->regs[30] = (unsigned long)sigtramp;
return gcs_signal_entry(sigtramp, ksig);
} }
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
@ -1537,14 +1553,16 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
err |= __save_altstack(&frame->uc.uc_stack, regs->sp); err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigframe(&user, regs, set, &ua_state); err |= setup_sigframe(&user, regs, set, &ua_state);
if (err == 0) { if (ksig->ka.sa.sa_flags & SA_SIGINFO)
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
if (err == 0)
err = setup_return(regs, ksig, &user, usig); err = setup_return(regs, ksig, &user, usig);
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
err |= copy_siginfo_to_user(&frame->info, &ksig->info); /*
regs->regs[1] = (unsigned long)&frame->info; * We must not fail if setup_return() succeeded - see comment at the
regs->regs[2] = (unsigned long)&frame->uc; * beginning of setup_return().
} */
}
if (err == 0) if (err == 0)
set_handler_user_access_state(); set_handler_user_access_state();

View File

@ -26,7 +26,6 @@ enum kunwind_source {
KUNWIND_SOURCE_CALLER, KUNWIND_SOURCE_CALLER,
KUNWIND_SOURCE_TASK, KUNWIND_SOURCE_TASK,
KUNWIND_SOURCE_REGS_PC, KUNWIND_SOURCE_REGS_PC,
KUNWIND_SOURCE_REGS_LR,
}; };
union unwind_flags { union unwind_flags {
@ -138,8 +137,10 @@ kunwind_recover_return_address(struct kunwind_state *state)
orig_pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, orig_pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
state->common.pc, state->common.pc,
(void *)state->common.fp); (void *)state->common.fp);
if (WARN_ON_ONCE(state->common.pc == orig_pc)) if (state->common.pc == orig_pc) {
WARN_ON_ONCE(state->task == current);
return -EINVAL; return -EINVAL;
}
state->common.pc = orig_pc; state->common.pc = orig_pc;
state->flags.fgraph = 1; state->flags.fgraph = 1;
} }
@ -178,23 +179,8 @@ int kunwind_next_regs_pc(struct kunwind_state *state)
state->regs = regs; state->regs = regs;
state->common.pc = regs->pc; state->common.pc = regs->pc;
state->common.fp = regs->regs[29]; state->common.fp = regs->regs[29];
state->source = KUNWIND_SOURCE_REGS_PC;
return 0;
}
static __always_inline int
kunwind_next_regs_lr(struct kunwind_state *state)
{
/*
* The stack for the regs was consumed by kunwind_next_regs_pc(), so we
* cannot consume that again here, but we know the regs are safe to
* access.
*/
state->common.pc = state->regs->regs[30];
state->common.fp = state->regs->regs[29];
state->regs = NULL; state->regs = NULL;
state->source = KUNWIND_SOURCE_REGS_LR; state->source = KUNWIND_SOURCE_REGS_PC;
return 0; return 0;
} }
@ -215,12 +201,12 @@ kunwind_next_frame_record_meta(struct kunwind_state *state)
case FRAME_META_TYPE_FINAL: case FRAME_META_TYPE_FINAL:
if (meta == &task_pt_regs(tsk)->stackframe) if (meta == &task_pt_regs(tsk)->stackframe)
return -ENOENT; return -ENOENT;
WARN_ON_ONCE(1); WARN_ON_ONCE(tsk == current);
return -EINVAL; return -EINVAL;
case FRAME_META_TYPE_PT_REGS: case FRAME_META_TYPE_PT_REGS:
return kunwind_next_regs_pc(state); return kunwind_next_regs_pc(state);
default: default:
WARN_ON_ONCE(1); WARN_ON_ONCE(tsk == current);
return -EINVAL; return -EINVAL;
} }
} }
@ -274,11 +260,8 @@ kunwind_next(struct kunwind_state *state)
case KUNWIND_SOURCE_FRAME: case KUNWIND_SOURCE_FRAME:
case KUNWIND_SOURCE_CALLER: case KUNWIND_SOURCE_CALLER:
case KUNWIND_SOURCE_TASK: case KUNWIND_SOURCE_TASK:
case KUNWIND_SOURCE_REGS_LR:
err = kunwind_next_frame_record(state);
break;
case KUNWIND_SOURCE_REGS_PC: case KUNWIND_SOURCE_REGS_PC:
err = kunwind_next_regs_lr(state); err = kunwind_next_frame_record(state);
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
@ -436,7 +419,6 @@ static const char *state_source_string(const struct kunwind_state *state)
case KUNWIND_SOURCE_CALLER: return "C"; case KUNWIND_SOURCE_CALLER: return "C";
case KUNWIND_SOURCE_TASK: return "T"; case KUNWIND_SOURCE_TASK: return "T";
case KUNWIND_SOURCE_REGS_PC: return "P"; case KUNWIND_SOURCE_REGS_PC: return "P";
case KUNWIND_SOURCE_REGS_LR: return "L";
default: return "U"; default: return "U";
} }
} }

View File

@ -739,8 +739,15 @@ static u64 compute_par_s12(struct kvm_vcpu *vcpu, u64 s1_par,
final_attr = s1_parattr; final_attr = s1_parattr;
break; break;
default: default:
/* MemAttr[2]=0, Device from S2 */ /*
final_attr = s2_memattr & GENMASK(1,0) << 2; * MemAttr[2]=0, Device from S2.
*
* FWB does not influence the way that stage 1
* memory types and attributes are combined
* with stage 2 Device type and attributes.
*/
final_attr = min(s2_memattr_to_attr(s2_memattr),
s1_parattr);
} }
} else { } else {
/* Combination of R_HMNDG, R_TNHFM and R_GQFSF */ /* Combination of R_HMNDG, R_TNHFM and R_GQFSF */

View File

@ -126,7 +126,7 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
/* Trap SPE */ /* Trap SPE */
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer), feature_ids)) { if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer), feature_ids)) {
mdcr_set |= MDCR_EL2_TPMS; mdcr_set |= MDCR_EL2_TPMS;
mdcr_clear |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT; mdcr_clear |= MDCR_EL2_E2PB_MASK;
} }
/* Trap Trace Filter */ /* Trap Trace Filter */
@ -143,7 +143,7 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
/* Trap External Trace */ /* Trap External Trace */
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids)) if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids))
mdcr_clear |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT; mdcr_clear |= MDCR_EL2_E2TB_MASK;
vcpu->arch.mdcr_el2 |= mdcr_set; vcpu->arch.mdcr_el2 |= mdcr_set;
vcpu->arch.mdcr_el2 &= ~mdcr_clear; vcpu->arch.mdcr_el2 &= ~mdcr_clear;

View File

@ -2618,7 +2618,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
ID_WRITABLE(ID_AA64MMFR0_EL1, ~(ID_AA64MMFR0_EL1_RES0 | ID_WRITABLE(ID_AA64MMFR0_EL1, ~(ID_AA64MMFR0_EL1_RES0 |
ID_AA64MMFR0_EL1_TGRAN4_2 | ID_AA64MMFR0_EL1_TGRAN4_2 |
ID_AA64MMFR0_EL1_TGRAN64_2 | ID_AA64MMFR0_EL1_TGRAN64_2 |
ID_AA64MMFR0_EL1_TGRAN16_2)), ID_AA64MMFR0_EL1_TGRAN16_2 |
ID_AA64MMFR0_EL1_ASIDBITS)),
ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 | ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 |
ID_AA64MMFR1_EL1_HCX | ID_AA64MMFR1_EL1_HCX |
ID_AA64MMFR1_EL1_TWED | ID_AA64MMFR1_EL1_TWED |

View File

@ -608,12 +608,22 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
lockdep_assert_held(&its->its_lock); lockdep_assert_held(&its->its_lock);
vgic_get_irq_kref(irq); vgic_get_irq_kref(irq);
old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT);
/*
* Put the reference taken on @irq if the store fails. Intentionally do
* not return the error as the translation cache is best effort.
*/
if (xa_is_err(old)) {
vgic_put_irq(kvm, irq);
return;
}
/* /*
* We could have raced with another CPU caching the same * We could have raced with another CPU caching the same
* translation behind our back, ensure we don't leak a * translation behind our back, ensure we don't leak a
* reference if that is the case. * reference if that is the case.
*/ */
old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT);
if (old) if (old)
vgic_put_irq(kvm, old); vgic_put_irq(kvm, old);
} }

View File

@ -32,3 +32,9 @@ KBUILD_LDFLAGS += $(ldflags-y)
TIR_NAME := r19 TIR_NAME := r19
KBUILD_CFLAGS += -ffixed-$(TIR_NAME) -DTHREADINFO_REG=$(TIR_NAME) -D__linux__ KBUILD_CFLAGS += -ffixed-$(TIR_NAME) -DTHREADINFO_REG=$(TIR_NAME) -D__linux__
KBUILD_AFLAGS += -DTHREADINFO_REG=$(TIR_NAME) KBUILD_AFLAGS += -DTHREADINFO_REG=$(TIR_NAME)
# Disable HexagonConstExtenders pass for LLVM versions prior to 19.1.0
# https://github.com/llvm/llvm-project/issues/99714
ifneq ($(call clang-min-version, 190100),y)
KBUILD_CFLAGS += -mllvm -hexagon-cext=false
endif

View File

@ -239,6 +239,8 @@ handler: ;\
/* =====================================================[ exceptions] === */ /* =====================================================[ exceptions] === */
__REF
/* ---[ 0x100: RESET exception ]----------------------------------------- */ /* ---[ 0x100: RESET exception ]----------------------------------------- */
EXCEPTION_ENTRY(_tng_kernel_start) EXCEPTION_ENTRY(_tng_kernel_start)

View File

@ -26,15 +26,15 @@
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#define tophys(rd,rs) \ #define tophys(rd,rs) \
l.movhi rd,hi(-KERNELBASE) ;\ l.movhi rd,hi(-KERNELBASE) ;\
l.add rd,rd,rs l.add rd,rd,rs
#define CLEAR_GPR(gpr) \ #define CLEAR_GPR(gpr) \
l.movhi gpr,0x0 l.movhi gpr,0x0
#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ #define LOAD_SYMBOL_2_GPR(gpr,symbol) \
l.movhi gpr,hi(symbol) ;\ l.movhi gpr,hi(symbol) ;\
l.ori gpr,gpr,lo(symbol) l.ori gpr,gpr,lo(symbol)
@ -326,21 +326,21 @@
l.addi r1,r1,-(INT_FRAME_SIZE) ;\ l.addi r1,r1,-(INT_FRAME_SIZE) ;\
/* r1 is KSP, r30 is __pa(KSP) */ ;\ /* r1 is KSP, r30 is __pa(KSP) */ ;\
tophys (r30,r1) ;\ tophys (r30,r1) ;\
l.sw PT_GPR12(r30),r12 ;\ l.sw PT_GPR12(r30),r12 ;\
l.mfspr r12,r0,SPR_EPCR_BASE ;\ l.mfspr r12,r0,SPR_EPCR_BASE ;\
l.sw PT_PC(r30),r12 ;\ l.sw PT_PC(r30),r12 ;\
l.mfspr r12,r0,SPR_ESR_BASE ;\ l.mfspr r12,r0,SPR_ESR_BASE ;\
l.sw PT_SR(r30),r12 ;\ l.sw PT_SR(r30),r12 ;\
/* save r31 */ ;\ /* save r31 */ ;\
EXCEPTION_T_LOAD_GPR30(r12) ;\ EXCEPTION_T_LOAD_GPR30(r12) ;\
l.sw PT_GPR30(r30),r12 ;\ l.sw PT_GPR30(r30),r12 ;\
/* save r10 as was prior to exception */ ;\ /* save r10 as was prior to exception */ ;\
EXCEPTION_T_LOAD_GPR10(r12) ;\ EXCEPTION_T_LOAD_GPR10(r12) ;\
l.sw PT_GPR10(r30),r12 ;\ l.sw PT_GPR10(r30),r12 ;\
/* save PT_SP as was prior to exception */ ;\ /* save PT_SP as was prior to exception */ ;\
EXCEPTION_T_LOAD_SP(r12) ;\ EXCEPTION_T_LOAD_SP(r12) ;\
l.sw PT_SP(r30),r12 ;\ l.sw PT_SP(r30),r12 ;\
l.sw PT_GPR13(r30),r13 ;\ l.sw PT_GPR13(r30),r13 ;\
/* --> */ ;\ /* --> */ ;\
/* save exception r4, set r4 = EA */ ;\ /* save exception r4, set r4 = EA */ ;\
l.sw PT_GPR4(r30),r4 ;\ l.sw PT_GPR4(r30),r4 ;\
@ -357,6 +357,8 @@
/* =====================================================[ exceptions] === */ /* =====================================================[ exceptions] === */
__HEAD
/* ---[ 0x100: RESET exception ]----------------------------------------- */ /* ---[ 0x100: RESET exception ]----------------------------------------- */
.org 0x100 .org 0x100
/* Jump to .init code at _start which lives in the .head section /* Jump to .init code at _start which lives in the .head section
@ -394,7 +396,7 @@ _dispatch_do_ipage_fault:
.org 0x500 .org 0x500
EXCEPTION_HANDLE(_timer_handler) EXCEPTION_HANDLE(_timer_handler)
/* ---[ 0x600: Alignment exception ]-------------------------------------- */ /* ---[ 0x600: Alignment exception ]------------------------------------- */
.org 0x600 .org 0x600
EXCEPTION_HANDLE(_alignment_handler) EXCEPTION_HANDLE(_alignment_handler)
@ -424,7 +426,7 @@ _dispatch_do_ipage_fault:
.org 0xc00 .org 0xc00
EXCEPTION_HANDLE(_sys_call_handler) EXCEPTION_HANDLE(_sys_call_handler)
/* ---[ 0xd00: Floating point exception ]--------------------------------- */ /* ---[ 0xd00: Floating point exception ]-------------------------------- */
.org 0xd00 .org 0xd00
EXCEPTION_HANDLE(_fpe_trap_handler) EXCEPTION_HANDLE(_fpe_trap_handler)
@ -506,10 +508,10 @@ _dispatch_do_ipage_fault:
/* .text*/ /* .text*/
/* This early stuff belongs in HEAD, but some of the functions below definitely /* This early stuff belongs in the .init.text section, but some of the functions below definitely
* don't... */ * don't... */
__HEAD __INIT
.global _start .global _start
_start: _start:
/* Init r0 to zero as per spec */ /* Init r0 to zero as per spec */
@ -816,7 +818,7 @@ secondary_start:
#endif #endif
/* ========================================[ cache ]=== */ /* ==========================================================[ cache ]=== */
/* alignment here so we don't change memory offsets with /* alignment here so we don't change memory offsets with
* memory controller defined * memory controller defined

View File

@ -50,6 +50,7 @@ SECTIONS
.text : AT(ADDR(.text) - LOAD_OFFSET) .text : AT(ADDR(.text) - LOAD_OFFSET)
{ {
_stext = .; _stext = .;
HEAD_TEXT
TEXT_TEXT TEXT_TEXT
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
@ -83,8 +84,6 @@ SECTIONS
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
__init_begin = .; __init_begin = .;
HEAD_TEXT_SECTION
/* Page aligned */ /* Page aligned */
INIT_TEXT_SECTION(PAGE_SIZE) INIT_TEXT_SECTION(PAGE_SIZE)

View File

@ -22,7 +22,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect)
else else
set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT)); set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT));
flush_tlb_kernel_range(addr, addr + PAGE_SIZE); preempt_disable();
local_flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
preempt_enable();
return true; return true;
} }

View File

@ -36,9 +36,15 @@ bool arch_jump_label_transform_queue(struct jump_entry *entry,
insn = RISCV_INSN_NOP; insn = RISCV_INSN_NOP;
} }
mutex_lock(&text_mutex); if (early_boot_irqs_disabled) {
patch_insn_write(addr, &insn, sizeof(insn)); riscv_patch_in_stop_machine = 1;
mutex_unlock(&text_mutex); patch_insn_write(addr, &insn, sizeof(insn));
riscv_patch_in_stop_machine = 0;
} else {
mutex_lock(&text_mutex);
patch_insn_write(addr, &insn, sizeof(insn));
mutex_unlock(&text_mutex);
}
return true; return true;
} }

View File

@ -227,7 +227,7 @@ static void __init init_resources(void)
static void __init parse_dtb(void) static void __init parse_dtb(void)
{ {
/* Early scan of device tree from init memory */ /* Early scan of device tree from init memory */
if (early_init_dt_scan(dtb_early_va, __pa(dtb_early_va))) { if (early_init_dt_scan(dtb_early_va, dtb_early_pa)) {
const char *name = of_flat_dt_get_machine_name(); const char *name = of_flat_dt_get_machine_name();
if (name) { if (name) {

View File

@ -590,7 +590,7 @@ void kvm_riscv_aia_enable(void)
csr_set(CSR_HIE, BIT(IRQ_S_GEXT)); csr_set(CSR_HIE, BIT(IRQ_S_GEXT));
/* Enable IRQ filtering for overflow interrupt only if sscofpmf is present */ /* Enable IRQ filtering for overflow interrupt only if sscofpmf is present */
if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSCOFPMF)) if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSCOFPMF))
csr_write(CSR_HVIEN, BIT(IRQ_PMU_OVF)); csr_set(CSR_HVIEN, BIT(IRQ_PMU_OVF));
} }
void kvm_riscv_aia_disable(void) void kvm_riscv_aia_disable(void)

View File

@ -1566,7 +1566,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
pmd_clear(pmd); pmd_clear(pmd);
} }
static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemmap)
{ {
struct page *page = pud_page(*pud); struct page *page = pud_page(*pud);
struct ptdesc *ptdesc = page_ptdesc(page); struct ptdesc *ptdesc = page_ptdesc(page);
@ -1579,7 +1579,8 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
return; return;
} }
pagetable_pmd_dtor(ptdesc); if (!is_vmemmap)
pagetable_pmd_dtor(ptdesc);
if (PageReserved(page)) if (PageReserved(page))
free_reserved_page(page); free_reserved_page(page);
else else
@ -1703,7 +1704,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un
remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap); remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap);
if (pgtable_l4_enabled) if (pgtable_l4_enabled)
free_pmd_table(pmd_base, pudp); free_pmd_table(pmd_base, pudp, is_vmemmap);
} }
} }

View File

@ -234,6 +234,8 @@ static unsigned long get_vmem_size(unsigned long identity_size,
vsize = round_up(SZ_2G + max_mappable, rte_size) + vsize = round_up(SZ_2G + max_mappable, rte_size) +
round_up(vmemmap_size, rte_size) + round_up(vmemmap_size, rte_size) +
FIXMAP_SIZE + MODULES_LEN + KASLR_LEN; FIXMAP_SIZE + MODULES_LEN + KASLR_LEN;
if (IS_ENABLED(CONFIG_KMSAN))
vsize += MODULES_LEN * 2;
return size_add(vsize, vmalloc_size); return size_add(vsize, vmalloc_size);
} }

View File

@ -306,7 +306,7 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e
pages++; pages++;
} }
} }
if (mode == POPULATE_DIRECT) if (mode == POPULATE_IDENTITY)
update_page_count(PG_DIRECT_MAP_4K, pages); update_page_count(PG_DIRECT_MAP_4K, pages);
} }
@ -339,7 +339,7 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e
} }
pgtable_pte_populate(pmd, addr, next, mode); pgtable_pte_populate(pmd, addr, next, mode);
} }
if (mode == POPULATE_DIRECT) if (mode == POPULATE_IDENTITY)
update_page_count(PG_DIRECT_MAP_1M, pages); update_page_count(PG_DIRECT_MAP_1M, pages);
} }
@ -372,7 +372,7 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e
} }
pgtable_pmd_populate(pud, addr, next, mode); pgtable_pmd_populate(pud, addr, next, mode);
} }
if (mode == POPULATE_DIRECT) if (mode == POPULATE_IDENTITY)
update_page_count(PG_DIRECT_MAP_2G, pages); update_page_count(PG_DIRECT_MAP_2G, pages);
} }

View File

@ -270,7 +270,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
if (len >= sizeof(_value)) \ if (len >= sizeof(_value)) \
return -E2BIG; \ return -E2BIG; \
len = strscpy(_value, buf, sizeof(_value)); \ len = strscpy(_value, buf, sizeof(_value)); \
if (len < 0) \ if ((ssize_t)len < 0) \
return len; \ return len; \
strim(_value); \ strim(_value); \
return len; \ return len; \

View File

@ -230,6 +230,8 @@ static inline unsigned long long l1tf_pfn_limit(void)
return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT); return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT);
} }
void init_cpu_devs(void);
void get_cpu_vendor(struct cpuinfo_x86 *c);
extern void early_cpu_init(void); extern void early_cpu_init(void);
extern void identify_secondary_cpu(struct cpuinfo_x86 *); extern void identify_secondary_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *);

View File

@ -65,4 +65,19 @@
extern bool __static_call_fixup(void *tramp, u8 op, void *dest); extern bool __static_call_fixup(void *tramp, u8 op, void *dest);
extern void __static_call_update_early(void *tramp, void *func);
#define static_call_update_early(name, _func) \
({ \
typeof(&STATIC_CALL_TRAMP(name)) __F = (_func); \
if (static_call_initialized) { \
__static_call_update(&STATIC_CALL_KEY(name), \
STATIC_CALL_TRAMP_ADDR(name), __F);\
} else { \
WRITE_ONCE(STATIC_CALL_KEY(name).func, _func); \
__static_call_update_early(STATIC_CALL_TRAMP_ADDR(name),\
__F); \
} \
})
#endif /* _ASM_STATIC_CALL_H */ #endif /* _ASM_STATIC_CALL_H */

View File

@ -8,7 +8,7 @@
#include <asm/special_insns.h> #include <asm/special_insns.h>
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
static inline void iret_to_self(void) static __always_inline void iret_to_self(void)
{ {
asm volatile ( asm volatile (
"pushfl\n\t" "pushfl\n\t"
@ -19,7 +19,7 @@ static inline void iret_to_self(void)
: ASM_CALL_CONSTRAINT : : "memory"); : ASM_CALL_CONSTRAINT : : "memory");
} }
#else #else
static inline void iret_to_self(void) static __always_inline void iret_to_self(void)
{ {
unsigned int tmp; unsigned int tmp;
@ -55,7 +55,7 @@ static inline void iret_to_self(void)
* Like all of Linux's memory ordering operations, this is a * Like all of Linux's memory ordering operations, this is a
* compiler barrier as well. * compiler barrier as well.
*/ */
static inline void sync_core(void) static __always_inline void sync_core(void)
{ {
/* /*
* The SERIALIZE instruction is the most straightforward way to * The SERIALIZE instruction is the most straightforward way to

View File

@ -39,9 +39,11 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pgtable.h> #include <linux/pgtable.h>
#include <linux/instrumentation.h>
#include <trace/events/xen.h> #include <trace/events/xen.h>
#include <asm/alternative.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/smap.h> #include <asm/smap.h>
#include <asm/nospec-branch.h> #include <asm/nospec-branch.h>
@ -86,11 +88,20 @@ struct xen_dm_op_buf;
* there aren't more than 5 arguments...) * there aren't more than 5 arguments...)
*/ */
extern struct { char _entry[32]; } hypercall_page[]; void xen_hypercall_func(void);
DECLARE_STATIC_CALL(xen_hypercall, xen_hypercall_func);
#define __HYPERCALL "call hypercall_page+%c[offset]" #ifdef MODULE
#define __HYPERCALL_ENTRY(x) \ #define __ADDRESSABLE_xen_hypercall
[offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0])) #else
#define __ADDRESSABLE_xen_hypercall __ADDRESSABLE_ASM_STR(__SCK__xen_hypercall)
#endif
#define __HYPERCALL \
__ADDRESSABLE_xen_hypercall \
"call __SCT__xen_hypercall"
#define __HYPERCALL_ENTRY(x) "a" (x)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define __HYPERCALL_RETREG "eax" #define __HYPERCALL_RETREG "eax"
@ -148,7 +159,7 @@ extern struct { char _entry[32]; } hypercall_page[];
__HYPERCALL_0ARG(); \ __HYPERCALL_0ARG(); \
asm volatile (__HYPERCALL \ asm volatile (__HYPERCALL \
: __HYPERCALL_0PARAM \ : __HYPERCALL_0PARAM \
: __HYPERCALL_ENTRY(name) \ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
: __HYPERCALL_CLOBBER0); \ : __HYPERCALL_CLOBBER0); \
(type)__res; \ (type)__res; \
}) })
@ -159,7 +170,7 @@ extern struct { char _entry[32]; } hypercall_page[];
__HYPERCALL_1ARG(a1); \ __HYPERCALL_1ARG(a1); \
asm volatile (__HYPERCALL \ asm volatile (__HYPERCALL \
: __HYPERCALL_1PARAM \ : __HYPERCALL_1PARAM \
: __HYPERCALL_ENTRY(name) \ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
: __HYPERCALL_CLOBBER1); \ : __HYPERCALL_CLOBBER1); \
(type)__res; \ (type)__res; \
}) })
@ -170,7 +181,7 @@ extern struct { char _entry[32]; } hypercall_page[];
__HYPERCALL_2ARG(a1, a2); \ __HYPERCALL_2ARG(a1, a2); \
asm volatile (__HYPERCALL \ asm volatile (__HYPERCALL \
: __HYPERCALL_2PARAM \ : __HYPERCALL_2PARAM \
: __HYPERCALL_ENTRY(name) \ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
: __HYPERCALL_CLOBBER2); \ : __HYPERCALL_CLOBBER2); \
(type)__res; \ (type)__res; \
}) })
@ -181,7 +192,7 @@ extern struct { char _entry[32]; } hypercall_page[];
__HYPERCALL_3ARG(a1, a2, a3); \ __HYPERCALL_3ARG(a1, a2, a3); \
asm volatile (__HYPERCALL \ asm volatile (__HYPERCALL \
: __HYPERCALL_3PARAM \ : __HYPERCALL_3PARAM \
: __HYPERCALL_ENTRY(name) \ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
: __HYPERCALL_CLOBBER3); \ : __HYPERCALL_CLOBBER3); \
(type)__res; \ (type)__res; \
}) })
@ -192,7 +203,7 @@ extern struct { char _entry[32]; } hypercall_page[];
__HYPERCALL_4ARG(a1, a2, a3, a4); \ __HYPERCALL_4ARG(a1, a2, a3, a4); \
asm volatile (__HYPERCALL \ asm volatile (__HYPERCALL \
: __HYPERCALL_4PARAM \ : __HYPERCALL_4PARAM \
: __HYPERCALL_ENTRY(name) \ : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
: __HYPERCALL_CLOBBER4); \ : __HYPERCALL_CLOBBER4); \
(type)__res; \ (type)__res; \
}) })
@ -206,12 +217,9 @@ xen_single_call(unsigned int call,
__HYPERCALL_DECLS; __HYPERCALL_DECLS;
__HYPERCALL_5ARG(a1, a2, a3, a4, a5); __HYPERCALL_5ARG(a1, a2, a3, a4, a5);
if (call >= PAGE_SIZE / sizeof(hypercall_page[0])) asm volatile(__HYPERCALL
return -EINVAL;
asm volatile(CALL_NOSPEC
: __HYPERCALL_5PARAM : __HYPERCALL_5PARAM
: [thunk_target] "a" (&hypercall_page[call]) : __HYPERCALL_ENTRY(call)
: __HYPERCALL_CLOBBER5); : __HYPERCALL_CLOBBER5);
return (long)__res; return (long)__res;

View File

@ -142,11 +142,6 @@ static bool skip_addr(void *dest)
if (dest >= (void *)relocate_kernel && if (dest >= (void *)relocate_kernel &&
dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE) dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE)
return true; return true;
#endif
#ifdef CONFIG_XEN
if (dest >= (void *)hypercall_page &&
dest < (void*)hypercall_page + PAGE_SIZE)
return true;
#endif #endif
return false; return false;
} }

View File

@ -867,7 +867,7 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c)
tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]);
} }
static void get_cpu_vendor(struct cpuinfo_x86 *c) void get_cpu_vendor(struct cpuinfo_x86 *c)
{ {
char *v = c->x86_vendor_id; char *v = c->x86_vendor_id;
int i; int i;
@ -1649,15 +1649,11 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
detect_nopl(); detect_nopl();
} }
void __init early_cpu_init(void) void __init init_cpu_devs(void)
{ {
const struct cpu_dev *const *cdev; const struct cpu_dev *const *cdev;
int count = 0; int count = 0;
#ifdef CONFIG_PROCESSOR_SELECT
pr_info("KERNEL supported cpus:\n");
#endif
for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) { for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
const struct cpu_dev *cpudev = *cdev; const struct cpu_dev *cpudev = *cdev;
@ -1665,20 +1661,30 @@ void __init early_cpu_init(void)
break; break;
cpu_devs[count] = cpudev; cpu_devs[count] = cpudev;
count++; count++;
}
}
void __init early_cpu_init(void)
{
#ifdef CONFIG_PROCESSOR_SELECT
unsigned int i, j;
pr_info("KERNEL supported cpus:\n");
#endif
init_cpu_devs();
#ifdef CONFIG_PROCESSOR_SELECT #ifdef CONFIG_PROCESSOR_SELECT
{ for (i = 0; i < X86_VENDOR_NUM && cpu_devs[i]; i++) {
unsigned int j; for (j = 0; j < 2; j++) {
if (!cpu_devs[i]->c_ident[j])
for (j = 0; j < 2; j++) { continue;
if (!cpudev->c_ident[j]) pr_info(" %s %s\n", cpu_devs[i]->c_vendor,
continue; cpu_devs[i]->c_ident[j]);
pr_info(" %s %s\n", cpudev->c_vendor,
cpudev->c_ident[j]);
}
} }
#endif
} }
#endif
early_identify_cpu(&boot_cpu_data); early_identify_cpu(&boot_cpu_data);
} }

View File

@ -223,6 +223,63 @@ static void hv_machine_crash_shutdown(struct pt_regs *regs)
hyperv_cleanup(); hyperv_cleanup();
} }
#endif /* CONFIG_CRASH_DUMP */ #endif /* CONFIG_CRASH_DUMP */
static u64 hv_ref_counter_at_suspend;
static void (*old_save_sched_clock_state)(void);
static void (*old_restore_sched_clock_state)(void);
/*
* Hyper-V clock counter resets during hibernation. Save and restore clock
* offset during suspend/resume, while also considering the time passed
* before suspend. This is to make sure that sched_clock using hv tsc page
* based clocksource, proceeds from where it left off during suspend and
* it shows correct time for the timestamps of kernel messages after resume.
*/
static void save_hv_clock_tsc_state(void)
{
hv_ref_counter_at_suspend = hv_read_reference_counter();
}
static void restore_hv_clock_tsc_state(void)
{
/*
* Adjust the offsets used by hv tsc clocksource to
* account for the time spent before hibernation.
* adjusted value = reference counter (time) at suspend
* - reference counter (time) now.
*/
hv_adj_sched_clock_offset(hv_ref_counter_at_suspend - hv_read_reference_counter());
}
/*
* Functions to override save_sched_clock_state and restore_sched_clock_state
* functions of x86_platform. The Hyper-V clock counter is reset during
* suspend-resume and the offset used to measure time needs to be
* corrected, post resume.
*/
static void hv_save_sched_clock_state(void)
{
old_save_sched_clock_state();
save_hv_clock_tsc_state();
}
static void hv_restore_sched_clock_state(void)
{
restore_hv_clock_tsc_state();
old_restore_sched_clock_state();
}
static void __init x86_setup_ops_for_tsc_pg_clock(void)
{
if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
return;
old_save_sched_clock_state = x86_platform.save_sched_clock_state;
x86_platform.save_sched_clock_state = hv_save_sched_clock_state;
old_restore_sched_clock_state = x86_platform.restore_sched_clock_state;
x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state;
}
#endif /* CONFIG_HYPERV */ #endif /* CONFIG_HYPERV */
static uint32_t __init ms_hyperv_platform(void) static uint32_t __init ms_hyperv_platform(void)
@ -579,6 +636,7 @@ static void __init ms_hyperv_init_platform(void)
/* Register Hyper-V specific clocksource */ /* Register Hyper-V specific clocksource */
hv_init_clocksource(); hv_init_clocksource();
x86_setup_ops_for_tsc_pg_clock();
hv_vtl_init_platform(); hv_vtl_init_platform();
#endif #endif
/* /*

View File

@ -172,6 +172,15 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
} }
EXPORT_SYMBOL_GPL(arch_static_call_transform); EXPORT_SYMBOL_GPL(arch_static_call_transform);
noinstr void __static_call_update_early(void *tramp, void *func)
{
BUG_ON(system_state != SYSTEM_BOOTING);
BUG_ON(!early_boot_irqs_disabled);
BUG_ON(static_call_initialized);
__text_gen_insn(tramp, JMP32_INSN_OPCODE, tramp, func, JMP32_INSN_SIZE);
sync_core();
}
#ifdef CONFIG_MITIGATION_RETHUNK #ifdef CONFIG_MITIGATION_RETHUNK
/* /*
* This is called by apply_returns() to fix up static call trampolines, * This is called by apply_returns() to fix up static call trampolines,

View File

@ -519,14 +519,10 @@ INIT_PER_CPU(irq_stack_backing_store);
* linker will never mark as relocatable. (Using just ABSOLUTE() is not * linker will never mark as relocatable. (Using just ABSOLUTE() is not
* sufficient for that). * sufficient for that).
*/ */
#ifdef CONFIG_XEN
#ifdef CONFIG_XEN_PV #ifdef CONFIG_XEN_PV
xen_elfnote_entry_value = xen_elfnote_entry_value =
ABSOLUTE(xen_elfnote_entry) + ABSOLUTE(startup_xen); ABSOLUTE(xen_elfnote_entry) + ABSOLUTE(startup_xen);
#endif #endif
xen_elfnote_hypercall_page_value =
ABSOLUTE(xen_elfnote_hypercall_page) + ABSOLUTE(hypercall_page);
#endif
#ifdef CONFIG_PVH #ifdef CONFIG_PVH
xen_elfnote_phys32_entry_value = xen_elfnote_phys32_entry_value =
ABSOLUTE(xen_elfnote_phys32_entry) + ABSOLUTE(pvh_start_xen - LOAD_OFFSET); ABSOLUTE(xen_elfnote_phys32_entry) + ABSOLUTE(pvh_start_xen - LOAD_OFFSET);

View File

@ -36,6 +36,26 @@
u32 kvm_cpu_caps[NR_KVM_CPU_CAPS] __read_mostly; u32 kvm_cpu_caps[NR_KVM_CPU_CAPS] __read_mostly;
EXPORT_SYMBOL_GPL(kvm_cpu_caps); EXPORT_SYMBOL_GPL(kvm_cpu_caps);
struct cpuid_xstate_sizes {
u32 eax;
u32 ebx;
u32 ecx;
};
static struct cpuid_xstate_sizes xstate_sizes[XFEATURE_MAX] __ro_after_init;
void __init kvm_init_xstate_sizes(void)
{
u32 ign;
int i;
for (i = XFEATURE_YMM; i < ARRAY_SIZE(xstate_sizes); i++) {
struct cpuid_xstate_sizes *xs = &xstate_sizes[i];
cpuid_count(0xD, i, &xs->eax, &xs->ebx, &xs->ecx, &ign);
}
}
u32 xstate_required_size(u64 xstate_bv, bool compacted) u32 xstate_required_size(u64 xstate_bv, bool compacted)
{ {
int feature_bit = 0; int feature_bit = 0;
@ -44,14 +64,15 @@ u32 xstate_required_size(u64 xstate_bv, bool compacted)
xstate_bv &= XFEATURE_MASK_EXTEND; xstate_bv &= XFEATURE_MASK_EXTEND;
while (xstate_bv) { while (xstate_bv) {
if (xstate_bv & 0x1) { if (xstate_bv & 0x1) {
u32 eax, ebx, ecx, edx, offset; struct cpuid_xstate_sizes *xs = &xstate_sizes[feature_bit];
cpuid_count(0xD, feature_bit, &eax, &ebx, &ecx, &edx); u32 offset;
/* ECX[1]: 64B alignment in compacted form */ /* ECX[1]: 64B alignment in compacted form */
if (compacted) if (compacted)
offset = (ecx & 0x2) ? ALIGN(ret, 64) : ret; offset = (xs->ecx & 0x2) ? ALIGN(ret, 64) : ret;
else else
offset = ebx; offset = xs->ebx;
ret = max(ret, offset + eax); ret = max(ret, offset + xs->eax);
} }
xstate_bv >>= 1; xstate_bv >>= 1;

View File

@ -31,6 +31,7 @@ int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx,
u32 *ecx, u32 *edx, bool exact_only); u32 *ecx, u32 *edx, bool exact_only);
void __init kvm_init_xstate_sizes(void);
u32 xstate_required_size(u64 xstate_bv, bool compacted); u32 xstate_required_size(u64 xstate_bv, bool compacted);
int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu); int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu);

View File

@ -13997,6 +13997,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_rmp_fault);
static int __init kvm_x86_init(void) static int __init kvm_x86_init(void)
{ {
kvm_init_xstate_sizes();
kvm_mmu_x86_module_init(); kvm_mmu_x86_module_init();
mitigate_smt_rsb &= boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible(); mitigate_smt_rsb &= boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible();
return 0; return 0;

View File

@ -2,6 +2,7 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/instrumentation.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -21,7 +22,8 @@
#include "xen-ops.h" #include "xen-ops.h"
EXPORT_SYMBOL_GPL(hypercall_page); DEFINE_STATIC_CALL(xen_hypercall, xen_hypercall_hvm);
EXPORT_STATIC_CALL_TRAMP(xen_hypercall);
/* /*
* Pointer to the xen_vcpu_info structure or * Pointer to the xen_vcpu_info structure or
@ -68,6 +70,67 @@ EXPORT_SYMBOL(xen_start_flags);
*/ */
struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;
static __ref void xen_get_vendor(void)
{
init_cpu_devs();
cpu_detect(&boot_cpu_data);
get_cpu_vendor(&boot_cpu_data);
}
void xen_hypercall_setfunc(void)
{
if (static_call_query(xen_hypercall) != xen_hypercall_hvm)
return;
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON))
static_call_update(xen_hypercall, xen_hypercall_amd);
else
static_call_update(xen_hypercall, xen_hypercall_intel);
}
/*
* Evaluate processor vendor in order to select the correct hypercall
* function for HVM/PVH guests.
* Might be called very early in boot before vendor has been set by
* early_cpu_init().
*/
noinstr void *__xen_hypercall_setfunc(void)
{
void (*func)(void);
/*
* Xen is supported only on CPUs with CPUID, so testing for
* X86_FEATURE_CPUID is a test for early_cpu_init() having been
* run.
*
* Note that __xen_hypercall_setfunc() is noinstr only due to a nasty
* dependency chain: it is being called via the xen_hypercall static
* call when running as a PVH or HVM guest. Hypercalls need to be
* noinstr due to PV guests using hypercalls in noinstr code. So we
* can safely tag the function body as "instrumentation ok", since
* the PV guest requirement is not of interest here (xen_get_vendor()
* calls noinstr functions, and static_call_update_early() might do
* so, too).
*/
instrumentation_begin();
if (!boot_cpu_has(X86_FEATURE_CPUID))
xen_get_vendor();
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON))
func = xen_hypercall_amd;
else
func = xen_hypercall_intel;
static_call_update_early(xen_hypercall, func);
instrumentation_end();
return func;
}
static int xen_cpu_up_online(unsigned int cpu) static int xen_cpu_up_online(unsigned int cpu)
{ {
xen_init_lock_cpu(cpu); xen_init_lock_cpu(cpu);

View File

@ -106,15 +106,8 @@ static void __init init_hvm_pv_info(void)
/* PVH set up hypercall page in xen_prepare_pvh(). */ /* PVH set up hypercall page in xen_prepare_pvh(). */
if (xen_pvh_domain()) if (xen_pvh_domain())
pv_info.name = "Xen PVH"; pv_info.name = "Xen PVH";
else { else
u64 pfn;
uint32_t msr;
pv_info.name = "Xen HVM"; pv_info.name = "Xen HVM";
msr = cpuid_ebx(base + 2);
pfn = __pa(hypercall_page);
wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
}
xen_setup_features(); xen_setup_features();
@ -300,6 +293,10 @@ static uint32_t __init xen_platform_hvm(void)
if (xen_pv_domain()) if (xen_pv_domain())
return 0; return 0;
/* Set correct hypercall function. */
if (xen_domain)
xen_hypercall_setfunc();
if (xen_pvh_domain() && nopv) { if (xen_pvh_domain() && nopv) {
/* Guest booting via the Xen-PVH boot entry goes here */ /* Guest booting via the Xen-PVH boot entry goes here */
pr_info("\"nopv\" parameter is ignored in PVH guest\n"); pr_info("\"nopv\" parameter is ignored in PVH guest\n");

View File

@ -1341,6 +1341,9 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
xen_domain_type = XEN_PV_DOMAIN; xen_domain_type = XEN_PV_DOMAIN;
xen_start_flags = xen_start_info->flags; xen_start_flags = xen_start_info->flags;
/* Interrupts are guaranteed to be off initially. */
early_boot_irqs_disabled = true;
static_call_update_early(xen_hypercall, xen_hypercall_pv);
xen_setup_features(); xen_setup_features();
@ -1431,7 +1434,6 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_pv, xen_cpu_dead_pv)); WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_pv, xen_cpu_dead_pv));
local_irq_disable(); local_irq_disable();
early_boot_irqs_disabled = true;
xen_raw_console_write("mapping kernel into physical memory\n"); xen_raw_console_write("mapping kernel into physical memory\n");
xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base,

View File

@ -129,17 +129,10 @@ static void __init pvh_arch_setup(void)
void __init xen_pvh_init(struct boot_params *boot_params) void __init xen_pvh_init(struct boot_params *boot_params)
{ {
u32 msr;
u64 pfn;
xen_pvh = 1; xen_pvh = 1;
xen_domain_type = XEN_HVM_DOMAIN; xen_domain_type = XEN_HVM_DOMAIN;
xen_start_flags = pvh_start_info.flags; xen_start_flags = pvh_start_info.flags;
msr = cpuid_ebx(xen_cpuid_base() + 2);
pfn = __pa(hypercall_page);
wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
x86_init.oem.arch_setup = pvh_arch_setup; x86_init.oem.arch_setup = pvh_arch_setup;
x86_init.oem.banner = xen_banner; x86_init.oem.banner = xen_banner;

View File

@ -20,9 +20,32 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/objtool.h>
#include <../entry/calling.h> #include <../entry/calling.h>
.pushsection .noinstr.text, "ax" .pushsection .noinstr.text, "ax"
/*
* PV hypercall interface to the hypervisor.
*
* Called via inline asm(), so better preserve %rcx and %r11.
*
* Input:
* %eax: hypercall number
* %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall
* Output: %rax
*/
SYM_FUNC_START(xen_hypercall_pv)
ANNOTATE_NOENDBR
push %rcx
push %r11
UNWIND_HINT_SAVE
syscall
UNWIND_HINT_RESTORE
pop %r11
pop %rcx
RET
SYM_FUNC_END(xen_hypercall_pv)
/* /*
* Disabling events is simply a matter of making the event mask * Disabling events is simply a matter of making the event mask
* non-zero. * non-zero.
@ -176,7 +199,6 @@ SYM_CODE_START(xen_early_idt_handler_array)
SYM_CODE_END(xen_early_idt_handler_array) SYM_CODE_END(xen_early_idt_handler_array)
__FINIT __FINIT
hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32
/* /*
* Xen64 iret frame: * Xen64 iret frame:
* *
@ -186,17 +208,28 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32
* cs * cs
* rip <-- standard iret frame * rip <-- standard iret frame
* *
* flags * flags <-- xen_iret must push from here on
* *
* rcx } * rcx
* r11 }<-- pushed by hypercall page * r11
* rsp->rax } * rsp->rax
*/ */
.macro xen_hypercall_iret
pushq $0 /* Flags */
push %rcx
push %r11
push %rax
mov $__HYPERVISOR_iret, %eax
syscall /* Do the IRET. */
#ifdef CONFIG_MITIGATION_SLS
int3
#endif
.endm
SYM_CODE_START(xen_iret) SYM_CODE_START(xen_iret)
UNWIND_HINT_UNDEFINED UNWIND_HINT_UNDEFINED
ANNOTATE_NOENDBR ANNOTATE_NOENDBR
pushq $0 xen_hypercall_iret
jmp hypercall_iret
SYM_CODE_END(xen_iret) SYM_CODE_END(xen_iret)
/* /*
@ -301,8 +334,7 @@ SYM_CODE_START(xen_entry_SYSENTER_compat)
ENDBR ENDBR
lea 16(%rsp), %rsp /* strip %rcx, %r11 */ lea 16(%rsp), %rsp /* strip %rcx, %r11 */
mov $-ENOSYS, %rax mov $-ENOSYS, %rax
pushq $0 xen_hypercall_iret
jmp hypercall_iret
SYM_CODE_END(xen_entry_SYSENTER_compat) SYM_CODE_END(xen_entry_SYSENTER_compat)
SYM_CODE_END(xen_entry_SYSCALL_compat) SYM_CODE_END(xen_entry_SYSCALL_compat)

View File

@ -6,9 +6,11 @@
#include <linux/elfnote.h> #include <linux/elfnote.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/instrumentation.h>
#include <asm/boot.h> #include <asm/boot.h>
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/frame.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/page_types.h> #include <asm/page_types.h>
#include <asm/percpu.h> #include <asm/percpu.h>
@ -20,28 +22,6 @@
#include <xen/interface/xen-mca.h> #include <xen/interface/xen-mca.h>
#include <asm/xen/interface.h> #include <asm/xen/interface.h>
.pushsection .noinstr.text, "ax"
.balign PAGE_SIZE
SYM_CODE_START(hypercall_page)
.rept (PAGE_SIZE / 32)
UNWIND_HINT_FUNC
ANNOTATE_NOENDBR
ANNOTATE_UNRET_SAFE
ret
/*
* Xen will write the hypercall page, and sort out ENDBR.
*/
.skip 31, 0xcc
.endr
#define HYPERCALL(n) \
.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
#include <asm/xen-hypercalls.h>
#undef HYPERCALL
SYM_CODE_END(hypercall_page)
.popsection
#ifdef CONFIG_XEN_PV #ifdef CONFIG_XEN_PV
__INIT __INIT
SYM_CODE_START(startup_xen) SYM_CODE_START(startup_xen)
@ -87,6 +67,87 @@ SYM_CODE_END(xen_cpu_bringup_again)
#endif #endif
#endif #endif
.pushsection .noinstr.text, "ax"
/*
* Xen hypercall interface to the hypervisor.
*
* Input:
* %eax: hypercall number
* 32-bit:
* %ebx, %ecx, %edx, %esi, %edi: args 1..5 for the hypercall
* 64-bit:
* %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall
* Output: %[er]ax
*/
SYM_FUNC_START(xen_hypercall_hvm)
ENDBR
FRAME_BEGIN
/* Save all relevant registers (caller save and arguments). */
#ifdef CONFIG_X86_32
push %eax
push %ebx
push %ecx
push %edx
push %esi
push %edi
#else
push %rax
push %rcx
push %rdx
push %rdi
push %rsi
push %r11
push %r10
push %r9
push %r8
#ifdef CONFIG_FRAME_POINTER
pushq $0 /* Dummy push for stack alignment. */
#endif
#endif
/* Set the vendor specific function. */
call __xen_hypercall_setfunc
/* Set ZF = 1 if AMD, Restore saved registers. */
#ifdef CONFIG_X86_32
lea xen_hypercall_amd, %ebx
cmp %eax, %ebx
pop %edi
pop %esi
pop %edx
pop %ecx
pop %ebx
pop %eax
#else
lea xen_hypercall_amd(%rip), %rbx
cmp %rax, %rbx
#ifdef CONFIG_FRAME_POINTER
pop %rax /* Dummy pop. */
#endif
pop %r8
pop %r9
pop %r10
pop %r11
pop %rsi
pop %rdi
pop %rdx
pop %rcx
pop %rax
#endif
/* Use correct hypercall function. */
jz xen_hypercall_amd
jmp xen_hypercall_intel
SYM_FUNC_END(xen_hypercall_hvm)
SYM_FUNC_START(xen_hypercall_amd)
vmmcall
RET
SYM_FUNC_END(xen_hypercall_amd)
SYM_FUNC_START(xen_hypercall_intel)
vmcall
RET
SYM_FUNC_END(xen_hypercall_intel)
.popsection
ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6")
ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0")
@ -116,8 +177,6 @@ SYM_CODE_END(xen_cpu_bringup_again)
#else #else
# define FEATURES_DOM0 0 # define FEATURES_DOM0 0
#endif #endif
ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .globl xen_elfnote_hypercall_page;
xen_elfnote_hypercall_page: _ASM_PTR xen_elfnote_hypercall_page_value - .)
ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES, ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES,
.long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0) .long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0)
ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")

View File

@ -326,4 +326,13 @@ static inline void xen_smp_intr_free_pv(unsigned int cpu) {}
static inline void xen_smp_count_cpus(void) { } static inline void xen_smp_count_cpus(void) { }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
#ifdef CONFIG_XEN_PV
void xen_hypercall_pv(void);
#endif
void xen_hypercall_hvm(void);
void xen_hypercall_amd(void);
void xen_hypercall_intel(void);
void xen_hypercall_setfunc(void);
void *__xen_hypercall_setfunc(void);
#endif /* XEN_OPS_H */ #endif /* XEN_OPS_H */

View File

@ -1171,7 +1171,7 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty)
} }
EXPORT_SYMBOL_GPL(__bio_release_pages); EXPORT_SYMBOL_GPL(__bio_release_pages);
void bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter) void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter)
{ {
WARN_ON_ONCE(bio->bi_max_vecs); WARN_ON_ONCE(bio->bi_max_vecs);

View File

@ -1324,10 +1324,14 @@ void blkcg_unpin_online(struct cgroup_subsys_state *blkcg_css)
struct blkcg *blkcg = css_to_blkcg(blkcg_css); struct blkcg *blkcg = css_to_blkcg(blkcg_css);
do { do {
struct blkcg *parent;
if (!refcount_dec_and_test(&blkcg->online_pin)) if (!refcount_dec_and_test(&blkcg->online_pin))
break; break;
parent = blkcg_parent(blkcg);
blkcg_destroy_blkgs(blkcg); blkcg_destroy_blkgs(blkcg);
blkcg = blkcg_parent(blkcg); blkcg = parent;
} while (blkcg); } while (blkcg);
} }

View File

@ -1098,7 +1098,14 @@ static void __propagate_weights(struct ioc_gq *iocg, u32 active, u32 inuse,
inuse = DIV64_U64_ROUND_UP(active * iocg->child_inuse_sum, inuse = DIV64_U64_ROUND_UP(active * iocg->child_inuse_sum,
iocg->child_active_sum); iocg->child_active_sum);
} else { } else {
inuse = clamp_t(u32, inuse, 1, active); /*
* It may be tempting to turn this into a clamp expression with
* a lower limit of 1 but active may be 0, which cannot be used
* as an upper limit in that situation. This expression allows
* active to clamp inuse unless it is 0, in which case inuse
* becomes 1.
*/
inuse = min(inuse, active) ?: 1;
} }
iocg->last_inuse = iocg->inuse; iocg->last_inuse = iocg->inuse;

View File

@ -574,7 +574,7 @@ static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL); bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL);
if (!bio) if (!bio)
return -ENOMEM; return -ENOMEM;
bio_iov_bvec_set(bio, (struct iov_iter *)iter); bio_iov_bvec_set(bio, iter);
/* check that the data layout matches the hardware restrictions */ /* check that the data layout matches the hardware restrictions */
ret = bio_split_rw_at(bio, lim, &nsegs, max_bytes); ret = bio_split_rw_at(bio, lim, &nsegs, max_bytes);

View File

@ -275,15 +275,13 @@ void blk_mq_sysfs_unregister_hctxs(struct request_queue *q)
struct blk_mq_hw_ctx *hctx; struct blk_mq_hw_ctx *hctx;
unsigned long i; unsigned long i;
mutex_lock(&q->sysfs_dir_lock); lockdep_assert_held(&q->sysfs_dir_lock);
if (!q->mq_sysfs_init_done) if (!q->mq_sysfs_init_done)
goto unlock; return;
queue_for_each_hw_ctx(q, hctx, i) queue_for_each_hw_ctx(q, hctx, i)
blk_mq_unregister_hctx(hctx); blk_mq_unregister_hctx(hctx);
unlock:
mutex_unlock(&q->sysfs_dir_lock);
} }
int blk_mq_sysfs_register_hctxs(struct request_queue *q) int blk_mq_sysfs_register_hctxs(struct request_queue *q)
@ -292,9 +290,10 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q)
unsigned long i; unsigned long i;
int ret = 0; int ret = 0;
mutex_lock(&q->sysfs_dir_lock); lockdep_assert_held(&q->sysfs_dir_lock);
if (!q->mq_sysfs_init_done) if (!q->mq_sysfs_init_done)
goto unlock; return ret;
queue_for_each_hw_ctx(q, hctx, i) { queue_for_each_hw_ctx(q, hctx, i) {
ret = blk_mq_register_hctx(hctx); ret = blk_mq_register_hctx(hctx);
@ -302,8 +301,5 @@ int blk_mq_sysfs_register_hctxs(struct request_queue *q)
break; break;
} }
unlock:
mutex_unlock(&q->sysfs_dir_lock);
return ret; return ret;
} }

View File

@ -1544,19 +1544,17 @@ static void blk_mq_requeue_work(struct work_struct *work)
while (!list_empty(&rq_list)) { while (!list_empty(&rq_list)) {
rq = list_entry(rq_list.next, struct request, queuelist); rq = list_entry(rq_list.next, struct request, queuelist);
list_del_init(&rq->queuelist);
/* /*
* If RQF_DONTPREP ist set, the request has been started by the * If RQF_DONTPREP is set, the request has been started by the
* driver already and might have driver-specific data allocated * driver already and might have driver-specific data allocated
* already. Insert it into the hctx dispatch list to avoid * already. Insert it into the hctx dispatch list to avoid
* block layer merges for the request. * block layer merges for the request.
*/ */
if (rq->rq_flags & RQF_DONTPREP) { if (rq->rq_flags & RQF_DONTPREP)
list_del_init(&rq->queuelist);
blk_mq_request_bypass_insert(rq, 0); blk_mq_request_bypass_insert(rq, 0);
} else { else
list_del_init(&rq->queuelist);
blk_mq_insert_request(rq, BLK_MQ_INSERT_AT_HEAD); blk_mq_insert_request(rq, BLK_MQ_INSERT_AT_HEAD);
}
} }
while (!list_empty(&flush_list)) { while (!list_empty(&flush_list)) {
@ -4455,7 +4453,8 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
unsigned long i, j; unsigned long i, j;
/* protect against switching io scheduler */ /* protect against switching io scheduler */
mutex_lock(&q->sysfs_lock); lockdep_assert_held(&q->sysfs_lock);
for (i = 0; i < set->nr_hw_queues; i++) { for (i = 0; i < set->nr_hw_queues; i++) {
int old_node; int old_node;
int node = blk_mq_get_hctx_node(set, i); int node = blk_mq_get_hctx_node(set, i);
@ -4488,7 +4487,6 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
xa_for_each_start(&q->hctx_table, j, hctx, j) xa_for_each_start(&q->hctx_table, j, hctx, j)
blk_mq_exit_hctx(q, set, hctx, j); blk_mq_exit_hctx(q, set, hctx, j);
mutex_unlock(&q->sysfs_lock);
/* unregister cpuhp callbacks for exited hctxs */ /* unregister cpuhp callbacks for exited hctxs */
blk_mq_remove_hw_queues_cpuhp(q); blk_mq_remove_hw_queues_cpuhp(q);
@ -4520,10 +4518,14 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
xa_init(&q->hctx_table); xa_init(&q->hctx_table);
mutex_lock(&q->sysfs_lock);
blk_mq_realloc_hw_ctxs(set, q); blk_mq_realloc_hw_ctxs(set, q);
if (!q->nr_hw_queues) if (!q->nr_hw_queues)
goto err_hctxs; goto err_hctxs;
mutex_unlock(&q->sysfs_lock);
INIT_WORK(&q->timeout_work, blk_mq_timeout_work); INIT_WORK(&q->timeout_work, blk_mq_timeout_work);
blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ); blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);
@ -4542,6 +4544,7 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
return 0; return 0;
err_hctxs: err_hctxs:
mutex_unlock(&q->sysfs_lock);
blk_mq_release(q); blk_mq_release(q);
err_exit: err_exit:
q->mq_ops = NULL; q->mq_ops = NULL;
@ -4922,12 +4925,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
return false; return false;
/* q->elevator needs protection from ->sysfs_lock */ /* q->elevator needs protection from ->sysfs_lock */
mutex_lock(&q->sysfs_lock); lockdep_assert_held(&q->sysfs_lock);
/* the check has to be done with holding sysfs_lock */ /* the check has to be done with holding sysfs_lock */
if (!q->elevator) { if (!q->elevator) {
kfree(qe); kfree(qe);
goto unlock; goto out;
} }
INIT_LIST_HEAD(&qe->node); INIT_LIST_HEAD(&qe->node);
@ -4937,9 +4940,7 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
__elevator_get(qe->type); __elevator_get(qe->type);
list_add(&qe->node, head); list_add(&qe->node, head);
elevator_disable(q); elevator_disable(q);
unlock: out:
mutex_unlock(&q->sysfs_lock);
return true; return true;
} }
@ -4968,11 +4969,9 @@ static void blk_mq_elv_switch_back(struct list_head *head,
list_del(&qe->node); list_del(&qe->node);
kfree(qe); kfree(qe);
mutex_lock(&q->sysfs_lock);
elevator_switch(q, t); elevator_switch(q, t);
/* drop the reference acquired in blk_mq_elv_switch_none */ /* drop the reference acquired in blk_mq_elv_switch_none */
elevator_put(t); elevator_put(t);
mutex_unlock(&q->sysfs_lock);
} }
static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
@ -4992,8 +4991,11 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues) if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues)
return; return;
list_for_each_entry(q, &set->tag_list, tag_set_list) list_for_each_entry(q, &set->tag_list, tag_set_list) {
mutex_lock(&q->sysfs_dir_lock);
mutex_lock(&q->sysfs_lock);
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
}
/* /*
* Switch IO scheduler to 'none', cleaning up the data associated * Switch IO scheduler to 'none', cleaning up the data associated
* with the previous scheduler. We will switch back once we are done * with the previous scheduler. We will switch back once we are done
@ -5049,8 +5051,11 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
list_for_each_entry(q, &set->tag_list, tag_set_list) list_for_each_entry(q, &set->tag_list, tag_set_list)
blk_mq_elv_switch_back(&head, q); blk_mq_elv_switch_back(&head, q);
list_for_each_entry(q, &set->tag_list, tag_set_list) list_for_each_entry(q, &set->tag_list, tag_set_list) {
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
mutex_unlock(&q->sysfs_lock);
mutex_unlock(&q->sysfs_dir_lock);
}
/* Free the excess tags when nr_hw_queues shrink. */ /* Free the excess tags when nr_hw_queues shrink. */
for (i = set->nr_hw_queues; i < prev_nr_hw_queues; i++) for (i = set->nr_hw_queues; i < prev_nr_hw_queues; i++)

View File

@ -263,7 +263,7 @@ static ssize_t queue_nr_zones_show(struct gendisk *disk, char *page)
static ssize_t queue_iostats_passthrough_show(struct gendisk *disk, char *page) static ssize_t queue_iostats_passthrough_show(struct gendisk *disk, char *page)
{ {
return queue_var_show(blk_queue_passthrough_stat(disk->queue), page); return queue_var_show(!!blk_queue_passthrough_stat(disk->queue), page);
} }
static ssize_t queue_iostats_passthrough_store(struct gendisk *disk, static ssize_t queue_iostats_passthrough_store(struct gendisk *disk,
@ -706,11 +706,11 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
if (entry->load_module) if (entry->load_module)
entry->load_module(disk, page, length); entry->load_module(disk, page, length);
blk_mq_freeze_queue(q);
mutex_lock(&q->sysfs_lock); mutex_lock(&q->sysfs_lock);
blk_mq_freeze_queue(q);
res = entry->store(disk, page, length); res = entry->store(disk, page, length);
mutex_unlock(&q->sysfs_lock);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
mutex_unlock(&q->sysfs_lock);
return res; return res;
} }

View File

@ -41,7 +41,6 @@ static const char *const zone_cond_name[] = {
/* /*
* Per-zone write plug. * Per-zone write plug.
* @node: hlist_node structure for managing the plug using a hash table. * @node: hlist_node structure for managing the plug using a hash table.
* @link: To list the plug in the zone write plug error list of the disk.
* @ref: Zone write plug reference counter. A zone write plug reference is * @ref: Zone write plug reference counter. A zone write plug reference is
* always at least 1 when the plug is hashed in the disk plug hash table. * always at least 1 when the plug is hashed in the disk plug hash table.
* The reference is incremented whenever a new BIO needing plugging is * The reference is incremented whenever a new BIO needing plugging is
@ -63,7 +62,6 @@ static const char *const zone_cond_name[] = {
*/ */
struct blk_zone_wplug { struct blk_zone_wplug {
struct hlist_node node; struct hlist_node node;
struct list_head link;
refcount_t ref; refcount_t ref;
spinlock_t lock; spinlock_t lock;
unsigned int flags; unsigned int flags;
@ -80,8 +78,8 @@ struct blk_zone_wplug {
* - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged, * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged,
* that is, that write BIOs are being throttled due to a write BIO already * that is, that write BIOs are being throttled due to a write BIO already
* being executed or the zone write plug bio list is not empty. * being executed or the zone write plug bio list is not empty.
* - BLK_ZONE_WPLUG_ERROR: Indicates that a write error happened which will be * - BLK_ZONE_WPLUG_NEED_WP_UPDATE: Indicates that we lost track of a zone
* recovered with a report zone to update the zone write pointer offset. * write pointer offset and need to update it.
* - BLK_ZONE_WPLUG_UNHASHED: Indicates that the zone write plug was removed * - BLK_ZONE_WPLUG_UNHASHED: Indicates that the zone write plug was removed
* from the disk hash table and that the initial reference to the zone * from the disk hash table and that the initial reference to the zone
* write plug set when the plug was first added to the hash table has been * write plug set when the plug was first added to the hash table has been
@ -91,11 +89,9 @@ struct blk_zone_wplug {
* freed once all remaining references from BIOs or functions are dropped. * freed once all remaining references from BIOs or functions are dropped.
*/ */
#define BLK_ZONE_WPLUG_PLUGGED (1U << 0) #define BLK_ZONE_WPLUG_PLUGGED (1U << 0)
#define BLK_ZONE_WPLUG_ERROR (1U << 1) #define BLK_ZONE_WPLUG_NEED_WP_UPDATE (1U << 1)
#define BLK_ZONE_WPLUG_UNHASHED (1U << 2) #define BLK_ZONE_WPLUG_UNHASHED (1U << 2)
#define BLK_ZONE_WPLUG_BUSY (BLK_ZONE_WPLUG_PLUGGED | BLK_ZONE_WPLUG_ERROR)
/** /**
* blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX. * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX.
* @zone_cond: BLK_ZONE_COND_XXX. * @zone_cond: BLK_ZONE_COND_XXX.
@ -115,6 +111,30 @@ const char *blk_zone_cond_str(enum blk_zone_cond zone_cond)
} }
EXPORT_SYMBOL_GPL(blk_zone_cond_str); EXPORT_SYMBOL_GPL(blk_zone_cond_str);
struct disk_report_zones_cb_args {
struct gendisk *disk;
report_zones_cb user_cb;
void *user_data;
};
static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
struct blk_zone *zone);
static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx,
void *data)
{
struct disk_report_zones_cb_args *args = data;
struct gendisk *disk = args->disk;
if (disk->zone_wplugs_hash)
disk_zone_wplug_sync_wp_offset(disk, zone);
if (!args->user_cb)
return 0;
return args->user_cb(zone, idx, args->user_data);
}
/** /**
* blkdev_report_zones - Get zones information * blkdev_report_zones - Get zones information
* @bdev: Target block device * @bdev: Target block device
@ -139,6 +159,11 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector,
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
sector_t capacity = get_capacity(disk); sector_t capacity = get_capacity(disk);
struct disk_report_zones_cb_args args = {
.disk = disk,
.user_cb = cb,
.user_data = data,
};
if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones)) if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones))
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -146,7 +171,8 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector,
if (!nr_zones || sector >= capacity) if (!nr_zones || sector >= capacity)
return 0; return 0;
return disk->fops->report_zones(disk, sector, nr_zones, cb, data); return disk->fops->report_zones(disk, sector, nr_zones,
disk_report_zones_cb, &args);
} }
EXPORT_SYMBOL_GPL(blkdev_report_zones); EXPORT_SYMBOL_GPL(blkdev_report_zones);
@ -427,7 +453,7 @@ static inline void disk_put_zone_wplug(struct blk_zone_wplug *zwplug)
{ {
if (refcount_dec_and_test(&zwplug->ref)) { if (refcount_dec_and_test(&zwplug->ref)) {
WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list)); WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list));
WARN_ON_ONCE(!list_empty(&zwplug->link)); WARN_ON_ONCE(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED);
WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)); WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED));
call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu); call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu);
@ -441,8 +467,8 @@ static inline bool disk_should_remove_zone_wplug(struct gendisk *disk,
if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)
return false; return false;
/* If the zone write plug is still busy, it cannot be removed. */ /* If the zone write plug is still plugged, it cannot be removed. */
if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) if (zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)
return false; return false;
/* /*
@ -525,12 +551,11 @@ static struct blk_zone_wplug *disk_get_and_lock_zone_wplug(struct gendisk *disk,
return NULL; return NULL;
INIT_HLIST_NODE(&zwplug->node); INIT_HLIST_NODE(&zwplug->node);
INIT_LIST_HEAD(&zwplug->link);
refcount_set(&zwplug->ref, 2); refcount_set(&zwplug->ref, 2);
spin_lock_init(&zwplug->lock); spin_lock_init(&zwplug->lock);
zwplug->flags = 0; zwplug->flags = 0;
zwplug->zone_no = zno; zwplug->zone_no = zno;
zwplug->wp_offset = sector & (disk->queue->limits.chunk_sectors - 1); zwplug->wp_offset = bdev_offset_from_zone_start(disk->part0, sector);
bio_list_init(&zwplug->bio_list); bio_list_init(&zwplug->bio_list);
INIT_WORK(&zwplug->bio_work, blk_zone_wplug_bio_work); INIT_WORK(&zwplug->bio_work, blk_zone_wplug_bio_work);
zwplug->disk = disk; zwplug->disk = disk;
@ -574,115 +599,22 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug)
} }
/* /*
* Abort (fail) all plugged BIOs of a zone write plug that are not aligned * Set a zone write plug write pointer offset to the specified value.
* with the assumed write pointer location of the zone when the BIO will * This aborts all plugged BIOs, which is fine as this function is called for
* be unplugged. * a zone reset operation, a zone finish operation or if the zone needs a wp
*/ * update from a report zone after a write error.
static void disk_zone_wplug_abort_unaligned(struct gendisk *disk,
struct blk_zone_wplug *zwplug)
{
unsigned int wp_offset = zwplug->wp_offset;
struct bio_list bl = BIO_EMPTY_LIST;
struct bio *bio;
while ((bio = bio_list_pop(&zwplug->bio_list))) {
if (disk_zone_is_full(disk, zwplug->zone_no, wp_offset) ||
(bio_op(bio) != REQ_OP_ZONE_APPEND &&
bio_offset_from_zone_start(bio) != wp_offset)) {
blk_zone_wplug_bio_io_error(zwplug, bio);
continue;
}
wp_offset += bio_sectors(bio);
bio_list_add(&bl, bio);
}
bio_list_merge(&zwplug->bio_list, &bl);
}
static inline void disk_zone_wplug_set_error(struct gendisk *disk,
struct blk_zone_wplug *zwplug)
{
unsigned long flags;
if (zwplug->flags & BLK_ZONE_WPLUG_ERROR)
return;
/*
* At this point, we already have a reference on the zone write plug.
* However, since we are going to add the plug to the disk zone write
* plugs work list, increase its reference count. This reference will
* be dropped in disk_zone_wplugs_work() once the error state is
* handled, or in disk_zone_wplug_clear_error() if the zone is reset or
* finished.
*/
zwplug->flags |= BLK_ZONE_WPLUG_ERROR;
refcount_inc(&zwplug->ref);
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
list_add_tail(&zwplug->link, &disk->zone_wplugs_err_list);
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
}
static inline void disk_zone_wplug_clear_error(struct gendisk *disk,
struct blk_zone_wplug *zwplug)
{
unsigned long flags;
if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR))
return;
/*
* We are racing with the error handling work which drops the reference
* on the zone write plug after handling the error state. So remove the
* plug from the error list and drop its reference count only if the
* error handling has not yet started, that is, if the zone write plug
* is still listed.
*/
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
if (!list_empty(&zwplug->link)) {
list_del_init(&zwplug->link);
zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR;
disk_put_zone_wplug(zwplug);
}
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
}
/*
* Set a zone write plug write pointer offset to either 0 (zone reset case)
* or to the zone size (zone finish case). This aborts all plugged BIOs, which
* is fine to do as doing a zone reset or zone finish while writes are in-flight
* is a mistake from the user which will most likely cause all plugged BIOs to
* fail anyway.
*/ */
static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, static void disk_zone_wplug_set_wp_offset(struct gendisk *disk,
struct blk_zone_wplug *zwplug, struct blk_zone_wplug *zwplug,
unsigned int wp_offset) unsigned int wp_offset)
{ {
unsigned long flags; lockdep_assert_held(&zwplug->lock);
spin_lock_irqsave(&zwplug->lock, flags);
/*
* Make sure that a BIO completion or another zone reset or finish
* operation has not already removed the plug from the hash table.
*/
if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) {
spin_unlock_irqrestore(&zwplug->lock, flags);
return;
}
/* Update the zone write pointer and abort all plugged BIOs. */ /* Update the zone write pointer and abort all plugged BIOs. */
zwplug->flags &= ~BLK_ZONE_WPLUG_NEED_WP_UPDATE;
zwplug->wp_offset = wp_offset; zwplug->wp_offset = wp_offset;
disk_zone_wplug_abort(zwplug); disk_zone_wplug_abort(zwplug);
/*
* Updating the write pointer offset puts back the zone
* in a good state. So clear the error flag and decrement the
* error count if we were in error state.
*/
disk_zone_wplug_clear_error(disk, zwplug);
/* /*
* The zone write plug now has no BIO plugged: remove it from the * The zone write plug now has no BIO plugged: remove it from the
* hash table so that it cannot be seen. The plug will be freed * hash table so that it cannot be seen. The plug will be freed
@ -690,8 +622,58 @@ static void disk_zone_wplug_set_wp_offset(struct gendisk *disk,
*/ */
if (disk_should_remove_zone_wplug(disk, zwplug)) if (disk_should_remove_zone_wplug(disk, zwplug))
disk_remove_zone_wplug(disk, zwplug); disk_remove_zone_wplug(disk, zwplug);
}
static unsigned int blk_zone_wp_offset(struct blk_zone *zone)
{
switch (zone->cond) {
case BLK_ZONE_COND_IMP_OPEN:
case BLK_ZONE_COND_EXP_OPEN:
case BLK_ZONE_COND_CLOSED:
return zone->wp - zone->start;
case BLK_ZONE_COND_FULL:
return zone->len;
case BLK_ZONE_COND_EMPTY:
return 0;
case BLK_ZONE_COND_NOT_WP:
case BLK_ZONE_COND_OFFLINE:
case BLK_ZONE_COND_READONLY:
default:
/*
* Conventional, offline and read-only zones do not have a valid
* write pointer.
*/
return UINT_MAX;
}
}
static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
struct blk_zone *zone)
{
struct blk_zone_wplug *zwplug;
unsigned long flags;
zwplug = disk_get_zone_wplug(disk, zone->start);
if (!zwplug)
return;
spin_lock_irqsave(&zwplug->lock, flags);
if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE)
disk_zone_wplug_set_wp_offset(disk, zwplug,
blk_zone_wp_offset(zone));
spin_unlock_irqrestore(&zwplug->lock, flags); spin_unlock_irqrestore(&zwplug->lock, flags);
disk_put_zone_wplug(zwplug);
}
static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector)
{
struct disk_report_zones_cb_args args = {
.disk = disk,
};
return disk->fops->report_zones(disk, sector, 1,
disk_report_zones_cb, &args);
} }
static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,
@ -700,6 +682,7 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,
struct gendisk *disk = bio->bi_bdev->bd_disk; struct gendisk *disk = bio->bi_bdev->bd_disk;
sector_t sector = bio->bi_iter.bi_sector; sector_t sector = bio->bi_iter.bi_sector;
struct blk_zone_wplug *zwplug; struct blk_zone_wplug *zwplug;
unsigned long flags;
/* Conventional zones cannot be reset nor finished. */ /* Conventional zones cannot be reset nor finished. */
if (!bdev_zone_is_seq(bio->bi_bdev, sector)) { if (!bdev_zone_is_seq(bio->bi_bdev, sector)) {
@ -707,6 +690,15 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,
return true; return true;
} }
/*
* No-wait reset or finish BIOs do not make much sense as the callers
* issue these as blocking operations in most cases. To avoid issues
* the BIO execution potentially failing with BLK_STS_AGAIN, warn about
* REQ_NOWAIT being set and ignore that flag.
*/
if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT))
bio->bi_opf &= ~REQ_NOWAIT;
/* /*
* If we have a zone write plug, set its write pointer offset to 0 * If we have a zone write plug, set its write pointer offset to 0
* (reset case) or to the zone size (finish case). This will abort all * (reset case) or to the zone size (finish case). This will abort all
@ -716,7 +708,9 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,
*/ */
zwplug = disk_get_zone_wplug(disk, sector); zwplug = disk_get_zone_wplug(disk, sector);
if (zwplug) { if (zwplug) {
spin_lock_irqsave(&zwplug->lock, flags);
disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset);
spin_unlock_irqrestore(&zwplug->lock, flags);
disk_put_zone_wplug(zwplug); disk_put_zone_wplug(zwplug);
} }
@ -727,6 +721,7 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio)
{ {
struct gendisk *disk = bio->bi_bdev->bd_disk; struct gendisk *disk = bio->bi_bdev->bd_disk;
struct blk_zone_wplug *zwplug; struct blk_zone_wplug *zwplug;
unsigned long flags;
sector_t sector; sector_t sector;
/* /*
@ -738,7 +733,9 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio)
sector += disk->queue->limits.chunk_sectors) { sector += disk->queue->limits.chunk_sectors) {
zwplug = disk_get_zone_wplug(disk, sector); zwplug = disk_get_zone_wplug(disk, sector);
if (zwplug) { if (zwplug) {
spin_lock_irqsave(&zwplug->lock, flags);
disk_zone_wplug_set_wp_offset(disk, zwplug, 0); disk_zone_wplug_set_wp_offset(disk, zwplug, 0);
spin_unlock_irqrestore(&zwplug->lock, flags);
disk_put_zone_wplug(zwplug); disk_put_zone_wplug(zwplug);
} }
} }
@ -746,9 +743,25 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio)
return false; return false;
} }
static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk,
struct bio *bio, unsigned int nr_segs) struct blk_zone_wplug *zwplug)
{ {
/*
* Take a reference on the zone write plug and schedule the submission
* of the next plugged BIO. blk_zone_wplug_bio_work() will release the
* reference we take here.
*/
WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
refcount_inc(&zwplug->ref);
queue_work(disk->zone_wplugs_wq, &zwplug->bio_work);
}
static inline void disk_zone_wplug_add_bio(struct gendisk *disk,
struct blk_zone_wplug *zwplug,
struct bio *bio, unsigned int nr_segs)
{
bool schedule_bio_work = false;
/* /*
* Grab an extra reference on the BIO request queue usage counter. * Grab an extra reference on the BIO request queue usage counter.
* This reference will be reused to submit a request for the BIO for * This reference will be reused to submit a request for the BIO for
@ -764,6 +777,16 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug,
*/ */
bio_clear_polled(bio); bio_clear_polled(bio);
/*
* REQ_NOWAIT BIOs are always handled using the zone write plug BIO
* work, which can block. So clear the REQ_NOWAIT flag and schedule the
* work if this is the first BIO we are plugging.
*/
if (bio->bi_opf & REQ_NOWAIT) {
schedule_bio_work = !(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED);
bio->bi_opf &= ~REQ_NOWAIT;
}
/* /*
* Reuse the poll cookie field to store the number of segments when * Reuse the poll cookie field to store the number of segments when
* split to the hardware limits. * split to the hardware limits.
@ -777,6 +800,11 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug,
* at the tail of the list to preserve the sequential write order. * at the tail of the list to preserve the sequential write order.
*/ */
bio_list_add(&zwplug->bio_list, bio); bio_list_add(&zwplug->bio_list, bio);
zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED;
if (schedule_bio_work)
disk_zone_wplug_schedule_bio_work(disk, zwplug);
} }
/* /*
@ -889,13 +917,23 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug,
{ {
struct gendisk *disk = bio->bi_bdev->bd_disk; struct gendisk *disk = bio->bi_bdev->bd_disk;
/*
* If we lost track of the zone write pointer due to a write error,
* the user must either execute a report zones, reset the zone or finish
* the to recover a reliable write pointer position. Fail BIOs if the
* user did not do that as we cannot handle emulated zone append
* otherwise.
*/
if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE)
return false;
/* /*
* Check that the user is not attempting to write to a full zone. * Check that the user is not attempting to write to a full zone.
* We know such BIO will fail, and that would potentially overflow our * We know such BIO will fail, and that would potentially overflow our
* write pointer offset beyond the end of the zone. * write pointer offset beyond the end of the zone.
*/ */
if (disk_zone_wplug_is_full(disk, zwplug)) if (disk_zone_wplug_is_full(disk, zwplug))
goto err; return false;
if (bio_op(bio) == REQ_OP_ZONE_APPEND) { if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
/* /*
@ -914,24 +952,18 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug,
bio_set_flag(bio, BIO_EMULATES_ZONE_APPEND); bio_set_flag(bio, BIO_EMULATES_ZONE_APPEND);
} else { } else {
/* /*
* Check for non-sequential writes early because we avoid a * Check for non-sequential writes early as we know that BIOs
* whole lot of error handling trouble if we don't send it off * with a start sector not unaligned to the zone write pointer
* to the driver. * will fail.
*/ */
if (bio_offset_from_zone_start(bio) != zwplug->wp_offset) if (bio_offset_from_zone_start(bio) != zwplug->wp_offset)
goto err; return false;
} }
/* Advance the zone write pointer offset. */ /* Advance the zone write pointer offset. */
zwplug->wp_offset += bio_sectors(bio); zwplug->wp_offset += bio_sectors(bio);
return true; return true;
err:
/* We detected an invalid write BIO: schedule error recovery. */
disk_zone_wplug_set_error(disk, zwplug);
kblockd_schedule_work(&disk->zone_wplugs_work);
return false;
} }
static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs)
@ -970,7 +1002,10 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs)
zwplug = disk_get_and_lock_zone_wplug(disk, sector, gfp_mask, &flags); zwplug = disk_get_and_lock_zone_wplug(disk, sector, gfp_mask, &flags);
if (!zwplug) { if (!zwplug) {
bio_io_error(bio); if (bio->bi_opf & REQ_NOWAIT)
bio_wouldblock_error(bio);
else
bio_io_error(bio);
return true; return true;
} }
@ -978,18 +1013,20 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs)
bio_set_flag(bio, BIO_ZONE_WRITE_PLUGGING); bio_set_flag(bio, BIO_ZONE_WRITE_PLUGGING);
/* /*
* If the zone is already plugged or has a pending error, add the BIO * If the zone is already plugged, add the BIO to the plug BIO list.
* to the plug BIO list. Otherwise, plug and let the BIO execute. * Do the same for REQ_NOWAIT BIOs to ensure that we will not see a
* BLK_STS_AGAIN failure if we let the BIO execute.
* Otherwise, plug and let the BIO execute.
*/ */
if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) if ((zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) ||
(bio->bi_opf & REQ_NOWAIT))
goto plug; goto plug;
/* if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
* If an error is detected when preparing the BIO, add it to the BIO spin_unlock_irqrestore(&zwplug->lock, flags);
* list so that error recovery can deal with it. bio_io_error(bio);
*/ return true;
if (!blk_zone_wplug_prepare_bio(zwplug, bio)) }
goto plug;
zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED;
@ -998,8 +1035,7 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs)
return false; return false;
plug: plug:
zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; disk_zone_wplug_add_bio(disk, zwplug, bio, nr_segs);
blk_zone_wplug_add_bio(zwplug, bio, nr_segs);
spin_unlock_irqrestore(&zwplug->lock, flags); spin_unlock_irqrestore(&zwplug->lock, flags);
@ -1083,19 +1119,6 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs)
} }
EXPORT_SYMBOL_GPL(blk_zone_plug_bio); EXPORT_SYMBOL_GPL(blk_zone_plug_bio);
static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk,
struct blk_zone_wplug *zwplug)
{
/*
* Take a reference on the zone write plug and schedule the submission
* of the next plugged BIO. blk_zone_wplug_bio_work() will release the
* reference we take here.
*/
WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
refcount_inc(&zwplug->ref);
queue_work(disk->zone_wplugs_wq, &zwplug->bio_work);
}
static void disk_zone_wplug_unplug_bio(struct gendisk *disk, static void disk_zone_wplug_unplug_bio(struct gendisk *disk,
struct blk_zone_wplug *zwplug) struct blk_zone_wplug *zwplug)
{ {
@ -1103,16 +1126,6 @@ static void disk_zone_wplug_unplug_bio(struct gendisk *disk,
spin_lock_irqsave(&zwplug->lock, flags); spin_lock_irqsave(&zwplug->lock, flags);
/*
* If we had an error, schedule error recovery. The recovery work
* will restart submission of plugged BIOs.
*/
if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) {
spin_unlock_irqrestore(&zwplug->lock, flags);
kblockd_schedule_work(&disk->zone_wplugs_work);
return;
}
/* Schedule submission of the next plugged BIO if we have one. */ /* Schedule submission of the next plugged BIO if we have one. */
if (!bio_list_empty(&zwplug->bio_list)) { if (!bio_list_empty(&zwplug->bio_list)) {
disk_zone_wplug_schedule_bio_work(disk, zwplug); disk_zone_wplug_schedule_bio_work(disk, zwplug);
@ -1155,12 +1168,13 @@ void blk_zone_write_plug_bio_endio(struct bio *bio)
} }
/* /*
* If the BIO failed, mark the plug as having an error to trigger * If the BIO failed, abort all plugged BIOs and mark the plug as
* recovery. * needing a write pointer update.
*/ */
if (bio->bi_status != BLK_STS_OK) { if (bio->bi_status != BLK_STS_OK) {
spin_lock_irqsave(&zwplug->lock, flags); spin_lock_irqsave(&zwplug->lock, flags);
disk_zone_wplug_set_error(disk, zwplug); disk_zone_wplug_abort(zwplug);
zwplug->flags |= BLK_ZONE_WPLUG_NEED_WP_UPDATE;
spin_unlock_irqrestore(&zwplug->lock, flags); spin_unlock_irqrestore(&zwplug->lock, flags);
} }
@ -1216,6 +1230,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
*/ */
spin_lock_irqsave(&zwplug->lock, flags); spin_lock_irqsave(&zwplug->lock, flags);
again:
bio = bio_list_pop(&zwplug->bio_list); bio = bio_list_pop(&zwplug->bio_list);
if (!bio) { if (!bio) {
zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
@ -1224,10 +1239,8 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
} }
if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
/* Error recovery will decide what to do with the BIO. */ blk_zone_wplug_bio_io_error(zwplug, bio);
bio_list_add_head(&zwplug->bio_list, bio); goto again;
spin_unlock_irqrestore(&zwplug->lock, flags);
goto put_zwplug;
} }
spin_unlock_irqrestore(&zwplug->lock, flags); spin_unlock_irqrestore(&zwplug->lock, flags);
@ -1249,120 +1262,6 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
disk_put_zone_wplug(zwplug); disk_put_zone_wplug(zwplug);
} }
static unsigned int blk_zone_wp_offset(struct blk_zone *zone)
{
switch (zone->cond) {
case BLK_ZONE_COND_IMP_OPEN:
case BLK_ZONE_COND_EXP_OPEN:
case BLK_ZONE_COND_CLOSED:
return zone->wp - zone->start;
case BLK_ZONE_COND_FULL:
return zone->len;
case BLK_ZONE_COND_EMPTY:
return 0;
case BLK_ZONE_COND_NOT_WP:
case BLK_ZONE_COND_OFFLINE:
case BLK_ZONE_COND_READONLY:
default:
/*
* Conventional, offline and read-only zones do not have a valid
* write pointer.
*/
return UINT_MAX;
}
}
static int blk_zone_wplug_report_zone_cb(struct blk_zone *zone,
unsigned int idx, void *data)
{
struct blk_zone *zonep = data;
*zonep = *zone;
return 0;
}
static void disk_zone_wplug_handle_error(struct gendisk *disk,
struct blk_zone_wplug *zwplug)
{
sector_t zone_start_sector =
bdev_zone_sectors(disk->part0) * zwplug->zone_no;
unsigned int noio_flag;
struct blk_zone zone;
unsigned long flags;
int ret;
/* Get the current zone information from the device. */
noio_flag = memalloc_noio_save();
ret = disk->fops->report_zones(disk, zone_start_sector, 1,
blk_zone_wplug_report_zone_cb, &zone);
memalloc_noio_restore(noio_flag);
spin_lock_irqsave(&zwplug->lock, flags);
/*
* A zone reset or finish may have cleared the error already. In such
* case, do nothing as the report zones may have seen the "old" write
* pointer value before the reset/finish operation completed.
*/
if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR))
goto unlock;
zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR;
if (ret != 1) {
/*
* We failed to get the zone information, meaning that something
* is likely really wrong with the device. Abort all remaining
* plugged BIOs as otherwise we could endup waiting forever on
* plugged BIOs to complete if there is a queue freeze on-going.
*/
disk_zone_wplug_abort(zwplug);
goto unplug;
}
/* Update the zone write pointer offset. */
zwplug->wp_offset = blk_zone_wp_offset(&zone);
disk_zone_wplug_abort_unaligned(disk, zwplug);
/* Restart BIO submission if we still have any BIO left. */
if (!bio_list_empty(&zwplug->bio_list)) {
disk_zone_wplug_schedule_bio_work(disk, zwplug);
goto unlock;
}
unplug:
zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
if (disk_should_remove_zone_wplug(disk, zwplug))
disk_remove_zone_wplug(disk, zwplug);
unlock:
spin_unlock_irqrestore(&zwplug->lock, flags);
}
static void disk_zone_wplugs_work(struct work_struct *work)
{
struct gendisk *disk =
container_of(work, struct gendisk, zone_wplugs_work);
struct blk_zone_wplug *zwplug;
unsigned long flags;
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
while (!list_empty(&disk->zone_wplugs_err_list)) {
zwplug = list_first_entry(&disk->zone_wplugs_err_list,
struct blk_zone_wplug, link);
list_del_init(&zwplug->link);
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
disk_zone_wplug_handle_error(disk, zwplug);
disk_put_zone_wplug(zwplug);
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
}
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
}
static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk)
{ {
return 1U << disk->zone_wplugs_hash_bits; return 1U << disk->zone_wplugs_hash_bits;
@ -1371,8 +1270,6 @@ static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk)
void disk_init_zone_resources(struct gendisk *disk) void disk_init_zone_resources(struct gendisk *disk)
{ {
spin_lock_init(&disk->zone_wplugs_lock); spin_lock_init(&disk->zone_wplugs_lock);
INIT_LIST_HEAD(&disk->zone_wplugs_err_list);
INIT_WORK(&disk->zone_wplugs_work, disk_zone_wplugs_work);
} }
/* /*
@ -1471,8 +1368,6 @@ void disk_free_zone_resources(struct gendisk *disk)
if (!disk->zone_wplugs_pool) if (!disk->zone_wplugs_pool)
return; return;
cancel_work_sync(&disk->zone_wplugs_work);
if (disk->zone_wplugs_wq) { if (disk->zone_wplugs_wq) {
destroy_workqueue(disk->zone_wplugs_wq); destroy_workqueue(disk->zone_wplugs_wq);
disk->zone_wplugs_wq = NULL; disk->zone_wplugs_wq = NULL;
@ -1669,6 +1564,8 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx,
if (!disk->zone_wplugs_hash) if (!disk->zone_wplugs_hash)
return 0; return 0;
disk_zone_wplug_sync_wp_offset(disk, zone);
wp_offset = blk_zone_wp_offset(zone); wp_offset = blk_zone_wp_offset(zone);
if (!wp_offset || wp_offset >= zone->capacity) if (!wp_offset || wp_offset >= zone->capacity)
return 0; return 0;
@ -1799,6 +1696,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
memalloc_noio_restore(noio_flag); memalloc_noio_restore(noio_flag);
return ret; return ret;
} }
ret = disk->fops->report_zones(disk, 0, UINT_MAX, ret = disk->fops->report_zones(disk, 0, UINT_MAX,
blk_revalidate_zone_cb, &args); blk_revalidate_zone_cb, &args);
if (!ret) { if (!ret) {
@ -1835,6 +1733,48 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
} }
EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones); EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
/**
* blk_zone_issue_zeroout - zero-fill a block range in a zone
* @bdev: blockdev to write
* @sector: start sector
* @nr_sects: number of sectors to write
* @gfp_mask: memory allocation flags (for bio_alloc)
*
* Description:
* Zero-fill a block range in a zone (@sector must be equal to the zone write
* pointer), handling potential errors due to the (initially unknown) lack of
* hardware offload (See blkdev_issue_zeroout()).
*/
int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask)
{
int ret;
if (WARN_ON_ONCE(!bdev_is_zoned(bdev)))
return -EIO;
ret = blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask,
BLKDEV_ZERO_NOFALLBACK);
if (ret != -EOPNOTSUPP)
return ret;
/*
* The failed call to blkdev_issue_zeroout() advanced the zone write
* pointer. Undo this using a report zone to update the zone write
* pointer to the correct current value.
*/
ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector);
if (ret != 1)
return ret < 0 ? ret : -EIO;
/*
* Retry without BLKDEV_ZERO_NOFALLBACK to force the fallback to a
* regular write with zero-pages.
*/
return blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, 0);
}
EXPORT_SYMBOL_GPL(blk_zone_issue_zeroout);
#ifdef CONFIG_BLK_DEBUG_FS #ifdef CONFIG_BLK_DEBUG_FS
int queue_zone_wplugs_show(void *data, struct seq_file *m) int queue_zone_wplugs_show(void *data, struct seq_file *m)

View File

@ -698,8 +698,6 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
list_add(&rq->queuelist, &per_prio->dispatch); list_add(&rq->queuelist, &per_prio->dispatch);
rq->fifo_time = jiffies; rq->fifo_time = jiffies;
} else { } else {
struct list_head *insert_before;
deadline_add_rq_rb(per_prio, rq); deadline_add_rq_rb(per_prio, rq);
if (rq_mergeable(rq)) { if (rq_mergeable(rq)) {
@ -712,8 +710,7 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
* set expire time and add to fifo list * set expire time and add to fifo list
*/ */
rq->fifo_time = jiffies + dd->fifo_expire[data_dir]; rq->fifo_time = jiffies + dd->fifo_expire[data_dir];
insert_before = &per_prio->fifo_list[data_dir]; list_add_tail(&rq->queuelist, &per_prio->fifo_list[data_dir]);
list_add_tail(&rq->queuelist, insert_before);
} }
} }

View File

@ -163,10 +163,6 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst); struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
const struct hash_prefix *hash_prefix = ictx->hash_prefix; const struct hash_prefix *hash_prefix = ictx->hash_prefix;
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
struct scatterlist in_sg[3], out_sg;
struct crypto_wait cwait;
unsigned int pad_len; unsigned int pad_len;
unsigned int ps_end; unsigned int ps_end;
unsigned int len; unsigned int len;
@ -187,37 +183,25 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
pad_len = ctx->key_size - slen - hash_prefix->size - 1; pad_len = ctx->key_size - slen - hash_prefix->size - 1;
child_req = kmalloc(sizeof(*child_req) + child_reqsize + pad_len,
GFP_KERNEL);
if (!child_req)
return -ENOMEM;
/* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */ /* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */
in_buf = (u8 *)(child_req + 1) + child_reqsize; in_buf = dst;
memmove(in_buf + pad_len + hash_prefix->size, src, slen);
memcpy(in_buf + pad_len, hash_prefix->data, hash_prefix->size);
ps_end = pad_len - 1; ps_end = pad_len - 1;
in_buf[0] = 0x01; in_buf[0] = 0x01;
memset(in_buf + 1, 0xff, ps_end - 1); memset(in_buf + 1, 0xff, ps_end - 1);
in_buf[ps_end] = 0x00; in_buf[ps_end] = 0x00;
/* RFC 8017 sec 8.2.1 step 2 - RSA signature */
crypto_init_wait(&cwait);
sg_init_table(in_sg, 3);
sg_set_buf(&in_sg[0], in_buf, pad_len);
sg_set_buf(&in_sg[1], hash_prefix->data, hash_prefix->size);
sg_set_buf(&in_sg[2], src, slen);
sg_init_one(&out_sg, dst, dlen);
akcipher_request_set_tfm(child_req, ctx->child);
akcipher_request_set_crypt(child_req, in_sg, &out_sg,
ctx->key_size - 1, dlen);
akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait);
err = crypto_akcipher_decrypt(child_req); /* RFC 8017 sec 8.2.1 step 2 - RSA signature */
err = crypto_wait_req(err, &cwait); err = crypto_akcipher_sync_decrypt(ctx->child, in_buf,
if (err) ctx->key_size - 1, in_buf,
ctx->key_size);
if (err < 0)
return err; return err;
len = child_req->dst_len; len = err;
pad_len = ctx->key_size - len; pad_len = ctx->key_size - len;
/* Four billion to one */ /* Four billion to one */
@ -239,8 +223,8 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child); unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
struct akcipher_request *child_req __free(kfree_sensitive) = NULL; struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
struct scatterlist in_sg, out_sg;
struct crypto_wait cwait; struct crypto_wait cwait;
struct scatterlist sg;
unsigned int dst_len; unsigned int dst_len;
unsigned int pos; unsigned int pos;
u8 *out_buf; u8 *out_buf;
@ -259,13 +243,12 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
return -ENOMEM; return -ENOMEM;
out_buf = (u8 *)(child_req + 1) + child_reqsize; out_buf = (u8 *)(child_req + 1) + child_reqsize;
memcpy(out_buf, src, slen);
crypto_init_wait(&cwait); crypto_init_wait(&cwait);
sg_init_one(&in_sg, src, slen); sg_init_one(&sg, out_buf, slen);
sg_init_one(&out_sg, out_buf, ctx->key_size);
akcipher_request_set_tfm(child_req, ctx->child); akcipher_request_set_tfm(child_req, ctx->child);
akcipher_request_set_crypt(child_req, &in_sg, &out_sg, akcipher_request_set_crypt(child_req, &sg, &sg, slen, slen);
slen, ctx->key_size);
akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP, akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait); crypto_req_done, &cwait);

View File

@ -232,8 +232,6 @@ acpi_remove_address_space_handler(acpi_handle device,
/* Now we can delete the handler object */ /* Now we can delete the handler object */
acpi_os_release_mutex(handler_obj->address_space.
context_mutex);
acpi_ut_remove_reference(handler_obj); acpi_ut_remove_reference(handler_obj);
goto unlock_and_exit; goto unlock_and_exit;
} }

View File

@ -454,8 +454,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
if (cmd_rc) if (cmd_rc)
*cmd_rc = -EINVAL; *cmd_rc = -EINVAL;
if (cmd == ND_CMD_CALL) if (cmd == ND_CMD_CALL) {
if (!buf || buf_len < sizeof(*call_pkg))
return -EINVAL;
call_pkg = buf; call_pkg = buf;
}
func = cmd_to_func(nfit_mem, cmd, call_pkg, &family); func = cmd_to_func(nfit_mem, cmd, call_pkg, &family);
if (func < 0) if (func < 0)
return func; return func;

View File

@ -250,6 +250,9 @@ static bool acpi_decode_space(struct resource_win *win,
switch (addr->resource_type) { switch (addr->resource_type) {
case ACPI_MEMORY_RANGE: case ACPI_MEMORY_RANGE:
acpi_dev_memresource_flags(res, len, wp); acpi_dev_memresource_flags(res, len, wp);
if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
res->flags |= IORESOURCE_PREFETCH;
break; break;
case ACPI_IO_RANGE: case ACPI_IO_RANGE:
acpi_dev_ioresource_flags(res, len, iodec, acpi_dev_ioresource_flags(res, len, iodec,
@ -265,9 +268,6 @@ static bool acpi_decode_space(struct resource_win *win,
if (addr->producer_consumer == ACPI_PRODUCER) if (addr->producer_consumer == ACPI_PRODUCER)
res->flags |= IORESOURCE_WINDOW; res->flags |= IORESOURCE_WINDOW;
if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
res->flags |= IORESOURCE_PREFETCH;
return !(res->flags & IORESOURCE_DISABLED); return !(res->flags & IORESOURCE_DISABLED);
} }

View File

@ -348,6 +348,7 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
phy_nodes[phy] = phy_data.np; phy_nodes[phy] = phy_data.np;
cphy_base[phy] = of_iomap(phy_nodes[phy], 0); cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
if (cphy_base[phy] == NULL) { if (cphy_base[phy] == NULL) {
of_node_put(phy_data.np);
return 0; return 0;
} }
phy_count += 1; phy_count += 1;

View File

@ -27,7 +27,8 @@
#include <asm/mshyperv.h> #include <asm/mshyperv.h>
static struct clock_event_device __percpu *hv_clock_event; static struct clock_event_device __percpu *hv_clock_event;
static u64 hv_sched_clock_offset __ro_after_init; /* Note: offset can hold negative values after hibernation. */
static u64 hv_sched_clock_offset __read_mostly;
/* /*
* If false, we're using the old mechanism for stimer0 interrupts * If false, we're using the old mechanism for stimer0 interrupts
@ -470,6 +471,17 @@ static void resume_hv_clock_tsc(struct clocksource *arg)
hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64); hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
} }
/*
* Called during resume from hibernation, from overridden
* x86_platform.restore_sched_clock_state routine. This is to adjust offsets
* used to calculate time for hv tsc page based sched_clock, to account for
* time spent before hibernation.
*/
void hv_adj_sched_clock_offset(u64 offset)
{
hv_sched_clock_offset -= offset;
}
#ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK #ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK
static int hv_cs_enable(struct clocksource *cs) static int hv_cs_enable(struct clocksource *cs)
{ {

View File

@ -192,7 +192,7 @@ static int qm_sqc_dump(struct hisi_qm *qm, char *s, char *name)
down_read(&qm->qps_lock); down_read(&qm->qps_lock);
if (qm->sqc) { if (qm->sqc) {
memcpy(&sqc, qm->sqc + qp_id * sizeof(struct qm_sqc), sizeof(struct qm_sqc)); memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc));
sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK);
sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK);
dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC"); dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC");
@ -229,7 +229,7 @@ static int qm_cqc_dump(struct hisi_qm *qm, char *s, char *name)
down_read(&qm->qps_lock); down_read(&qm->qps_lock);
if (qm->cqc) { if (qm->cqc) {
memcpy(&cqc, qm->cqc + qp_id * sizeof(struct qm_cqc), sizeof(struct qm_cqc)); memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc));
cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK);
cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK);
dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC"); dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC");

View File

@ -1295,6 +1295,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
struct cxl_region_params *p = &cxlr->params; struct cxl_region_params *p = &cxlr->params;
struct cxl_decoder *cxld = cxl_rr->decoder; struct cxl_decoder *cxld = cxl_rr->decoder;
struct cxl_switch_decoder *cxlsd; struct cxl_switch_decoder *cxlsd;
struct cxl_port *iter = port;
u16 eig, peig; u16 eig, peig;
u8 eiw, peiw; u8 eiw, peiw;
@ -1311,16 +1312,26 @@ static int cxl_port_setup_targets(struct cxl_port *port,
cxlsd = to_cxl_switch_decoder(&cxld->dev); cxlsd = to_cxl_switch_decoder(&cxld->dev);
if (cxl_rr->nr_targets_set) { if (cxl_rr->nr_targets_set) {
int i, distance; int i, distance = 1;
struct cxl_region_ref *cxl_rr_iter;
/* /*
* Passthrough decoders impose no distance requirements between * The "distance" between peer downstream ports represents which
* peers * endpoint positions in the region interleave a given port can
* host.
*
* For example, at the root of a hierarchy the distance is
* always 1 as every index targets a different host-bridge. At
* each subsequent switch level those ports map every Nth region
* position where N is the width of the switch == distance.
*/ */
if (cxl_rr->nr_targets == 1) do {
distance = 0; cxl_rr_iter = cxl_rr_load(iter, cxlr);
else distance *= cxl_rr_iter->nr_targets;
distance = p->nr_targets / cxl_rr->nr_targets; iter = to_cxl_port(iter->dev.parent);
} while (!is_cxl_root(iter));
distance *= cxlrd->cxlsd.cxld.interleave_ways;
for (i = 0; i < cxl_rr->nr_targets_set; i++) for (i = 0; i < cxl_rr->nr_targets_set; i++)
if (ep->dport == cxlsd->target[i]) { if (ep->dport == cxlsd->target[i]) {
rc = check_last_peer(cxled, ep, cxl_rr, rc = check_last_peer(cxled, ep, cxl_rr,

View File

@ -836,6 +836,9 @@ static ssize_t rcd_pcie_cap_emit(struct device *dev, u16 offset, char *buf, size
if (!root_dev) if (!root_dev)
return -ENXIO; return -ENXIO;
if (!dport->regs.rcd_pcie_cap)
return -ENXIO;
guard(device)(root_dev); guard(device)(root_dev);
if (!root_dev->driver) if (!root_dev->driver)
return -ENXIO; return -ENXIO;
@ -1032,8 +1035,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc) if (rc)
return rc; return rc;
rc = cxl_pci_ras_unmask(pdev); if (cxl_pci_ras_unmask(pdev))
if (rc)
dev_dbg(&pdev->dev, "No RAS reporting unmasked\n"); dev_dbg(&pdev->dev, "No RAS reporting unmasked\n");
pci_save_state(pdev); pci_save_state(pdev);

View File

@ -3362,36 +3362,24 @@ static bool dct_ecc_enabled(struct amd64_pvt *pvt)
static bool umc_ecc_enabled(struct amd64_pvt *pvt) static bool umc_ecc_enabled(struct amd64_pvt *pvt)
{ {
u8 umc_en_mask = 0, ecc_en_mask = 0;
u16 nid = pvt->mc_node_id;
struct amd64_umc *umc; struct amd64_umc *umc;
u8 ecc_en = 0, i; bool ecc_en = false;
int i;
/* Check whether at least one UMC is enabled: */
for_each_umc(i) { for_each_umc(i) {
umc = &pvt->umc[i]; umc = &pvt->umc[i];
/* Only check enabled UMCs. */ if (umc->sdp_ctrl & UMC_SDP_INIT &&
if (!(umc->sdp_ctrl & UMC_SDP_INIT)) umc->umc_cap_hi & UMC_ECC_ENABLED) {
continue; ecc_en = true;
break;
umc_en_mask |= BIT(i); }
if (umc->umc_cap_hi & UMC_ECC_ENABLED)
ecc_en_mask |= BIT(i);
} }
/* Check whether at least one UMC is enabled: */ edac_dbg(3, "Node %d: DRAM ECC %s.\n", pvt->mc_node_id, (ecc_en ? "enabled" : "disabled"));
if (umc_en_mask)
ecc_en = umc_en_mask == ecc_en_mask;
else
edac_dbg(0, "Node %d: No enabled UMCs.\n", nid);
edac_dbg(3, "Node %d: DRAM ECC %s.\n", nid, (ecc_en ? "enabled" : "disabled")); return ecc_en;
if (!ecc_en)
return false;
else
return true;
} }
static inline void static inline void

View File

@ -187,13 +187,18 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev)
return valid; return valid;
} }
struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, struct ffa_device *
const struct ffa_ops *ops) ffa_device_register(const struct ffa_partition_info *part_info,
const struct ffa_ops *ops)
{ {
int id, ret; int id, ret;
uuid_t uuid;
struct device *dev; struct device *dev;
struct ffa_device *ffa_dev; struct ffa_device *ffa_dev;
if (!part_info)
return NULL;
id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL); id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);
if (id < 0) if (id < 0)
return NULL; return NULL;
@ -210,9 +215,11 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
ffa_dev->id = id; ffa_dev->id = id;
ffa_dev->vm_id = vm_id; ffa_dev->vm_id = part_info->id;
ffa_dev->properties = part_info->properties;
ffa_dev->ops = ops; ffa_dev->ops = ops;
uuid_copy(&ffa_dev->uuid, uuid); import_uuid(&uuid, (u8 *)part_info->uuid);
uuid_copy(&ffa_dev->uuid, &uuid);
ret = device_register(&ffa_dev->dev); ret = device_register(&ffa_dev->dev);
if (ret) { if (ret) {

View File

@ -1387,7 +1387,6 @@ static struct notifier_block ffa_bus_nb = {
static int ffa_setup_partitions(void) static int ffa_setup_partitions(void)
{ {
int count, idx, ret; int count, idx, ret;
uuid_t uuid;
struct ffa_device *ffa_dev; struct ffa_device *ffa_dev;
struct ffa_dev_part_info *info; struct ffa_dev_part_info *info;
struct ffa_partition_info *pbuf, *tpbuf; struct ffa_partition_info *pbuf, *tpbuf;
@ -1406,23 +1405,19 @@ static int ffa_setup_partitions(void)
xa_init(&drv_info->partition_info); xa_init(&drv_info->partition_info);
for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) {
import_uuid(&uuid, (u8 *)tpbuf->uuid);
/* Note that if the UUID will be uuid_null, that will require /* Note that if the UUID will be uuid_null, that will require
* ffa_bus_notifier() to find the UUID of this partition id * ffa_bus_notifier() to find the UUID of this partition id
* with help of ffa_device_match_uuid(). FF-A v1.1 and above * with help of ffa_device_match_uuid(). FF-A v1.1 and above
* provides UUID here for each partition as part of the * provides UUID here for each partition as part of the
* discovery API and the same is passed. * discovery API and the same is passed.
*/ */
ffa_dev = ffa_device_register(&uuid, tpbuf->id, &ffa_drv_ops); ffa_dev = ffa_device_register(tpbuf, &ffa_drv_ops);
if (!ffa_dev) { if (!ffa_dev) {
pr_err("%s: failed to register partition ID 0x%x\n", pr_err("%s: failed to register partition ID 0x%x\n",
__func__, tpbuf->id); __func__, tpbuf->id);
continue; continue;
} }
ffa_dev->properties = tpbuf->properties;
if (drv_info->version > FFA_VERSION_1_0 && if (drv_info->version > FFA_VERSION_1_0 &&
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
ffa_mode_32bit_set(ffa_dev); ffa_mode_32bit_set(ffa_dev);

View File

@ -15,6 +15,7 @@ config IMX_SCMI_BBM_EXT
config IMX_SCMI_MISC_EXT config IMX_SCMI_MISC_EXT
tristate "i.MX SCMI MISC EXTENSION" tristate "i.MX SCMI MISC EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
depends on IMX_SCMI_MISC_DRV
default y if ARCH_MXC default y if ARCH_MXC
help help
This enables i.MX System MISC control logic such as gpio expander This enables i.MX System MISC control logic such as gpio expander

View File

@ -76,10 +76,6 @@ config EFI_ZBOOT
bool "Enable the generic EFI decompressor" bool "Enable the generic EFI decompressor"
depends on EFI_GENERIC_STUB && !ARM depends on EFI_GENERIC_STUB && !ARM
select HAVE_KERNEL_GZIP select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
select HAVE_KERNEL_ZSTD select HAVE_KERNEL_ZSTD
help help
Create the bootable image as an EFI application that carries the Create the bootable image as an EFI application that carries the

View File

@ -75,8 +75,6 @@ static LIST_HEAD(entry_list);
struct esre_attribute { struct esre_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct esre_entry *entry, char *buf); ssize_t (*show)(struct esre_entry *entry, char *buf);
ssize_t (*store)(struct esre_entry *entry,
const char *buf, size_t count);
}; };
static struct esre_entry *to_entry(struct kobject *kobj) static struct esre_entry *to_entry(struct kobject *kobj)

View File

@ -12,22 +12,16 @@ quiet_cmd_copy_and_pad = PAD $@
$(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE $(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE
$(call if_changed,copy_and_pad) $(call if_changed,copy_and_pad)
comp-type-$(CONFIG_KERNEL_GZIP) := gzip
comp-type-$(CONFIG_KERNEL_LZ4) := lz4
comp-type-$(CONFIG_KERNEL_LZMA) := lzma
comp-type-$(CONFIG_KERNEL_LZO) := lzo
comp-type-$(CONFIG_KERNEL_XZ) := xzkern
comp-type-$(CONFIG_KERNEL_ZSTD) := zstd22
# in GZIP, the appended le32 carrying the uncompressed size is part of the # in GZIP, the appended le32 carrying the uncompressed size is part of the
# format, but in other cases, we just append it at the end for convenience, # format, but in other cases, we just append it at the end for convenience,
# causing the original tools to complain when checking image integrity. # causing the original tools to complain when checking image integrity.
# So disregard it when calculating the payload size in the zimage header. comp-type-y := gzip
zboot-method-y := $(comp-type-y)_with_size zboot-method-y := gzip
zboot-size-len-y := 4 zboot-size-len-y := 0
zboot-method-$(CONFIG_KERNEL_GZIP) := gzip comp-type-$(CONFIG_KERNEL_ZSTD) := zstd
zboot-size-len-$(CONFIG_KERNEL_GZIP) := 0 zboot-method-$(CONFIG_KERNEL_ZSTD) := zstd22_with_size
zboot-size-len-$(CONFIG_KERNEL_ZSTD) := 4
$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE $(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
$(call if_changed,$(zboot-method-y)) $(call if_changed,$(zboot-method-y))

View File

@ -25,7 +25,6 @@ config IMX_SCU
config IMX_SCMI_MISC_DRV config IMX_SCMI_MISC_DRV
tristate "IMX SCMI MISC Protocol driver" tristate "IMX SCMI MISC Protocol driver"
depends on IMX_SCMI_MISC_EXT || COMPILE_TEST
default y if ARCH_MXC default y if ARCH_MXC
help help
The System Controller Management Interface firmware (SCMI FW) is The System Controller Management Interface firmware (SCMI FW) is

View File

@ -482,8 +482,9 @@ config GPIO_MT7621
Say yes here to support the Mediatek MT7621 SoC GPIO device. Say yes here to support the Mediatek MT7621 SoC GPIO device.
config GPIO_MVEBU config GPIO_MVEBU
def_bool y bool "Marvell Orion and EBU GPIO support" if COMPILE_TEST
depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST
default PLAT_ORION || ARCH_MVEBU
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select REGMAP_MMIO select REGMAP_MMIO

View File

@ -32,12 +32,14 @@
#define GNR_PINS_PER_REG 32 #define GNR_PINS_PER_REG 32
#define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG) #define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG)
#define GNR_CFG_BAR 0x00 #define GNR_CFG_PADBAR 0x00
#define GNR_CFG_LOCK_OFFSET 0x04 #define GNR_CFG_LOCK_OFFSET 0x04
#define GNR_GPI_STATUS_OFFSET 0x20 #define GNR_GPI_STATUS_OFFSET 0x14
#define GNR_GPI_ENABLE_OFFSET 0x24 #define GNR_GPI_ENABLE_OFFSET 0x24
#define GNR_CFG_DW_RX_MASK GENMASK(25, 22) #define GNR_CFG_DW_HOSTSW_MODE BIT(27)
#define GNR_CFG_DW_RX_MASK GENMASK(23, 22)
#define GNR_CFG_DW_INTSEL_MASK GENMASK(21, 14)
#define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2) #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2)
#define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1) #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1)
#define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0) #define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0)
@ -50,6 +52,7 @@
* struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state
* @gc: GPIO controller interface * @gc: GPIO controller interface
* @reg_base: base address of the GPIO registers * @reg_base: base address of the GPIO registers
* @pad_base: base address of the vGPIO pad configuration registers
* @ro_bitmap: bitmap of read-only pins * @ro_bitmap: bitmap of read-only pins
* @lock: guard the registers * @lock: guard the registers
* @pad_backup: backup of the register state for suspend * @pad_backup: backup of the register state for suspend
@ -57,6 +60,7 @@
struct gnr_gpio { struct gnr_gpio {
struct gpio_chip gc; struct gpio_chip gc;
void __iomem *reg_base; void __iomem *reg_base;
void __iomem *pad_base;
DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS); DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS);
raw_spinlock_t lock; raw_spinlock_t lock;
u32 pad_backup[]; u32 pad_backup[];
@ -65,7 +69,7 @@ struct gnr_gpio {
static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv, static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv,
unsigned int gpio) unsigned int gpio)
{ {
return priv->reg_base + gpio * sizeof(u32); return priv->pad_base + gpio * sizeof(u32);
} }
static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio,
@ -88,6 +92,20 @@ static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio,
return 0; return 0;
} }
static int gnr_gpio_request(struct gpio_chip *gc, unsigned int gpio)
{
struct gnr_gpio *priv = gpiochip_get_data(gc);
u32 dw;
dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio));
if (!(dw & GNR_CFG_DW_HOSTSW_MODE)) {
dev_warn(gc->parent, "GPIO %u is not owned by host", gpio);
return -EBUSY;
}
return 0;
}
static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio) static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{ {
const struct gnr_gpio *priv = gpiochip_get_data(gc); const struct gnr_gpio *priv = gpiochip_get_data(gc);
@ -139,6 +157,7 @@ static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, in
static const struct gpio_chip gnr_gpio_chip = { static const struct gpio_chip gnr_gpio_chip = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.request = gnr_gpio_request,
.get = gnr_gpio_get, .get = gnr_gpio_get,
.set = gnr_gpio_set, .set = gnr_gpio_set,
.get_direction = gnr_gpio_get_direction, .get_direction = gnr_gpio_get_direction,
@ -166,7 +185,7 @@ static void gnr_gpio_irq_ack(struct irq_data *d)
guard(raw_spinlock_irqsave)(&priv->lock); guard(raw_spinlock_irqsave)(&priv->lock);
reg = readl(addr); reg = readl(addr);
reg &= ~BIT(bit_idx); reg |= BIT(bit_idx);
writel(reg, addr); writel(reg, addr);
} }
@ -209,10 +228,18 @@ static void gnr_gpio_irq_unmask(struct irq_data *d)
static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
irq_hw_number_t pin = irqd_to_hwirq(d); struct gnr_gpio *priv = gpiochip_get_data(gc);
u32 mask = GNR_CFG_DW_RX_MASK; irq_hw_number_t hwirq = irqd_to_hwirq(d);
u32 reg;
u32 set; u32 set;
/* Allow interrupts only if Interrupt Select field is non-zero */
reg = readl(gnr_gpio_get_padcfg_addr(priv, hwirq));
if (!(reg & GNR_CFG_DW_INTSEL_MASK)) {
dev_dbg(gc->parent, "GPIO %lu cannot be used as IRQ", hwirq);
return -EPERM;
}
/* Falling edge and level low triggers not supported by the GPIO controller */ /* Falling edge and level low triggers not supported by the GPIO controller */
switch (type) { switch (type) {
case IRQ_TYPE_NONE: case IRQ_TYPE_NONE:
@ -230,10 +257,11 @@ static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL; return -EINVAL;
} }
return gnr_gpio_configure_line(gc, pin, mask, set); return gnr_gpio_configure_line(gc, hwirq, GNR_CFG_DW_RX_MASK, set);
} }
static const struct irq_chip gnr_gpio_irq_chip = { static const struct irq_chip gnr_gpio_irq_chip = {
.name = "gpio-graniterapids",
.irq_ack = gnr_gpio_irq_ack, .irq_ack = gnr_gpio_irq_ack,
.irq_mask = gnr_gpio_irq_mask, .irq_mask = gnr_gpio_irq_mask,
.irq_unmask = gnr_gpio_irq_unmask, .irq_unmask = gnr_gpio_irq_unmask,
@ -291,6 +319,7 @@ static int gnr_gpio_probe(struct platform_device *pdev)
struct gnr_gpio *priv; struct gnr_gpio *priv;
void __iomem *regs; void __iomem *regs;
int irq, ret; int irq, ret;
u32 offset;
priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL); priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL);
if (!priv) if (!priv)
@ -302,6 +331,10 @@ static int gnr_gpio_probe(struct platform_device *pdev)
if (IS_ERR(regs)) if (IS_ERR(regs))
return PTR_ERR(regs); return PTR_ERR(regs);
priv->reg_base = regs;
offset = readl(priv->reg_base + GNR_CFG_PADBAR);
priv->pad_base = priv->reg_base + offset;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
return irq; return irq;
@ -311,8 +344,6 @@ static int gnr_gpio_probe(struct platform_device *pdev)
if (ret) if (ret)
return dev_err_probe(dev, ret, "failed to request interrupt\n"); return dev_err_probe(dev, ret, "failed to request interrupt\n");
priv->reg_base = regs + readl(regs + GNR_CFG_BAR);
gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET, gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET,
priv->ro_bitmap); priv->ro_bitmap);
@ -324,7 +355,6 @@ static int gnr_gpio_probe(struct platform_device *pdev)
girq = &priv->gc.irq; girq = &priv->gc.irq;
gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip); gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip);
girq->chip->name = dev_name(dev);
girq->parent_handler = NULL; girq->parent_handler = NULL;
girq->num_parents = 0; girq->num_parents = 0;
girq->parents = NULL; girq->parents = NULL;

View File

@ -3,6 +3,9 @@
* GPIO library for the ACCES IDIO-16 family * GPIO library for the ACCES IDIO-16 family
* Copyright (C) 2022 William Breathitt Gray * Copyright (C) 2022 William Breathitt Gray
*/ */
#define DEFAULT_SYMBOL_NAMESPACE "GPIO_IDIO_16"
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
@ -14,8 +17,6 @@
#include "gpio-idio-16.h" #include "gpio-idio-16.h"
#define DEFAULT_SYMBOL_NAMESPACE "GPIO_IDIO_16"
#define IDIO_16_DAT_BASE 0x0 #define IDIO_16_DAT_BASE 0x0
#define IDIO_16_OUT_BASE IDIO_16_DAT_BASE #define IDIO_16_OUT_BASE IDIO_16_DAT_BASE
#define IDIO_16_IN_BASE (IDIO_16_DAT_BASE + 1) #define IDIO_16_IN_BASE (IDIO_16_DAT_BASE + 1)

View File

@ -82,9 +82,9 @@ static int ljca_gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id,
int ret; int ret;
mutex_lock(&ljca_gpio->trans_lock); mutex_lock(&ljca_gpio->trans_lock);
packet->num = 1;
packet->item[0].index = gpio_id; packet->item[0].index = gpio_id;
packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id]; packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id];
packet->num = 1;
ret = ljca_transfer(ljca_gpio->ljca, LJCA_GPIO_CONFIG, (u8 *)packet, ret = ljca_transfer(ljca_gpio->ljca, LJCA_GPIO_CONFIG, (u8 *)packet,
struct_size(packet, item, packet->num), NULL, 0); struct_size(packet, item, packet->num), NULL, 0);

View File

@ -1801,13 +1801,18 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket) if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket)
return -EINVAL; return -EINVAL;
/* Make sure VRAM is allocated contigiously */
(*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); if ((*bo)->tbo.resource->mem_type == TTM_PL_VRAM &&
for (i = 0; i < (*bo)->placement.num_placement; i++) !((*bo)->tbo.resource->placement & TTM_PL_FLAG_CONTIGUOUS)) {
(*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS;
r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains);
if (r) for (i = 0; i < (*bo)->placement.num_placement; i++)
return r; (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS;
r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx);
if (r)
return r;
}
return amdgpu_ttm_alloc_gart(&(*bo)->tbo); return amdgpu_ttm_alloc_gart(&(*bo)->tbo);
} }

View File

@ -145,7 +145,7 @@ const char *amdgpu_asic_name[] = {
"LAST", "LAST",
}; };
#define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMDGPU_MAX_IP_NUM, 0) #define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMD_IP_BLOCK_TYPE_NUM - 1, 0)
/* /*
* Default init level where all blocks are expected to be initialized. This is * Default init level where all blocks are expected to be initialized. This is
* the level of initialization expected by default and also after a full reset * the level of initialization expected by default and also after a full reset

View File

@ -551,6 +551,8 @@ static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo)
for (i = 0; i < abo->placement.num_placement; ++i) { for (i = 0; i < abo->placement.num_placement; ++i) {
abo->placements[i].fpfn = 0 >> PAGE_SHIFT; abo->placements[i].fpfn = 0 >> PAGE_SHIFT;
abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
if (abo->placements[i].mem_type == TTM_PL_VRAM)
abo->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS;
} }
} }

View File

@ -674,12 +674,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping &&
ring->funcs->emit_wreg; ring->funcs->emit_wreg;
if (adev->gfx.enable_cleaner_shader && if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync &&
ring->funcs->emit_cleaner_shader && !(job->enforce_isolation && !job->vmid))
job->enforce_isolation)
ring->funcs->emit_cleaner_shader(ring);
if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync)
return 0; return 0;
amdgpu_ring_ib_begin(ring); amdgpu_ring_ib_begin(ring);
@ -690,6 +686,11 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
if (need_pipe_sync) if (need_pipe_sync)
amdgpu_ring_emit_pipeline_sync(ring); amdgpu_ring_emit_pipeline_sync(ring);
if (adev->gfx.enable_cleaner_shader &&
ring->funcs->emit_cleaner_shader &&
job->enforce_isolation)
ring->funcs->emit_cleaner_shader(ring);
if (vm_flush_needed) { if (vm_flush_needed) {
trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr); trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr);
amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr); amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr);

View File

@ -45,6 +45,8 @@ MODULE_FIRMWARE("amdgpu/gc_9_4_3_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_9_4_4_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_4_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_9_4_3_rlc.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_3_rlc.bin");
MODULE_FIRMWARE("amdgpu/gc_9_4_4_rlc.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_4_rlc.bin");
MODULE_FIRMWARE("amdgpu/gc_9_4_3_sjt_mec.bin");
MODULE_FIRMWARE("amdgpu/gc_9_4_4_sjt_mec.bin");
#define GFX9_MEC_HPD_SIZE 4096 #define GFX9_MEC_HPD_SIZE 4096
#define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
@ -574,8 +576,12 @@ static int gfx_v9_4_3_init_cp_compute_microcode(struct amdgpu_device *adev,
{ {
int err; int err;
err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, if (amdgpu_sriov_vf(adev))
"amdgpu/%s_mec.bin", chip_name); err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw,
"amdgpu/%s_sjt_mec.bin", chip_name);
else
err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw,
"amdgpu/%s_mec.bin", chip_name);
if (err) if (err)
goto out; goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1);

View File

@ -1288,7 +1288,7 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
struct amdgpu_job *job, struct amdgpu_job *job,
struct amdgpu_ib *ib) struct amdgpu_ib *ib)
{ {
struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); struct amdgpu_ring *ring = amdgpu_job_ring(job);
unsigned i; unsigned i;
/* No patching necessary for the first instance */ /* No patching necessary for the first instance */

View File

@ -1423,6 +1423,7 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,
static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
bool cache_line_size_missing,
struct kfd_gpu_cache_info *pcache_info) struct kfd_gpu_cache_info *pcache_info)
{ {
struct amdgpu_device *adev = kdev->adev; struct amdgpu_device *adev = kdev->adev;
@ -1437,6 +1438,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_tcp_per_wpg / 2; pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_tcp_per_wpg / 2;
pcache_info[i].cache_line_size = adev->gfx.config.gc_tcp_cache_line_size; pcache_info[i].cache_line_size = adev->gfx.config.gc_tcp_cache_line_size;
if (cache_line_size_missing && !pcache_info[i].cache_line_size)
pcache_info[i].cache_line_size = 128;
i++; i++;
} }
/* Scalar L1 Instruction Cache per SQC */ /* Scalar L1 Instruction Cache per SQC */
@ -1449,6 +1452,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2;
pcache_info[i].cache_line_size = adev->gfx.config.gc_instruction_cache_line_size; pcache_info[i].cache_line_size = adev->gfx.config.gc_instruction_cache_line_size;
if (cache_line_size_missing && !pcache_info[i].cache_line_size)
pcache_info[i].cache_line_size = 128;
i++; i++;
} }
/* Scalar L1 Data Cache per SQC */ /* Scalar L1 Data Cache per SQC */
@ -1460,6 +1465,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2;
pcache_info[i].cache_line_size = adev->gfx.config.gc_scalar_data_cache_line_size; pcache_info[i].cache_line_size = adev->gfx.config.gc_scalar_data_cache_line_size;
if (cache_line_size_missing && !pcache_info[i].cache_line_size)
pcache_info[i].cache_line_size = 64;
i++; i++;
} }
/* GL1 Data Cache per SA */ /* GL1 Data Cache per SA */
@ -1472,7 +1479,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_DATA_CACHE |
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh;
pcache_info[i].cache_line_size = 0; if (cache_line_size_missing)
pcache_info[i].cache_line_size = 128;
i++; i++;
} }
/* L2 Data Cache per GPU (Total Tex Cache) */ /* L2 Data Cache per GPU (Total Tex Cache) */
@ -1484,6 +1492,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh;
pcache_info[i].cache_line_size = adev->gfx.config.gc_tcc_cache_line_size; pcache_info[i].cache_line_size = adev->gfx.config.gc_tcc_cache_line_size;
if (cache_line_size_missing && !pcache_info[i].cache_line_size)
pcache_info[i].cache_line_size = 128;
i++; i++;
} }
/* L3 Data Cache per GPU */ /* L3 Data Cache per GPU */
@ -1494,7 +1504,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev,
CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_DATA_CACHE |
CRAT_CACHE_FLAGS_SIMD_CACHE); CRAT_CACHE_FLAGS_SIMD_CACHE);
pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh;
pcache_info[i].cache_line_size = 0; pcache_info[i].cache_line_size = 64;
i++; i++;
} }
return i; return i;
@ -1569,6 +1579,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev,
int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pcache_info) int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pcache_info)
{ {
int num_of_cache_types = 0; int num_of_cache_types = 0;
bool cache_line_size_missing = false;
switch (kdev->adev->asic_type) { switch (kdev->adev->asic_type) {
case CHIP_KAVERI: case CHIP_KAVERI:
@ -1692,10 +1703,17 @@ int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pc
case IP_VERSION(11, 5, 0): case IP_VERSION(11, 5, 0):
case IP_VERSION(11, 5, 1): case IP_VERSION(11, 5, 1):
case IP_VERSION(11, 5, 2): case IP_VERSION(11, 5, 2):
/* Cacheline size not available in IP discovery for gc11.
* kfd_fill_gpu_cache_info_from_gfx_config to hard code it
*/
cache_line_size_missing = true;
fallthrough;
case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 0):
case IP_VERSION(12, 0, 1): case IP_VERSION(12, 0, 1):
num_of_cache_types = num_of_cache_types =
kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd, *pcache_info); kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd,
cache_line_size_missing,
*pcache_info);
break; break;
default: default:
*pcache_info = dummy_cache_info; *pcache_info = dummy_cache_info;

View File

@ -207,6 +207,21 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
if (!down_read_trylock(&adev->reset_domain->sem)) if (!down_read_trylock(&adev->reset_domain->sem))
return -EIO; return -EIO;
if (!pdd->proc_ctx_cpu_ptr) {
r = amdgpu_amdkfd_alloc_gtt_mem(adev,
AMDGPU_MES_PROC_CTX_SIZE,
&pdd->proc_ctx_bo,
&pdd->proc_ctx_gpu_addr,
&pdd->proc_ctx_cpu_ptr,
false);
if (r) {
dev_err(adev->dev,
"failed to allocate process context bo\n");
return r;
}
memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
}
memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input)); memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input));
queue_input.process_id = qpd->pqm->process->pasid; queue_input.process_id = qpd->pqm->process->pasid;
queue_input.page_table_base_addr = qpd->page_table_base; queue_input.page_table_base_addr = qpd->page_table_base;

View File

@ -306,7 +306,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
spage = migrate_pfn_to_page(migrate->src[i]); spage = migrate_pfn_to_page(migrate->src[i]);
if (spage && !is_zone_device_page(spage)) { if (spage && !is_zone_device_page(spage)) {
src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE, src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
DMA_TO_DEVICE); DMA_BIDIRECTIONAL);
r = dma_mapping_error(dev, src[i]); r = dma_mapping_error(dev, src[i]);
if (r) { if (r) {
dev_err(dev, "%s: fail %d dma_map_page\n", dev_err(dev, "%s: fail %d dma_map_page\n",
@ -629,7 +629,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
goto out_oom; goto out_oom;
} }
dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_FROM_DEVICE); dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
r = dma_mapping_error(dev, dst[i]); r = dma_mapping_error(dev, dst[i]);
if (r) { if (r) {
dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r); dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r);

View File

@ -1076,7 +1076,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
kfd_free_process_doorbells(pdd->dev->kfd, pdd); kfd_free_process_doorbells(pdd->dev->kfd, pdd);
if (pdd->dev->kfd->shared_resources.enable_mes) if (pdd->dev->kfd->shared_resources.enable_mes &&
pdd->proc_ctx_cpu_ptr)
amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev,
&pdd->proc_ctx_bo); &pdd->proc_ctx_bo);
/* /*
@ -1608,7 +1609,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
struct kfd_process *p) struct kfd_process *p)
{ {
struct kfd_process_device *pdd = NULL; struct kfd_process_device *pdd = NULL;
int retval = 0;
if (WARN_ON_ONCE(p->n_pdds >= MAX_GPU_INSTANCE)) if (WARN_ON_ONCE(p->n_pdds >= MAX_GPU_INSTANCE))
return NULL; return NULL;
@ -1632,21 +1632,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
pdd->user_gpu_id = dev->id; pdd->user_gpu_id = dev->id;
atomic64_set(&pdd->evict_duration_counter, 0); atomic64_set(&pdd->evict_duration_counter, 0);
if (dev->kfd->shared_resources.enable_mes) {
retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev,
AMDGPU_MES_PROC_CTX_SIZE,
&pdd->proc_ctx_bo,
&pdd->proc_ctx_gpu_addr,
&pdd->proc_ctx_cpu_ptr,
false);
if (retval) {
dev_err(dev->adev->dev,
"failed to allocate process context bo\n");
goto err_free_pdd;
}
memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
}
p->pdds[p->n_pdds++] = pdd; p->pdds[p->n_pdds++] = pdd;
if (kfd_dbg_is_per_vmid_supported(pdd->dev)) if (kfd_dbg_is_per_vmid_supported(pdd->dev))
pdd->spi_dbg_override = pdd->dev->kfd2kgd->disable_debug_trap( pdd->spi_dbg_override = pdd->dev->kfd2kgd->disable_debug_trap(
@ -1658,10 +1643,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
idr_init(&pdd->alloc_idr); idr_init(&pdd->alloc_idr);
return pdd; return pdd;
err_free_pdd:
kfree(pdd);
return NULL;
} }
/** /**

View File

@ -212,13 +212,17 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm,
void pqm_uninit(struct process_queue_manager *pqm) void pqm_uninit(struct process_queue_manager *pqm)
{ {
struct process_queue_node *pqn, *next; struct process_queue_node *pqn, *next;
struct kfd_process_device *pdd;
list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) { list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
if (pqn->q) { if (pqn->q) {
pdd = kfd_get_process_device_data(pqn->q->device, pqm->process); struct kfd_process_device *pdd = kfd_get_process_device_data(pqn->q->device,
kfd_queue_unref_bo_vas(pdd, &pqn->q->properties); pqm->process);
kfd_queue_release_buffers(pdd, &pqn->q->properties); if (pdd) {
kfd_queue_unref_bo_vas(pdd, &pqn->q->properties);
kfd_queue_release_buffers(pdd, &pqn->q->properties);
} else {
WARN_ON(!pdd);
}
pqm_clean_queue_resource(pqm, pqn); pqm_clean_queue_resource(pqm, pqn);
} }

View File

@ -164,6 +164,7 @@ enum amd_pp_task {
}; };
enum PP_SMC_POWER_PROFILE { enum PP_SMC_POWER_PROFILE {
PP_SMC_POWER_PROFILE_UNKNOWN = -1,
PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0, PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0,
PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1, PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1,
PP_SMC_POWER_PROFILE_POWERSAVING = 0x2, PP_SMC_POWER_PROFILE_POWERSAVING = 0x2,

View File

@ -764,6 +764,7 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block)
smu->smu_baco.platform_support = false; smu->smu_baco.platform_support = false;
smu->smu_baco.maco_support = false; smu->smu_baco.maco_support = false;
smu->user_dpm_profile.fan_mode = -1; smu->user_dpm_profile.fan_mode = -1;
smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN;
mutex_init(&smu->message_lock); mutex_init(&smu->message_lock);
@ -1248,6 +1249,21 @@ static bool smu_is_workload_profile_available(struct smu_context *smu,
return smu->workload_map && smu->workload_map[profile].valid_mapping; return smu->workload_map && smu->workload_map[profile].valid_mapping;
} }
static void smu_init_power_profile(struct smu_context *smu)
{
if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) {
if (smu->is_apu ||
!smu_is_workload_profile_available(
smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
smu->power_profile_mode =
PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
else
smu->power_profile_mode =
PP_SMC_POWER_PROFILE_FULLSCREEN3D;
}
smu_power_profile_mode_get(smu, smu->power_profile_mode);
}
static int smu_sw_init(struct amdgpu_ip_block *ip_block) static int smu_sw_init(struct amdgpu_ip_block *ip_block)
{ {
struct amdgpu_device *adev = ip_block->adev; struct amdgpu_device *adev = ip_block->adev;
@ -1269,13 +1285,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
atomic_set(&smu->smu_power.power_gate.vpe_gated, 1); atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1); atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
if (smu->is_apu || smu_init_power_profile(smu);
!smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D))
smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
else
smu->power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
smu_power_profile_mode_get(smu, smu->power_profile_mode);
smu->display_config = &adev->pm.pm_display_cfg; smu->display_config = &adev->pm.pm_display_cfg;
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;

View File

@ -2810,4 +2810,5 @@ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
smu->workload_map = smu_v13_0_7_workload_map; smu->workload_map = smu_v13_0_7_workload_map;
smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION;
smu_v13_0_set_smu_mailbox_registers(smu); smu_v13_0_set_smu_mailbox_registers(smu);
smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
} }

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