Merge remote-tracking branch 'common/android-4.9' into android-hikey-linaro-4.9-aosp
This commit is contained in:
@@ -11,24 +11,56 @@ in AArch64 Linux.
|
||||
The kernel configures the translation tables so that translations made
|
||||
via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of
|
||||
the virtual address ignored by the translation hardware. This frees up
|
||||
this byte for application use, with the following caveats:
|
||||
this byte for application use.
|
||||
|
||||
(1) The kernel requires that all user addresses passed to EL1
|
||||
are tagged with tag 0x00. This means that any syscall
|
||||
parameters containing user virtual addresses *must* have
|
||||
their top byte cleared before trapping to the kernel.
|
||||
|
||||
(2) Non-zero tags are not preserved when delivering signals.
|
||||
This means that signal handlers in applications making use
|
||||
of tags cannot rely on the tag information for user virtual
|
||||
addresses being maintained for fields inside siginfo_t.
|
||||
One exception to this rule is for signals raised in response
|
||||
to watchpoint debug exceptions, where the tag information
|
||||
will be preserved.
|
||||
Passing tagged addresses to the kernel
|
||||
--------------------------------------
|
||||
|
||||
(3) Special care should be taken when using tagged pointers,
|
||||
since it is likely that C compilers will not hazard two
|
||||
virtual addresses differing only in the upper byte.
|
||||
All interpretation of userspace memory addresses by the kernel assumes
|
||||
an address tag of 0x00.
|
||||
|
||||
This includes, but is not limited to, addresses found in:
|
||||
|
||||
- pointer arguments to system calls, including pointers in structures
|
||||
passed to system calls,
|
||||
|
||||
- the stack pointer (sp), e.g. when interpreting it to deliver a
|
||||
signal,
|
||||
|
||||
- the frame pointer (x29) and frame records, e.g. when interpreting
|
||||
them to generate a backtrace or call graph.
|
||||
|
||||
Using non-zero address tags in any of these locations may result in an
|
||||
error code being returned, a (fatal) signal being raised, or other modes
|
||||
of failure.
|
||||
|
||||
For these reasons, passing non-zero address tags to the kernel via
|
||||
system calls is forbidden, and using a non-zero address tag for sp is
|
||||
strongly discouraged.
|
||||
|
||||
Programs maintaining a frame pointer and frame records that use non-zero
|
||||
address tags may suffer impaired or inaccurate debug and profiling
|
||||
visibility.
|
||||
|
||||
|
||||
Preserving tags
|
||||
---------------
|
||||
|
||||
Non-zero tags are not preserved when delivering signals. This means that
|
||||
signal handlers in applications making use of tags cannot rely on the
|
||||
tag information for user virtual addresses being maintained for fields
|
||||
inside siginfo_t. One exception to this rule is for signals raised in
|
||||
response to watchpoint debug exceptions, where the tag information will
|
||||
be preserved.
|
||||
|
||||
The architecture prevents the use of a tagged PC, so the upper byte will
|
||||
be set to a sign-extension of bit 55 on exception return.
|
||||
|
||||
|
||||
Other considerations
|
||||
--------------------
|
||||
|
||||
Special care should be taken when using tagged pointers, since it is
|
||||
likely that C compilers will not hazard two virtual addresses differing
|
||||
only in the upper byte.
|
||||
|
||||
@@ -308,6 +308,12 @@ Color Management Properties
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
|
||||
:export:
|
||||
|
||||
Explicit Fencing Properties
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
|
||||
:doc: explicit fencing properties
|
||||
|
||||
Existing KMS Properties
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 29
|
||||
SUBLEVEL = 30
|
||||
EXTRAVERSION =
|
||||
NAME = Roaring Lionus
|
||||
|
||||
|
||||
@@ -97,4 +97,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
||||
@@ -1188,8 +1188,10 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
|
||||
if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
|
||||
return -EFAULT;
|
||||
|
||||
err = 0;
|
||||
err |= put_user(status, ustatus);
|
||||
err = put_user(status, ustatus);
|
||||
if (ret < 0)
|
||||
return err ? err : ret;
|
||||
|
||||
err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
|
||||
err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
|
||||
err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
|
||||
|
||||
@@ -162,9 +162,10 @@
|
||||
};
|
||||
|
||||
adc0: adc@f8018000 {
|
||||
atmel,adc-vref = <3300>;
|
||||
atmel,adc-channels-used = <0xfe>;
|
||||
pinctrl-0 = <
|
||||
&pinctrl_adc0_adtrg
|
||||
&pinctrl_adc0_ad0
|
||||
&pinctrl_adc0_ad1
|
||||
&pinctrl_adc0_ad2
|
||||
&pinctrl_adc0_ad3
|
||||
@@ -172,8 +173,6 @@
|
||||
&pinctrl_adc0_ad5
|
||||
&pinctrl_adc0_ad6
|
||||
&pinctrl_adc0_ad7
|
||||
&pinctrl_adc0_ad8
|
||||
&pinctrl_adc0_ad9
|
||||
>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -12,23 +12,6 @@
|
||||
model = "Freescale i.MX6 SoloX SDB RevB Board";
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
996000 1250000
|
||||
792000 1175000
|
||||
396000 1175000
|
||||
198000 1175000
|
||||
>;
|
||||
fsl,soc-operating-points = <
|
||||
/* ARM kHz SOC uV */
|
||||
996000 1250000
|
||||
792000 1175000
|
||||
396000 1175000
|
||||
198000 1175000
|
||||
>;
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
clock-frequency = <100000>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
@@ -569,6 +569,7 @@
|
||||
regulator-name = "+3VS,vdd_pnl";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
gpio = <&gpio TEGRA_GPIO(A, 4) GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,8 @@ void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table);
|
||||
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
|
||||
|
||||
@@ -18,13 +18,18 @@ enum {
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mod_plt_sec {
|
||||
struct elf32_shdr *plt;
|
||||
int plt_count;
|
||||
};
|
||||
|
||||
struct mod_arch_specific {
|
||||
#ifdef CONFIG_ARM_UNWIND
|
||||
struct unwind_table *unwind[ARM_SEC_MAX];
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_MODULE_PLTS
|
||||
struct elf32_shdr *plt;
|
||||
int plt_count;
|
||||
struct mod_plt_sec core;
|
||||
struct mod_plt_sec init;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
* Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -31,9 +31,17 @@ struct plt_entries {
|
||||
u32 lit[PLT_ENT_COUNT];
|
||||
};
|
||||
|
||||
static bool in_init(const struct module *mod, unsigned long loc)
|
||||
{
|
||||
return loc - (u32)mod->init_layout.base < mod->init_layout.size;
|
||||
}
|
||||
|
||||
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
|
||||
{
|
||||
struct plt_entries *plt = (struct plt_entries *)mod->arch.plt->sh_addr;
|
||||
struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
|
||||
&mod->arch.init;
|
||||
|
||||
struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
|
||||
int idx = 0;
|
||||
|
||||
/*
|
||||
@@ -41,9 +49,9 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
|
||||
* relocations are sorted, this will be the last entry we allocated.
|
||||
* (if one exists).
|
||||
*/
|
||||
if (mod->arch.plt_count > 0) {
|
||||
plt += (mod->arch.plt_count - 1) / PLT_ENT_COUNT;
|
||||
idx = (mod->arch.plt_count - 1) % PLT_ENT_COUNT;
|
||||
if (pltsec->plt_count > 0) {
|
||||
plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
|
||||
idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
|
||||
|
||||
if (plt->lit[idx] == val)
|
||||
return (u32)&plt->ldr[idx];
|
||||
@@ -53,8 +61,8 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
|
||||
plt++;
|
||||
}
|
||||
|
||||
mod->arch.plt_count++;
|
||||
BUG_ON(mod->arch.plt_count * PLT_ENT_SIZE > mod->arch.plt->sh_size);
|
||||
pltsec->plt_count++;
|
||||
BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size);
|
||||
|
||||
if (!idx)
|
||||
/* Populate a new set of entries */
|
||||
@@ -129,7 +137,7 @@ static bool duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num)
|
||||
|
||||
/* Count how many PLT entries we may need */
|
||||
static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
|
||||
const Elf32_Rel *rel, int num)
|
||||
const Elf32_Rel *rel, int num, Elf32_Word dstidx)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
const Elf32_Sym *s;
|
||||
@@ -144,13 +152,17 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
|
||||
case R_ARM_THM_JUMP24:
|
||||
/*
|
||||
* We only have to consider branch targets that resolve
|
||||
* to undefined symbols. This is not simply a heuristic,
|
||||
* it is a fundamental limitation, since the PLT itself
|
||||
* is part of the module, and needs to be within range
|
||||
* as well, so modules can never grow beyond that limit.
|
||||
* to symbols that are defined in a different section.
|
||||
* This is not simply a heuristic, it is a fundamental
|
||||
* limitation, since there is no guaranteed way to emit
|
||||
* PLT entries sufficiently close to the branch if the
|
||||
* section size exceeds the range of a branch
|
||||
* instruction. So ignore relocations against defined
|
||||
* symbols if they live in the same section as the
|
||||
* relocation target.
|
||||
*/
|
||||
s = syms + ELF32_R_SYM(rel[i].r_info);
|
||||
if (s->st_shndx != SHN_UNDEF)
|
||||
if (s->st_shndx == dstidx)
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -161,7 +173,12 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
|
||||
* So we need to support them, but there is no need to
|
||||
* take them into consideration when trying to optimize
|
||||
* this code. So let's only check for duplicates when
|
||||
* the addend is zero.
|
||||
* the addend is zero. (Note that calls into the core
|
||||
* module via init PLT entries could involve section
|
||||
* relative symbol references with non-zero addends, for
|
||||
* which we may end up emitting duplicates, but the init
|
||||
* PLT is released along with the rest of the .init
|
||||
* region as soon as module loading completes.)
|
||||
*/
|
||||
if (!is_zero_addend_relocation(base, rel + i) ||
|
||||
!duplicate_rel(base, rel, i))
|
||||
@@ -174,7 +191,8 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
|
||||
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
unsigned long plts = 0;
|
||||
unsigned long core_plts = 0;
|
||||
unsigned long init_plts = 0;
|
||||
Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
|
||||
Elf32_Sym *syms = NULL;
|
||||
|
||||
@@ -184,13 +202,15 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
*/
|
||||
for (s = sechdrs; s < sechdrs_end; ++s) {
|
||||
if (strcmp(".plt", secstrings + s->sh_name) == 0)
|
||||
mod->arch.plt = s;
|
||||
mod->arch.core.plt = s;
|
||||
else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
|
||||
mod->arch.init.plt = s;
|
||||
else if (s->sh_type == SHT_SYMTAB)
|
||||
syms = (Elf32_Sym *)s->sh_addr;
|
||||
}
|
||||
|
||||
if (!mod->arch.plt) {
|
||||
pr_err("%s: module PLT section missing\n", mod->name);
|
||||
if (!mod->arch.core.plt || !mod->arch.init.plt) {
|
||||
pr_err("%s: module PLT section(s) missing\n", mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if (!syms) {
|
||||
@@ -213,16 +233,29 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
/* sort by type and symbol index */
|
||||
sort(rels, numrels, sizeof(Elf32_Rel), cmp_rel, NULL);
|
||||
|
||||
plts += count_plts(syms, dstsec->sh_addr, rels, numrels);
|
||||
if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0)
|
||||
core_plts += count_plts(syms, dstsec->sh_addr, rels,
|
||||
numrels, s->sh_info);
|
||||
else
|
||||
init_plts += count_plts(syms, dstsec->sh_addr, rels,
|
||||
numrels, s->sh_info);
|
||||
}
|
||||
|
||||
mod->arch.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.plt->sh_size = round_up(plts * PLT_ENT_SIZE,
|
||||
sizeof(struct plt_entries));
|
||||
mod->arch.plt_count = 0;
|
||||
mod->arch.core.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.core.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.core.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
|
||||
sizeof(struct plt_entries));
|
||||
mod->arch.core.plt_count = 0;
|
||||
|
||||
pr_debug("%s: plt=%x\n", __func__, mod->arch.plt->sh_size);
|
||||
mod->arch.init.plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.init.plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
|
||||
sizeof(struct plt_entries));
|
||||
mod->arch.init.plt_count = 0;
|
||||
|
||||
pr_debug("%s: plt=%x, init.plt=%x\n", __func__,
|
||||
mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
SECTIONS {
|
||||
.plt : { BYTE(0) }
|
||||
.init.plt : { BYTE(0) }
|
||||
}
|
||||
|
||||
+59
-18
@@ -93,12 +93,6 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
|
||||
{
|
||||
/*
|
||||
@@ -514,12 +508,7 @@ static int emulate_cp15(struct kvm_vcpu *vcpu,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
static struct coproc_params decode_64bit_hsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct coproc_params params;
|
||||
|
||||
@@ -533,9 +522,38 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf;
|
||||
params.CRm = 0;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
struct coproc_params params = decode_64bit_hsr(vcpu);
|
||||
|
||||
return emulate_cp15(vcpu, ¶ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp14_64 -- handles a mrrc/mcrr trap on a guest CP14 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
struct coproc_params params = decode_64bit_hsr(vcpu);
|
||||
|
||||
/* raz_wi cp14 */
|
||||
pm_fake(vcpu, ¶ms, NULL);
|
||||
|
||||
/* handled */
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void reset_coproc_regs(struct kvm_vcpu *vcpu,
|
||||
const struct coproc_reg *table, size_t num)
|
||||
{
|
||||
@@ -546,12 +564,7 @@ static void reset_coproc_regs(struct kvm_vcpu *vcpu,
|
||||
table[i].reset(vcpu, &table[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct coproc_params params;
|
||||
|
||||
@@ -565,9 +578,37 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
params.Op2 = (kvm_vcpu_get_hsr(vcpu) >> 17) & 0x7;
|
||||
params.Rt2 = 0;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
struct coproc_params params = decode_32bit_hsr(vcpu);
|
||||
return emulate_cp15(vcpu, ¶ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_cp14_32 -- handles a mrc/mcr trap on a guest CP14 access
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The kvm_run struct
|
||||
*/
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
struct coproc_params params = decode_32bit_hsr(vcpu);
|
||||
|
||||
/* raz_wi cp14 */
|
||||
pm_fake(vcpu, ¶ms, NULL);
|
||||
|
||||
/* handled */
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Userspace API
|
||||
*****************************************************************************/
|
||||
|
||||
@@ -83,9 +83,9 @@ static exit_handle_fn arm_exit_handlers[] = {
|
||||
[HSR_EC_WFI] = kvm_handle_wfx,
|
||||
[HSR_EC_CP15_32] = kvm_handle_cp15_32,
|
||||
[HSR_EC_CP15_64] = kvm_handle_cp15_64,
|
||||
[HSR_EC_CP14_MR] = kvm_handle_cp14_access,
|
||||
[HSR_EC_CP14_MR] = kvm_handle_cp14_32,
|
||||
[HSR_EC_CP14_LS] = kvm_handle_cp14_load_store,
|
||||
[HSR_EC_CP14_64] = kvm_handle_cp14_access,
|
||||
[HSR_EC_CP14_64] = kvm_handle_cp14_64,
|
||||
[HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access,
|
||||
[HSR_EC_CP10_ID] = kvm_handle_cp10_id,
|
||||
[HSR_EC_HVC] = handle_hvc,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Makefile for Kernel-based Virtual Machine module, HYP part
|
||||
#
|
||||
|
||||
ccflags-y += -fno-stack-protector
|
||||
|
||||
KVM=../../../../virt/kvm
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
|
||||
|
||||
@@ -48,7 +48,9 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host)
|
||||
write_sysreg(HSTR_T(15), HSTR);
|
||||
write_sysreg(HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11), HCPTR);
|
||||
val = read_sysreg(HDCR);
|
||||
write_sysreg(val | HDCR_TPM | HDCR_TPMCR, HDCR);
|
||||
val |= HDCR_TPM | HDCR_TPMCR; /* trap performance monitors */
|
||||
val |= HDCR_TDRA | HDCR_TDOSA | HDCR_TDA; /* trap debug regs */
|
||||
write_sysreg(val, HDCR);
|
||||
}
|
||||
|
||||
static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
|
||||
|
||||
@@ -147,10 +147,10 @@ __v7m_setup_cont:
|
||||
|
||||
@ Configure caches (if implemented)
|
||||
teq r8, #0
|
||||
stmneia r12, {r0-r6, lr} @ v7m_invalidate_l1 touches r0-r6
|
||||
stmneia sp, {r0-r6, lr} @ v7m_invalidate_l1 touches r0-r6
|
||||
blne v7m_invalidate_l1
|
||||
teq r8, #0 @ re-evalutae condition
|
||||
ldmneia r12, {r0-r6, lr}
|
||||
ldmneia sp, {r0-r6, lr}
|
||||
|
||||
@ Configure the System Control Register to ensure 8-byte stack alignment
|
||||
@ Note the STKALIGN bit is either RW or RAO.
|
||||
|
||||
@@ -808,6 +808,7 @@
|
||||
clocks = <&sys_ctrl 2>, <&sys_ctrl 1>;
|
||||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC0>;
|
||||
reset-names = "reset";
|
||||
bus-width = <0x8>;
|
||||
vmmc-supply = <&ldo19>;
|
||||
pinctrl-names = "default";
|
||||
@@ -831,6 +832,7 @@
|
||||
clocks = <&sys_ctrl 4>, <&sys_ctrl 3>;
|
||||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC1>;
|
||||
reset-names = "reset";
|
||||
vqmmc-supply = <&ldo7>;
|
||||
vmmc-supply = <&ldo10>;
|
||||
bus-width = <0x4>;
|
||||
@@ -849,6 +851,7 @@
|
||||
clocks = <&sys_ctrl HI6220_MMC2_CIUCLK>, <&sys_ctrl HI6220_MMC2_CLK>;
|
||||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC2>;
|
||||
reset-names = "reset";
|
||||
bus-width = <0x4>;
|
||||
broken-cd;
|
||||
pinctrl-names = "default", "idle";
|
||||
|
||||
@@ -42,25 +42,35 @@
|
||||
#define __smp_rmb() dmb(ishld)
|
||||
#define __smp_wmb() dmb(ishst)
|
||||
|
||||
#define __smp_store_release(p, v) \
|
||||
#define __smp_store_release(p, v) \
|
||||
do { \
|
||||
union { typeof(*p) __val; char __c[1]; } __u = \
|
||||
{ .__val = (__force typeof(*p)) (v) }; \
|
||||
compiletime_assert_atomic_type(*p); \
|
||||
switch (sizeof(*p)) { \
|
||||
case 1: \
|
||||
asm volatile ("stlrb %w1, %0" \
|
||||
: "=Q" (*p) : "r" (v) : "memory"); \
|
||||
: "=Q" (*p) \
|
||||
: "r" (*(__u8 *)__u.__c) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 2: \
|
||||
asm volatile ("stlrh %w1, %0" \
|
||||
: "=Q" (*p) : "r" (v) : "memory"); \
|
||||
: "=Q" (*p) \
|
||||
: "r" (*(__u16 *)__u.__c) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 4: \
|
||||
asm volatile ("stlr %w1, %0" \
|
||||
: "=Q" (*p) : "r" (v) : "memory"); \
|
||||
: "=Q" (*p) \
|
||||
: "r" (*(__u32 *)__u.__c) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
case 8: \
|
||||
asm volatile ("stlr %1, %0" \
|
||||
: "=Q" (*p) : "r" (v) : "memory"); \
|
||||
: "=Q" (*p) \
|
||||
: "r" (*(__u64 *)__u.__c) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -46,7 +46,7 @@ static inline unsigned long __xchg_case_##name(unsigned long x, \
|
||||
" swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n" \
|
||||
__nops(3) \
|
||||
" " #nop_lse) \
|
||||
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) \
|
||||
: "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr) \
|
||||
: "r" (x) \
|
||||
: cl); \
|
||||
\
|
||||
|
||||
@@ -97,11 +97,12 @@ static inline void set_fs(mm_segment_t fs)
|
||||
*/
|
||||
#define __range_ok(addr, size) \
|
||||
({ \
|
||||
unsigned long __addr = (unsigned long __force)(addr); \
|
||||
unsigned long flag, roksum; \
|
||||
__chk_user_ptr(addr); \
|
||||
asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
|
||||
: "=&r" (flag), "=&r" (roksum) \
|
||||
: "1" (addr), "Ir" (size), \
|
||||
: "1" (__addr), "Ir" (size), \
|
||||
"r" (current_thread_info()->addr_limit) \
|
||||
: "cc"); \
|
||||
flag; \
|
||||
|
||||
@@ -306,7 +306,8 @@ do { \
|
||||
_ASM_EXTABLE(0b, 4b) \
|
||||
_ASM_EXTABLE(1b, 4b) \
|
||||
: "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
|
||||
: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \
|
||||
: "r" ((unsigned long)addr), "i" (-EAGAIN), \
|
||||
"i" (-EFAULT), \
|
||||
"i" (__SWP_LL_SC_LOOPS) \
|
||||
: "memory"); \
|
||||
uaccess_disable(); \
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Makefile for Kernel-based Virtual Machine module, HYP part
|
||||
#
|
||||
|
||||
ccflags-y += -fno-stack-protector
|
||||
|
||||
KVM=../../../../virt/kvm
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
|
||||
|
||||
@@ -90,4 +90,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _UAPI__ASM_AVR32_SOCKET_H */
|
||||
|
||||
@@ -90,5 +90,7 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
||||
|
||||
@@ -99,4 +99,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_IA64_SOCKET_H */
|
||||
|
||||
@@ -90,4 +90,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_M32R_SOCKET_H */
|
||||
|
||||
@@ -28,24 +28,32 @@
|
||||
|
||||
#define segment_eq(a, b) ((a).seg == (b).seg)
|
||||
|
||||
#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
|
||||
/*
|
||||
* Explicitly allow NULL pointers here. Parts of the kernel such
|
||||
* as readv/writev use access_ok to validate pointers, but want
|
||||
* to allow NULL pointers for various reasons. NULL pointers are
|
||||
* safe to allow through because the first page is not mappable on
|
||||
* Meta.
|
||||
*
|
||||
* We also wish to avoid letting user code access the system area
|
||||
* and the kernel half of the address space.
|
||||
*/
|
||||
#define __user_bad(addr, size) (((addr) > 0 && (addr) < META_MEMORY_BASE) || \
|
||||
((addr) > PAGE_OFFSET && \
|
||||
(addr) < LINCORE_BASE))
|
||||
|
||||
static inline int __access_ok(unsigned long addr, unsigned long size)
|
||||
{
|
||||
return __kernel_ok || !__user_bad(addr, size);
|
||||
/*
|
||||
* Allow access to the user mapped memory area, but not the system area
|
||||
* before it. The check extends to the top of the address space when
|
||||
* kernel access is allowed (there's no real reason to user copy to the
|
||||
* system area in any case).
|
||||
*/
|
||||
if (likely(addr >= META_MEMORY_BASE && addr < get_fs().seg &&
|
||||
size <= get_fs().seg - addr))
|
||||
return true;
|
||||
/*
|
||||
* Explicitly allow NULL pointers here. Parts of the kernel such
|
||||
* as readv/writev use access_ok to validate pointers, but want
|
||||
* to allow NULL pointers for various reasons. NULL pointers are
|
||||
* safe to allow through because the first page is not mappable on
|
||||
* Meta.
|
||||
*/
|
||||
if (!addr)
|
||||
return true;
|
||||
/* Allow access to core code memory area... */
|
||||
if (addr >= LINCORE_CODE_BASE && addr <= LINCORE_CODE_LIMIT &&
|
||||
size <= LINCORE_CODE_LIMIT + 1 - addr)
|
||||
return true;
|
||||
/* ... but no other areas. */
|
||||
return false;
|
||||
}
|
||||
|
||||
#define access_ok(type, addr, size) __access_ok((unsigned long)(addr), \
|
||||
@@ -186,8 +194,13 @@ do { \
|
||||
extern long __must_check __strncpy_from_user(char *dst, const char __user *src,
|
||||
long count);
|
||||
|
||||
#define strncpy_from_user(dst, src, count) __strncpy_from_user(dst, src, count)
|
||||
|
||||
static inline long
|
||||
strncpy_from_user(char *dst, const char __user *src, long count)
|
||||
{
|
||||
if (!access_ok(VERIFY_READ, src, 1))
|
||||
return -EFAULT;
|
||||
return __strncpy_from_user(dst, src, count);
|
||||
}
|
||||
/*
|
||||
* Return the size of a string (including the ending 0)
|
||||
*
|
||||
|
||||
@@ -1368,6 +1368,7 @@ config CPU_LOONGSON3
|
||||
select WEAK_ORDERING
|
||||
select WEAK_REORDERING_BEYOND_LLSC
|
||||
select MIPS_PGD_C0_CONTEXT
|
||||
select MIPS_L1_CACHE_SHIFT_6
|
||||
select GPIOLIB
|
||||
help
|
||||
The Loongson 3 processor implements the MIPS64R2 instruction
|
||||
|
||||
@@ -108,4 +108,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
||||
@@ -90,4 +90,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
||||
@@ -89,4 +89,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 0x402E
|
||||
|
||||
#define SO_COOKIE 0x4032
|
||||
|
||||
#endif /* _UAPI_ASM_SOCKET_H */
|
||||
|
||||
@@ -70,8 +70,9 @@ extern void drop_cop(unsigned long acop, struct mm_struct *mm);
|
||||
* switch_mm is the entry point called from the architecture independent
|
||||
* code in kernel/sched/core.c
|
||||
*/
|
||||
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
static inline void switch_mm_irqs_off(struct mm_struct *prev,
|
||||
struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
/* Mark this context has been used on the new CPU */
|
||||
if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next)))
|
||||
@@ -110,6 +111,18 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
switch_mmu_context(prev, next, tsk);
|
||||
}
|
||||
|
||||
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
switch_mm_irqs_off(prev, next, tsk);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#define switch_mm_irqs_off switch_mm_irqs_off
|
||||
|
||||
|
||||
#define deactivate_mm(tsk,mm) do { } while (0)
|
||||
|
||||
/*
|
||||
|
||||
@@ -97,4 +97,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_POWERPC_SOCKET_H */
|
||||
|
||||
@@ -724,7 +724,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
|
||||
*/
|
||||
#define MAX_WAIT_FOR_RECOVERY 300
|
||||
|
||||
static void eeh_handle_normal_event(struct eeh_pe *pe)
|
||||
static bool eeh_handle_normal_event(struct eeh_pe *pe)
|
||||
{
|
||||
struct pci_bus *frozen_bus;
|
||||
struct eeh_dev *edev, *tmp;
|
||||
@@ -736,7 +736,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
|
||||
if (!frozen_bus) {
|
||||
pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
|
||||
__func__, pe->phb->global_number, pe->addr);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
eeh_pe_update_time_stamp(pe);
|
||||
@@ -870,7 +870,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
|
||||
pr_info("EEH: Notify device driver to resume\n");
|
||||
eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
|
||||
|
||||
return;
|
||||
return false;
|
||||
|
||||
excess_failures:
|
||||
/*
|
||||
@@ -915,8 +915,12 @@ perm_error:
|
||||
pci_lock_rescan_remove();
|
||||
pci_hp_remove_devices(frozen_bus);
|
||||
pci_unlock_rescan_remove();
|
||||
|
||||
/* The passed PE should no longer be used */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void eeh_handle_special_event(void)
|
||||
@@ -982,7 +986,14 @@ static void eeh_handle_special_event(void)
|
||||
*/
|
||||
if (rc == EEH_NEXT_ERR_FROZEN_PE ||
|
||||
rc == EEH_NEXT_ERR_FENCED_PHB) {
|
||||
eeh_handle_normal_event(pe);
|
||||
/*
|
||||
* eeh_handle_normal_event() can make the PE stale if it
|
||||
* determines that the PE cannot possibly be recovered.
|
||||
* Don't modify the PE state if that's the case.
|
||||
*/
|
||||
if (eeh_handle_normal_event(pe))
|
||||
continue;
|
||||
|
||||
eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
|
||||
} else {
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
@@ -735,8 +735,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
andis. r15,r14,(DBSR_IC|DBSR_BT)@h
|
||||
beq+ 1f
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
ld r15,PACATOC(r13)
|
||||
ld r14,interrupt_base_book3e@got(r15)
|
||||
ld r15,__end_interrupts@got(r15)
|
||||
#else
|
||||
LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
|
||||
LOAD_REG_IMMEDIATE(r15,__end_interrupts)
|
||||
#endif
|
||||
cmpld cr0,r10,r14
|
||||
cmpld cr1,r10,r15
|
||||
blt+ cr0,1f
|
||||
@@ -799,8 +805,14 @@ kernel_dbg_exc:
|
||||
andis. r15,r14,(DBSR_IC|DBSR_BT)@h
|
||||
beq+ 1f
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
ld r15,PACATOC(r13)
|
||||
ld r14,interrupt_base_book3e@got(r15)
|
||||
ld r15,__end_interrupts@got(r15)
|
||||
#else
|
||||
LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
|
||||
LOAD_REG_IMMEDIATE(r15,__end_interrupts)
|
||||
#endif
|
||||
cmpld cr0,r10,r14
|
||||
cmpld cr1,r10,r15
|
||||
blt+ cr0,1f
|
||||
|
||||
@@ -205,6 +205,8 @@ static void machine_check_process_queued_event(struct irq_work *work)
|
||||
{
|
||||
int index;
|
||||
|
||||
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
|
||||
|
||||
/*
|
||||
* For now just print it to console.
|
||||
* TODO: log this error event to FSP or nvram.
|
||||
|
||||
@@ -839,6 +839,25 @@ static void tm_reclaim_thread(struct thread_struct *thr,
|
||||
if (!MSR_TM_SUSPENDED(mfmsr()))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we are in a transaction and FP is off then we can't have
|
||||
* used FP inside that transaction. Hence the checkpointed
|
||||
* state is the same as the live state. We need to copy the
|
||||
* live state to the checkpointed state so that when the
|
||||
* transaction is restored, the checkpointed state is correct
|
||||
* and the aborted transaction sees the correct state. We use
|
||||
* ckpt_regs.msr here as that's what tm_reclaim will use to
|
||||
* determine if it's going to write the checkpointed state or
|
||||
* not. So either this will write the checkpointed registers,
|
||||
* or reclaim will. Similarly for VMX.
|
||||
*/
|
||||
if ((thr->ckpt_regs.msr & MSR_FP) == 0)
|
||||
memcpy(&thr->ckfp_state, &thr->fp_state,
|
||||
sizeof(struct thread_fp_state));
|
||||
if ((thr->ckpt_regs.msr & MSR_VEC) == 0)
|
||||
memcpy(&thr->ckvr_state, &thr->vr_state,
|
||||
sizeof(struct thread_vr_state));
|
||||
|
||||
giveup_all(container_of(thr, struct task_struct, thread));
|
||||
|
||||
tm_reclaim(thr, thr->ckpt_regs.msr, cause);
|
||||
|
||||
@@ -302,8 +302,6 @@ long machine_check_early(struct pt_regs *regs)
|
||||
|
||||
__this_cpu_inc(irq_stat.mce_exceptions);
|
||||
|
||||
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
|
||||
|
||||
if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
|
||||
handled = cur_cpu_spec->machine_check_early(regs);
|
||||
return handled;
|
||||
@@ -737,6 +735,8 @@ void machine_check_exception(struct pt_regs *regs)
|
||||
|
||||
__this_cpu_inc(irq_stat.mce_exceptions);
|
||||
|
||||
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
|
||||
|
||||
/* See if any machine dependent calls. In theory, we would want
|
||||
* to call the CPU first, and call the ppc_md. one if the CPU
|
||||
* one returns a positive number. However there is existing code
|
||||
|
||||
@@ -81,7 +81,7 @@ struct page *new_iommu_non_cma_page(struct page *page, unsigned long private,
|
||||
gfp_t gfp_mask = GFP_USER;
|
||||
struct page *new_page;
|
||||
|
||||
if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
|
||||
if (PageCompound(page))
|
||||
return NULL;
|
||||
|
||||
if (PageHighMem(page))
|
||||
@@ -100,7 +100,7 @@ static int mm_iommu_move_page_from_cma(struct page *page)
|
||||
LIST_HEAD(cma_migrate_pages);
|
||||
|
||||
/* Ignore huge pages for now */
|
||||
if (PageHuge(page) || PageTransHuge(page) || PageCompound(page))
|
||||
if (PageCompound(page))
|
||||
return -EBUSY;
|
||||
|
||||
lru_add_drain();
|
||||
|
||||
@@ -288,7 +288,6 @@ int dlpar_detach_node(struct device_node *dn)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
of_node_put(dn); /* Must decrement the refcount */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,4 +96,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _ASM_SOCKET_H */
|
||||
|
||||
@@ -426,6 +426,20 @@ static void *nt_vmcoreinfo(void *ptr)
|
||||
return nt_init_name(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize final note (needed for /proc/vmcore code)
|
||||
*/
|
||||
static void *nt_final(void *ptr)
|
||||
{
|
||||
Elf64_Nhdr *note;
|
||||
|
||||
note = (Elf64_Nhdr *) ptr;
|
||||
note->n_namesz = 0;
|
||||
note->n_descsz = 0;
|
||||
note->n_type = 0;
|
||||
return PTR_ADD(ptr, sizeof(Elf64_Nhdr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize ELF header (new kernel)
|
||||
*/
|
||||
@@ -513,6 +527,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
||||
if (sa->prefix != 0)
|
||||
ptr = fill_cpu_elf_notes(ptr, cpu++, sa);
|
||||
ptr = nt_vmcoreinfo(ptr);
|
||||
ptr = nt_final(ptr);
|
||||
memset(phdr, 0, sizeof(*phdr));
|
||||
phdr->p_type = PT_NOTE;
|
||||
phdr->p_offset = notes_offset;
|
||||
|
||||
@@ -321,6 +321,7 @@ ENTRY(system_call)
|
||||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
|
||||
.Lsysc_exit_timer:
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
@@ -606,6 +607,7 @@ ENTRY(io_int_handler)
|
||||
lg %r14,__LC_VDSO_PER_CPU
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r11)
|
||||
.Lio_exit_timer:
|
||||
stpt __LC_EXIT_TIMER
|
||||
mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
|
||||
lmg %r11,%r15,__PT_R11(%r11)
|
||||
@@ -1135,15 +1137,23 @@ cleanup_critical:
|
||||
br %r14
|
||||
|
||||
.Lcleanup_sysc_restore:
|
||||
# check if stpt has been executed
|
||||
clg %r9,BASED(.Lcleanup_sysc_restore_insn)
|
||||
jh 0f
|
||||
mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
|
||||
cghi %r11,__LC_SAVE_AREA_ASYNC
|
||||
je 0f
|
||||
mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
|
||||
0: clg %r9,BASED(.Lcleanup_sysc_restore_insn+8)
|
||||
je 1f
|
||||
lg %r9,24(%r11) # get saved pointer to pt_regs
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r9)
|
||||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
0: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
1: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
br %r14
|
||||
.Lcleanup_sysc_restore_insn:
|
||||
.quad .Lsysc_exit_timer
|
||||
.quad .Lsysc_done - 4
|
||||
|
||||
.Lcleanup_io_tif:
|
||||
@@ -1151,15 +1161,20 @@ cleanup_critical:
|
||||
br %r14
|
||||
|
||||
.Lcleanup_io_restore:
|
||||
# check if stpt has been executed
|
||||
clg %r9,BASED(.Lcleanup_io_restore_insn)
|
||||
je 0f
|
||||
jh 0f
|
||||
mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
|
||||
0: clg %r9,BASED(.Lcleanup_io_restore_insn+8)
|
||||
je 1f
|
||||
lg %r9,24(%r11) # get saved r11 pointer to pt_regs
|
||||
mvc __LC_RETURN_PSW(16),__PT_PSW(%r9)
|
||||
mvc 0(64,%r11),__PT_R8(%r9)
|
||||
lmg %r0,%r7,__PT_R0(%r9)
|
||||
0: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
1: lmg %r8,%r9,__LC_RETURN_PSW
|
||||
br %r14
|
||||
.Lcleanup_io_restore_insn:
|
||||
.quad .Lio_exit_timer
|
||||
.quad .Lio_done - 4
|
||||
|
||||
.Lcleanup_idle:
|
||||
|
||||
@@ -86,6 +86,8 @@
|
||||
|
||||
#define SO_CNX_ADVICE 0x0037
|
||||
|
||||
#define SO_COOKIE 0x003b
|
||||
|
||||
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
||||
#define SO_SECURITY_AUTHENTICATION 0x5001
|
||||
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
static char *initrd __initdata = NULL;
|
||||
static int load_initrd(char *filename, void *buf, int size);
|
||||
|
||||
static int __init read_initrd(void)
|
||||
int __init read_initrd(void)
|
||||
{
|
||||
void *area;
|
||||
long long size;
|
||||
@@ -46,8 +46,6 @@ static int __init read_initrd(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
__uml_postsetup(read_initrd);
|
||||
|
||||
static int __init uml_initrd_setup(char *line, int *add)
|
||||
{
|
||||
initrd = line;
|
||||
|
||||
@@ -336,11 +336,17 @@ int __init linux_main(int argc, char **argv)
|
||||
return start_uml();
|
||||
}
|
||||
|
||||
int __init __weak read_initrd(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
stack_protections((unsigned long) &init_thread_info);
|
||||
setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
|
||||
mem_total_pages(physmem_size, iomem_size, highmem);
|
||||
read_initrd();
|
||||
|
||||
paging_init();
|
||||
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
|
||||
|
||||
@@ -315,10 +315,10 @@ do { \
|
||||
#define __get_user_asm_u64(x, ptr, retval, errret) \
|
||||
({ \
|
||||
__typeof__(ptr) __ptr = (ptr); \
|
||||
asm volatile(ASM_STAC "\n" \
|
||||
asm volatile("\n" \
|
||||
"1: movl %2,%%eax\n" \
|
||||
"2: movl %3,%%edx\n" \
|
||||
"3: " ASM_CLAC "\n" \
|
||||
"3:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"4: mov %4,%0\n" \
|
||||
" xorl %%eax,%%eax\n" \
|
||||
@@ -327,7 +327,7 @@ do { \
|
||||
".previous\n" \
|
||||
_ASM_EXTABLE(1b, 4b) \
|
||||
_ASM_EXTABLE(2b, 4b) \
|
||||
: "=r" (retval), "=A"(x) \
|
||||
: "=r" (retval), "=&A"(x) \
|
||||
: "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \
|
||||
"i" (errret), "0" (retval)); \
|
||||
})
|
||||
|
||||
@@ -101,6 +101,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
|
||||
* Boot time FPU feature detection code:
|
||||
*/
|
||||
unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
|
||||
EXPORT_SYMBOL_GPL(mxcsr_feature_mask);
|
||||
|
||||
static void __init fpu__init_system_mxcsr(void)
|
||||
{
|
||||
|
||||
+31
-12
@@ -1735,6 +1735,7 @@ static u64 __get_kvmclock_ns(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_arch *ka = &kvm->arch;
|
||||
struct pvclock_vcpu_time_info hv_clock;
|
||||
u64 ret;
|
||||
|
||||
spin_lock(&ka->pvclock_gtod_sync_lock);
|
||||
if (!ka->use_master_clock) {
|
||||
@@ -1746,10 +1747,17 @@ static u64 __get_kvmclock_ns(struct kvm *kvm)
|
||||
hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
|
||||
spin_unlock(&ka->pvclock_gtod_sync_lock);
|
||||
|
||||
/* both __this_cpu_read() and rdtsc() should be on the same cpu */
|
||||
get_cpu();
|
||||
|
||||
kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
|
||||
&hv_clock.tsc_shift,
|
||||
&hv_clock.tsc_to_system_mul);
|
||||
return __pvclock_read_cycles(&hv_clock, rdtsc());
|
||||
ret = __pvclock_read_cycles(&hv_clock, rdtsc());
|
||||
|
||||
put_cpu();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 get_kvmclock_ns(struct kvm *kvm)
|
||||
@@ -3231,11 +3239,14 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
#define XSAVE_MXCSR_OFFSET 24
|
||||
|
||||
static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
|
||||
struct kvm_xsave *guest_xsave)
|
||||
{
|
||||
u64 xstate_bv =
|
||||
*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
|
||||
u32 mxcsr = *(u32 *)&guest_xsave->region[XSAVE_MXCSR_OFFSET / sizeof(u32)];
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_XSAVE)) {
|
||||
/*
|
||||
@@ -3243,11 +3254,13 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
|
||||
* CPUID leaf 0xD, index 0, EDX:EAX. This is for compatibility
|
||||
* with old userspace.
|
||||
*/
|
||||
if (xstate_bv & ~kvm_supported_xcr0())
|
||||
if (xstate_bv & ~kvm_supported_xcr0() ||
|
||||
mxcsr & ~mxcsr_feature_mask)
|
||||
return -EINVAL;
|
||||
load_xsave(vcpu, (u8 *)guest_xsave->region);
|
||||
} else {
|
||||
if (xstate_bv & ~XFEATURE_MASK_FPSSE)
|
||||
if (xstate_bv & ~XFEATURE_MASK_FPSSE ||
|
||||
mxcsr & ~mxcsr_feature_mask)
|
||||
return -EINVAL;
|
||||
memcpy(&vcpu->arch.guest_fpu.state.fxsave,
|
||||
guest_xsave->region, sizeof(struct fxregs_state));
|
||||
@@ -4750,16 +4763,20 @@ emul_write:
|
||||
|
||||
static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
|
||||
{
|
||||
/* TODO: String I/O for in kernel device */
|
||||
int r;
|
||||
int r = 0, i;
|
||||
|
||||
if (vcpu->arch.pio.in)
|
||||
r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
|
||||
vcpu->arch.pio.size, pd);
|
||||
else
|
||||
r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
|
||||
vcpu->arch.pio.port, vcpu->arch.pio.size,
|
||||
pd);
|
||||
for (i = 0; i < vcpu->arch.pio.count; i++) {
|
||||
if (vcpu->arch.pio.in)
|
||||
r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
|
||||
vcpu->arch.pio.size, pd);
|
||||
else
|
||||
r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
|
||||
vcpu->arch.pio.port, vcpu->arch.pio.size,
|
||||
pd);
|
||||
if (r)
|
||||
break;
|
||||
pd += vcpu->arch.pio.size;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -4797,6 +4814,8 @@ static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt,
|
||||
if (vcpu->arch.pio.count)
|
||||
goto data_avail;
|
||||
|
||||
memset(vcpu->arch.pio_data, 0, size * count);
|
||||
|
||||
ret = emulator_pio_in_out(vcpu, size, port, val, count, true);
|
||||
if (ret) {
|
||||
data_avail:
|
||||
|
||||
@@ -101,4 +101,6 @@
|
||||
|
||||
#define SO_CNX_ADVICE 53
|
||||
|
||||
#define SO_COOKIE 57
|
||||
|
||||
#endif /* _XTENSA_SOCKET_H */
|
||||
|
||||
+5
-1
@@ -859,7 +859,11 @@ static int __init lp_setup (char *str)
|
||||
} else if (!strcmp(str, "auto")) {
|
||||
parport_nr[0] = LP_PARPORT_AUTO;
|
||||
} else if (!strcmp(str, "none")) {
|
||||
parport_nr[parport_ptr++] = LP_PARPORT_NONE;
|
||||
if (parport_ptr < LP_NO)
|
||||
parport_nr[parport_ptr++] = LP_PARPORT_NONE;
|
||||
else
|
||||
printk(KERN_INFO "lp: too many ports, %s ignored.\n",
|
||||
str);
|
||||
} else if (!strcmp(str, "reset")) {
|
||||
reset = 1;
|
||||
}
|
||||
|
||||
@@ -340,6 +340,11 @@ static const struct vm_operations_struct mmap_mem_ops = {
|
||||
static int mmap_mem(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
|
||||
|
||||
/* It's illegal to wrap around the end of the physical address space. */
|
||||
if (offset + (phys_addr_t)size < offset)
|
||||
return -EINVAL;
|
||||
|
||||
if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -111,8 +111,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
|
||||
memcpy_fromio(buf, priv->rsp, 6);
|
||||
expected = be32_to_cpup((__be32 *) &buf[2]);
|
||||
|
||||
if (expected > count)
|
||||
if (expected > count || expected < 6)
|
||||
return -EIO;
|
||||
|
||||
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
|
||||
|
||||
@@ -49,9 +49,10 @@
|
||||
*/
|
||||
#define TPM_I2C_MAX_BUF_SIZE 32
|
||||
#define TPM_I2C_RETRY_COUNT 32
|
||||
#define TPM_I2C_BUS_DELAY 1 /* msec */
|
||||
#define TPM_I2C_RETRY_DELAY_SHORT 2 /* msec */
|
||||
#define TPM_I2C_RETRY_DELAY_LONG 10 /* msec */
|
||||
#define TPM_I2C_BUS_DELAY 1000 /* usec */
|
||||
#define TPM_I2C_RETRY_DELAY_SHORT (2 * 1000) /* usec */
|
||||
#define TPM_I2C_RETRY_DELAY_LONG (10 * 1000) /* usec */
|
||||
#define TPM_I2C_DELAY_RANGE 300 /* usec */
|
||||
|
||||
#define OF_IS_TPM2 ((void *)1)
|
||||
#define I2C_IS_TPM2 1
|
||||
@@ -123,7 +124,9 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data)
|
||||
/* this causes the current command to be aborted */
|
||||
for (i = 0, status = -1; i < TPM_I2C_RETRY_COUNT && status < 0; i++) {
|
||||
status = i2c_nuvoton_write_buf(client, TPM_STS, 1, &data);
|
||||
msleep(TPM_I2C_BUS_DELAY);
|
||||
if (status < 0)
|
||||
usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY
|
||||
+ TPM_I2C_DELAY_RANGE);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -160,7 +163,8 @@ static int i2c_nuvoton_get_burstcount(struct i2c_client *client,
|
||||
burst_count = min_t(u8, TPM_I2C_MAX_BUF_SIZE, data);
|
||||
break;
|
||||
}
|
||||
msleep(TPM_I2C_BUS_DELAY);
|
||||
usleep_range(TPM_I2C_BUS_DELAY, TPM_I2C_BUS_DELAY
|
||||
+ TPM_I2C_DELAY_RANGE);
|
||||
} while (time_before(jiffies, stop));
|
||||
|
||||
return burst_count;
|
||||
@@ -203,13 +207,17 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
|
||||
return 0;
|
||||
|
||||
/* use polling to wait for the event */
|
||||
ten_msec = jiffies + msecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG);
|
||||
ten_msec = jiffies + usecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG);
|
||||
stop = jiffies + timeout;
|
||||
do {
|
||||
if (time_before(jiffies, ten_msec))
|
||||
msleep(TPM_I2C_RETRY_DELAY_SHORT);
|
||||
usleep_range(TPM_I2C_RETRY_DELAY_SHORT,
|
||||
TPM_I2C_RETRY_DELAY_SHORT
|
||||
+ TPM_I2C_DELAY_RANGE);
|
||||
else
|
||||
msleep(TPM_I2C_RETRY_DELAY_LONG);
|
||||
usleep_range(TPM_I2C_RETRY_DELAY_LONG,
|
||||
TPM_I2C_RETRY_DELAY_LONG
|
||||
+ TPM_I2C_DELAY_RANGE);
|
||||
status_valid = i2c_nuvoton_check_status(chip, mask,
|
||||
value);
|
||||
if (status_valid)
|
||||
|
||||
@@ -160,8 +160,10 @@ static int get_burstcount(struct tpm_chip *chip)
|
||||
u32 value;
|
||||
|
||||
/* wait for burstcount */
|
||||
/* which timeout value, spec has 2 answers (c & d) */
|
||||
stop = jiffies + chip->timeout_d;
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
stop = jiffies + chip->timeout_a;
|
||||
else
|
||||
stop = jiffies + chip->timeout_d;
|
||||
do {
|
||||
rc = tpm_tis_read32(priv, TPM_STS(priv->locality), &value);
|
||||
if (rc < 0)
|
||||
|
||||
@@ -48,8 +48,8 @@ struct tpm_tis_spi_phy {
|
||||
struct tpm_tis_data priv;
|
||||
struct spi_device *spi_device;
|
||||
|
||||
u8 tx_buf[MAX_SPI_FRAMESIZE + 4];
|
||||
u8 rx_buf[MAX_SPI_FRAMESIZE + 4];
|
||||
u8 tx_buf[4];
|
||||
u8 rx_buf[4];
|
||||
};
|
||||
|
||||
static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data)
|
||||
@@ -57,120 +57,96 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da
|
||||
return container_of(data, struct tpm_tis_spi_phy, priv);
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *result)
|
||||
static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *buffer, u8 direction)
|
||||
{
|
||||
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
|
||||
int ret, i;
|
||||
int ret = 0;
|
||||
int i;
|
||||
struct spi_message m;
|
||||
struct spi_transfer spi_xfer = {
|
||||
.tx_buf = phy->tx_buf,
|
||||
.rx_buf = phy->rx_buf,
|
||||
.len = 4,
|
||||
};
|
||||
|
||||
if (len > MAX_SPI_FRAMESIZE)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->tx_buf[0] = 0x80 | (len - 1);
|
||||
phy->tx_buf[1] = 0xd4;
|
||||
phy->tx_buf[2] = (addr >> 8) & 0xFF;
|
||||
phy->tx_buf[3] = addr & 0xFF;
|
||||
|
||||
spi_xfer.cs_change = 1;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
struct spi_transfer spi_xfer;
|
||||
u8 transfer_len;
|
||||
|
||||
spi_bus_lock(phy->spi_device->master);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
memset(phy->tx_buf, 0, len);
|
||||
while (len) {
|
||||
transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
|
||||
|
||||
phy->tx_buf[0] = direction | (transfer_len - 1);
|
||||
phy->tx_buf[1] = 0xd4;
|
||||
phy->tx_buf[2] = addr >> 8;
|
||||
phy->tx_buf[3] = addr;
|
||||
|
||||
memset(&spi_xfer, 0, sizeof(spi_xfer));
|
||||
spi_xfer.tx_buf = phy->tx_buf;
|
||||
spi_xfer.rx_buf = phy->rx_buf;
|
||||
spi_xfer.len = 4;
|
||||
spi_xfer.cs_change = 1;
|
||||
|
||||
/* According to TCG PTP specification, if there is no TPM present at
|
||||
* all, then the design has a weak pull-up on MISO. If a TPM is not
|
||||
* present, a pull-up on MISO means that the SB controller sees a 1,
|
||||
* and will latch in 0xFF on the read.
|
||||
*/
|
||||
for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) {
|
||||
spi_xfer.len = 1;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if ((phy->rx_buf[3] & 0x01) == 0) {
|
||||
// handle SPI wait states
|
||||
phy->tx_buf[0] = 0;
|
||||
|
||||
for (i = 0; i < TPM_RETRY; i++) {
|
||||
spi_xfer.len = 1;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
if (phy->rx_buf[0] & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == TPM_RETRY) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
spi_xfer.cs_change = 0;
|
||||
spi_xfer.len = transfer_len;
|
||||
spi_xfer.delay_usecs = 5;
|
||||
|
||||
if (direction) {
|
||||
spi_xfer.tx_buf = NULL;
|
||||
spi_xfer.rx_buf = buffer;
|
||||
} else {
|
||||
spi_xfer.tx_buf = buffer;
|
||||
spi_xfer.rx_buf = NULL;
|
||||
}
|
||||
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
len -= transfer_len;
|
||||
buffer += transfer_len;
|
||||
}
|
||||
|
||||
spi_xfer.cs_change = 0;
|
||||
spi_xfer.len = len;
|
||||
spi_xfer.rx_buf = result;
|
||||
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
|
||||
exit:
|
||||
spi_bus_unlock(phy->spi_device->master);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *result)
|
||||
{
|
||||
return tpm_tis_spi_transfer(data, addr, len, result, 0x80);
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
|
||||
u16 len, u8 *value)
|
||||
{
|
||||
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
|
||||
int ret, i;
|
||||
struct spi_message m;
|
||||
struct spi_transfer spi_xfer = {
|
||||
.tx_buf = phy->tx_buf,
|
||||
.rx_buf = phy->rx_buf,
|
||||
.len = 4,
|
||||
};
|
||||
|
||||
if (len > MAX_SPI_FRAMESIZE)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->tx_buf[0] = len - 1;
|
||||
phy->tx_buf[1] = 0xd4;
|
||||
phy->tx_buf[2] = (addr >> 8) & 0xFF;
|
||||
phy->tx_buf[3] = addr & 0xFF;
|
||||
|
||||
spi_xfer.cs_change = 1;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
|
||||
spi_bus_lock(phy->spi_device->master);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
memset(phy->tx_buf, 0, len);
|
||||
|
||||
/* According to TCG PTP specification, if there is no TPM present at
|
||||
* all, then the design has a weak pull-up on MISO. If a TPM is not
|
||||
* present, a pull-up on MISO means that the SB controller sees a 1,
|
||||
* and will latch in 0xFF on the read.
|
||||
*/
|
||||
for (i = 0; (phy->rx_buf[0] & 0x01) == 0 && i < TPM_RETRY; i++) {
|
||||
spi_xfer.len = 1;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spi_xfer.len = len;
|
||||
spi_xfer.tx_buf = value;
|
||||
spi_xfer.cs_change = 0;
|
||||
spi_xfer.tx_buf = value;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&spi_xfer, &m);
|
||||
ret = spi_sync_locked(phy->spi_device, &m);
|
||||
|
||||
exit:
|
||||
spi_bus_unlock(phy->spi_device->master);
|
||||
return ret;
|
||||
return tpm_tis_spi_transfer(data, addr, len, value, 0);
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
|
||||
|
||||
@@ -570,13 +570,15 @@ again:
|
||||
|
||||
for_each_cpu(cpu, &tmp_mask) {
|
||||
struct interactive_cpu *icpu = &per_cpu(interactive_cpu, cpu);
|
||||
struct cpufreq_policy *policy = icpu->ipolicy->policy;
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if (unlikely(!down_read_trylock(&icpu->enable_sem)))
|
||||
continue;
|
||||
|
||||
if (likely(icpu->ipolicy))
|
||||
if (likely(icpu->ipolicy)) {
|
||||
policy = icpu->ipolicy->policy;
|
||||
cpufreq_interactive_adjust_cpu(cpu, policy);
|
||||
}
|
||||
|
||||
up_read(&icpu->enable_sem);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ int fence_signal_locked(struct fence *fence)
|
||||
struct fence_cb *cur, *tmp;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(fence->lock);
|
||||
|
||||
if (WARN_ON(!fence))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -159,9 +161,6 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout)
|
||||
if (WARN_ON(timeout < 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (timeout == 0)
|
||||
return fence_is_signaled(fence);
|
||||
|
||||
trace_fence_wait_start(fence);
|
||||
ret = fence->ops->wait(fence, intr, timeout);
|
||||
trace_fence_wait_end(fence);
|
||||
|
||||
@@ -280,18 +280,24 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
|
||||
unsigned *pshared_count,
|
||||
struct fence ***pshared)
|
||||
{
|
||||
unsigned shared_count = 0;
|
||||
unsigned retry = 1;
|
||||
struct fence **shared = NULL, *fence_excl = NULL;
|
||||
int ret = 0;
|
||||
struct fence **shared = NULL;
|
||||
struct fence *fence_excl;
|
||||
unsigned int shared_count;
|
||||
int ret = 1;
|
||||
|
||||
while (retry) {
|
||||
do {
|
||||
struct reservation_object_list *fobj;
|
||||
unsigned seq;
|
||||
unsigned int i;
|
||||
|
||||
seq = read_seqcount_begin(&obj->seq);
|
||||
shared_count = i = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
seq = read_seqcount_begin(&obj->seq);
|
||||
|
||||
fence_excl = rcu_dereference(obj->fence_excl);
|
||||
if (fence_excl && !fence_get_rcu(fence_excl))
|
||||
goto unlock;
|
||||
|
||||
fobj = rcu_dereference(obj->fence);
|
||||
if (fobj) {
|
||||
@@ -309,52 +315,37 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
shared_count = 0;
|
||||
break;
|
||||
}
|
||||
shared = nshared;
|
||||
memcpy(shared, fobj->shared, sz);
|
||||
shared_count = fobj->shared_count;
|
||||
} else
|
||||
shared_count = 0;
|
||||
fence_excl = rcu_dereference(obj->fence_excl);
|
||||
|
||||
retry = read_seqcount_retry(&obj->seq, seq);
|
||||
if (retry)
|
||||
goto unlock;
|
||||
|
||||
if (!fence_excl || fence_get_rcu(fence_excl)) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < shared_count; ++i) {
|
||||
if (fence_get_rcu(shared[i]))
|
||||
continue;
|
||||
|
||||
/* uh oh, refcount failed, abort and retry */
|
||||
while (i--)
|
||||
fence_put(shared[i]);
|
||||
|
||||
if (fence_excl) {
|
||||
fence_put(fence_excl);
|
||||
fence_excl = NULL;
|
||||
}
|
||||
|
||||
retry = 1;
|
||||
break;
|
||||
shared[i] = rcu_dereference(fobj->shared[i]);
|
||||
if (!fence_get_rcu(shared[i]))
|
||||
break;
|
||||
}
|
||||
} else
|
||||
retry = 1;
|
||||
}
|
||||
|
||||
if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
|
||||
while (i--)
|
||||
fence_put(shared[i]);
|
||||
fence_put(fence_excl);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
*pshared_count = shared_count;
|
||||
if (shared_count)
|
||||
*pshared = shared;
|
||||
else {
|
||||
*pshared = NULL;
|
||||
} while (ret);
|
||||
|
||||
if (!shared_count) {
|
||||
kfree(shared);
|
||||
shared = NULL;
|
||||
}
|
||||
|
||||
*pshared_count = shared_count;
|
||||
*pshared = shared;
|
||||
*pfence_excl = fence_excl;
|
||||
|
||||
return ret;
|
||||
@@ -379,10 +370,7 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
|
||||
{
|
||||
struct fence *fence;
|
||||
unsigned seq, shared_count, i = 0;
|
||||
long ret = timeout;
|
||||
|
||||
if (!timeout)
|
||||
return reservation_object_test_signaled_rcu(obj, wait_all);
|
||||
long ret = timeout ? timeout : 1;
|
||||
|
||||
retry:
|
||||
fence = NULL;
|
||||
@@ -397,9 +385,6 @@ retry:
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto unlock_retry;
|
||||
|
||||
for (i = 0; i < shared_count; ++i) {
|
||||
struct fence *lfence = rcu_dereference(fobj->shared[i]);
|
||||
|
||||
@@ -422,9 +407,6 @@ retry:
|
||||
if (!shared_count) {
|
||||
struct fence *fence_excl = rcu_dereference(obj->fence_excl);
|
||||
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto unlock_retry;
|
||||
|
||||
if (fence_excl &&
|
||||
!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence_excl->flags)) {
|
||||
if (!fence_get_rcu(fence_excl))
|
||||
@@ -439,6 +421,11 @@ retry:
|
||||
|
||||
rcu_read_unlock();
|
||||
if (fence) {
|
||||
if (read_seqcount_retry(&obj->seq, seq)) {
|
||||
fence_put(fence);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ret = fence_wait_timeout(fence, intr, ret);
|
||||
fence_put(fence);
|
||||
if (ret > 0 && wait_all && (i + 1 < shared_count))
|
||||
@@ -484,12 +471,13 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
|
||||
bool test_all)
|
||||
{
|
||||
unsigned seq, shared_count;
|
||||
int ret = true;
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
retry:
|
||||
ret = true;
|
||||
shared_count = 0;
|
||||
seq = read_seqcount_begin(&obj->seq);
|
||||
rcu_read_lock();
|
||||
|
||||
if (test_all) {
|
||||
unsigned i;
|
||||
@@ -500,46 +488,35 @@ retry:
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto unlock_retry;
|
||||
|
||||
for (i = 0; i < shared_count; ++i) {
|
||||
struct fence *fence = rcu_dereference(fobj->shared[i]);
|
||||
|
||||
ret = reservation_object_test_signaled_single(fence);
|
||||
if (ret < 0)
|
||||
goto unlock_retry;
|
||||
goto retry;
|
||||
else if (!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* There could be a read_seqcount_retry here, but nothing cares
|
||||
* about whether it's the old or newer fence pointers that are
|
||||
* signaled. That race could still have happened after checking
|
||||
* read_seqcount_retry. If you care, use ww_mutex_lock.
|
||||
*/
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!shared_count) {
|
||||
struct fence *fence_excl = rcu_dereference(obj->fence_excl);
|
||||
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto unlock_retry;
|
||||
|
||||
if (fence_excl) {
|
||||
ret = reservation_object_test_signaled_single(
|
||||
fence_excl);
|
||||
if (ret < 0)
|
||||
goto unlock_retry;
|
||||
goto retry;
|
||||
|
||||
if (read_seqcount_retry(&obj->seq, seq))
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
|
||||
unlock_retry:
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu);
|
||||
|
||||
@@ -324,8 +324,8 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
|
||||
}
|
||||
|
||||
sync_file = sync_file_create(&pt->base);
|
||||
fence_put(&pt->base);
|
||||
if (!sync_file) {
|
||||
fence_put(&pt->base);
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -67,9 +67,10 @@ static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
|
||||
* sync_file_create() - creates a sync file
|
||||
* @fence: fence to add to the sync_fence
|
||||
*
|
||||
* Creates a sync_file containg @fence. Once this is called, the sync_file
|
||||
* takes ownership of @fence. The sync_file can be released with
|
||||
* fput(sync_file->file). Returns the sync_file or NULL in case of error.
|
||||
* Creates a sync_file containg @fence. This function acquires and additional
|
||||
* reference of @fence for the newly-created &sync_file, if it succeeds. The
|
||||
* sync_file can be released with fput(sync_file->file). Returns the
|
||||
* sync_file or NULL in case of error.
|
||||
*/
|
||||
struct sync_file *sync_file_create(struct fence *fence)
|
||||
{
|
||||
@@ -79,7 +80,7 @@ struct sync_file *sync_file_create(struct fence *fence)
|
||||
if (!sync_file)
|
||||
return NULL;
|
||||
|
||||
sync_file->fence = fence;
|
||||
sync_file->fence = fence_get(fence);
|
||||
|
||||
snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d",
|
||||
fence->ops->get_driver_name(fence),
|
||||
@@ -90,13 +91,6 @@ struct sync_file *sync_file_create(struct fence *fence)
|
||||
}
|
||||
EXPORT_SYMBOL(sync_file_create);
|
||||
|
||||
/**
|
||||
* sync_file_fdget() - get a sync_file from an fd
|
||||
* @fd: fd referencing a fence
|
||||
*
|
||||
* Ensures @fd references a valid sync_file, increments the refcount of the
|
||||
* backing file. Returns the sync_file or NULL in case of error.
|
||||
*/
|
||||
static struct sync_file *sync_file_fdget(int fd)
|
||||
{
|
||||
struct file *file = fget(fd);
|
||||
@@ -305,10 +299,9 @@ static unsigned int sync_file_poll(struct file *file, poll_table *wait)
|
||||
|
||||
poll_wait(file, &sync_file->wq, wait);
|
||||
|
||||
if (!poll_does_not_wait(wait) &&
|
||||
!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) {
|
||||
if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) {
|
||||
if (fence_add_callback(sync_file->fence, &sync_file->cb,
|
||||
fence_check_cb_func) < 0)
|
||||
fence_check_cb_func) < 0)
|
||||
wake_up_all(&sync_file->wq);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
|
||||
* OMAP's debounce time is in 31us steps
|
||||
* <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31
|
||||
* so we need to convert and round up to the closest unit.
|
||||
*
|
||||
* Return: 0 on success, negative error otherwise.
|
||||
*/
|
||||
static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
unsigned debounce)
|
||||
static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
unsigned debounce)
|
||||
{
|
||||
void __iomem *reg;
|
||||
u32 val;
|
||||
@@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
bool enable = !!debounce;
|
||||
|
||||
if (!bank->dbck_flag)
|
||||
return;
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (enable) {
|
||||
debounce = DIV_ROUND_UP(debounce, 31) - 1;
|
||||
debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK;
|
||||
if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
l = BIT(offset);
|
||||
@@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
|
||||
bank->context.debounce = debounce;
|
||||
bank->context.debounce_en = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
bank = gpiochip_get_data(chip);
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
omap2_set_gpio_debounce(bank, offset, debounce);
|
||||
ret = omap2_set_gpio_debounce(bank, offset, debounce);
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
return 0;
|
||||
if (ret)
|
||||
dev_info(chip->parent,
|
||||
"Could not set line %u debounce to %u microseconds (%d)",
|
||||
offset, debounce, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
|
||||
@@ -12,6 +12,7 @@ menuconfig DRM
|
||||
select I2C
|
||||
select I2C_ALGOBIT
|
||||
select DMA_SHARED_BUFFER
|
||||
select SYNC_FILE
|
||||
help
|
||||
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
||||
introduced in XFree86 4.0. If you say Y here, you need to select
|
||||
|
||||
@@ -1173,23 +1173,10 @@ static u32 dce_v10_0_latency_watermark(struct dce10_wm_params *wm)
|
||||
a.full = dfixed_const(available_bandwidth);
|
||||
b.full = dfixed_const(wm->num_heads);
|
||||
a.full = dfixed_div(a, b);
|
||||
tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
|
||||
tmp = min(dfixed_trunc(a), tmp);
|
||||
|
||||
b.full = dfixed_const(mc_latency + 512);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(b, c);
|
||||
|
||||
c.full = dfixed_const(dmif_size);
|
||||
b.full = dfixed_div(c, b);
|
||||
|
||||
tmp = min(dfixed_trunc(a), dfixed_trunc(b));
|
||||
|
||||
b.full = dfixed_const(1000);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(c, b);
|
||||
c.full = dfixed_const(wm->bytes_per_pixel);
|
||||
b.full = dfixed_mul(b, c);
|
||||
|
||||
lb_fill_bw = min(tmp, dfixed_trunc(b));
|
||||
lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
|
||||
|
||||
a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
|
||||
b.full = dfixed_const(1000);
|
||||
@@ -1297,14 +1284,14 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
|
||||
{
|
||||
struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
|
||||
struct dce10_wm_params wm_low, wm_high;
|
||||
u32 pixel_period;
|
||||
u32 active_time;
|
||||
u32 line_time = 0;
|
||||
u32 latency_watermark_a = 0, latency_watermark_b = 0;
|
||||
u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
|
||||
|
||||
if (amdgpu_crtc->base.enabled && num_heads && mode) {
|
||||
pixel_period = 1000000 / (u32)mode->clock;
|
||||
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
|
||||
active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
|
||||
line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
|
||||
|
||||
/* watermark for high clocks */
|
||||
if (adev->pm.dpm_enabled) {
|
||||
@@ -1319,7 +1306,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_high.disp_clk = mode->clock;
|
||||
wm_high.src_width = mode->crtc_hdisplay;
|
||||
wm_high.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_high.active_time = active_time;
|
||||
wm_high.blank_time = line_time - wm_high.active_time;
|
||||
wm_high.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
@@ -1358,7 +1345,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_low.disp_clk = mode->clock;
|
||||
wm_low.src_width = mode->crtc_hdisplay;
|
||||
wm_low.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_low.active_time = active_time;
|
||||
wm_low.blank_time = line_time - wm_low.active_time;
|
||||
wm_low.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
|
||||
@@ -1140,23 +1140,10 @@ static u32 dce_v11_0_latency_watermark(struct dce10_wm_params *wm)
|
||||
a.full = dfixed_const(available_bandwidth);
|
||||
b.full = dfixed_const(wm->num_heads);
|
||||
a.full = dfixed_div(a, b);
|
||||
tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
|
||||
tmp = min(dfixed_trunc(a), tmp);
|
||||
|
||||
b.full = dfixed_const(mc_latency + 512);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(b, c);
|
||||
|
||||
c.full = dfixed_const(dmif_size);
|
||||
b.full = dfixed_div(c, b);
|
||||
|
||||
tmp = min(dfixed_trunc(a), dfixed_trunc(b));
|
||||
|
||||
b.full = dfixed_const(1000);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(c, b);
|
||||
c.full = dfixed_const(wm->bytes_per_pixel);
|
||||
b.full = dfixed_mul(b, c);
|
||||
|
||||
lb_fill_bw = min(tmp, dfixed_trunc(b));
|
||||
lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
|
||||
|
||||
a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
|
||||
b.full = dfixed_const(1000);
|
||||
@@ -1264,14 +1251,14 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
|
||||
{
|
||||
struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
|
||||
struct dce10_wm_params wm_low, wm_high;
|
||||
u32 pixel_period;
|
||||
u32 active_time;
|
||||
u32 line_time = 0;
|
||||
u32 latency_watermark_a = 0, latency_watermark_b = 0;
|
||||
u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
|
||||
|
||||
if (amdgpu_crtc->base.enabled && num_heads && mode) {
|
||||
pixel_period = 1000000 / (u32)mode->clock;
|
||||
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
|
||||
active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
|
||||
line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
|
||||
|
||||
/* watermark for high clocks */
|
||||
if (adev->pm.dpm_enabled) {
|
||||
@@ -1286,7 +1273,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_high.disp_clk = mode->clock;
|
||||
wm_high.src_width = mode->crtc_hdisplay;
|
||||
wm_high.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_high.active_time = active_time;
|
||||
wm_high.blank_time = line_time - wm_high.active_time;
|
||||
wm_high.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
@@ -1325,7 +1312,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_low.disp_clk = mode->clock;
|
||||
wm_low.src_width = mode->crtc_hdisplay;
|
||||
wm_low.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_low.active_time = active_time;
|
||||
wm_low.blank_time = line_time - wm_low.active_time;
|
||||
wm_low.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
|
||||
@@ -932,23 +932,10 @@ static u32 dce_v6_0_latency_watermark(struct dce6_wm_params *wm)
|
||||
a.full = dfixed_const(available_bandwidth);
|
||||
b.full = dfixed_const(wm->num_heads);
|
||||
a.full = dfixed_div(a, b);
|
||||
tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
|
||||
tmp = min(dfixed_trunc(a), tmp);
|
||||
|
||||
b.full = dfixed_const(mc_latency + 512);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(b, c);
|
||||
|
||||
c.full = dfixed_const(dmif_size);
|
||||
b.full = dfixed_div(c, b);
|
||||
|
||||
tmp = min(dfixed_trunc(a), dfixed_trunc(b));
|
||||
|
||||
b.full = dfixed_const(1000);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(c, b);
|
||||
c.full = dfixed_const(wm->bytes_per_pixel);
|
||||
b.full = dfixed_mul(b, c);
|
||||
|
||||
lb_fill_bw = min(tmp, dfixed_trunc(b));
|
||||
lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
|
||||
|
||||
a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
|
||||
b.full = dfixed_const(1000);
|
||||
@@ -1057,18 +1044,18 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
|
||||
struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
|
||||
struct dce6_wm_params wm_low, wm_high;
|
||||
u32 dram_channels;
|
||||
u32 pixel_period;
|
||||
u32 active_time;
|
||||
u32 line_time = 0;
|
||||
u32 latency_watermark_a = 0, latency_watermark_b = 0;
|
||||
u32 priority_a_mark = 0, priority_b_mark = 0;
|
||||
u32 priority_a_cnt = PRIORITY_OFF;
|
||||
u32 priority_b_cnt = PRIORITY_OFF;
|
||||
u32 tmp, arb_control3;
|
||||
u32 tmp, arb_control3, lb_vblank_lead_lines = 0;
|
||||
fixed20_12 a, b, c;
|
||||
|
||||
if (amdgpu_crtc->base.enabled && num_heads && mode) {
|
||||
pixel_period = 1000000 / (u32)mode->clock;
|
||||
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
|
||||
active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
|
||||
line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
|
||||
priority_a_cnt = 0;
|
||||
priority_b_cnt = 0;
|
||||
|
||||
@@ -1087,7 +1074,7 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_high.disp_clk = mode->clock;
|
||||
wm_high.src_width = mode->crtc_hdisplay;
|
||||
wm_high.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_high.active_time = active_time;
|
||||
wm_high.blank_time = line_time - wm_high.active_time;
|
||||
wm_high.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
@@ -1114,7 +1101,7 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_low.disp_clk = mode->clock;
|
||||
wm_low.src_width = mode->crtc_hdisplay;
|
||||
wm_low.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_low.active_time = active_time;
|
||||
wm_low.blank_time = line_time - wm_low.active_time;
|
||||
wm_low.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
@@ -1175,6 +1162,8 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
|
||||
c.full = dfixed_div(c, a);
|
||||
priority_b_mark = dfixed_trunc(c);
|
||||
priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
|
||||
|
||||
lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
|
||||
}
|
||||
|
||||
/* select wm A */
|
||||
@@ -1204,6 +1193,9 @@ static void dce_v6_0_program_watermarks(struct amdgpu_device *adev,
|
||||
/* save values for DPM */
|
||||
amdgpu_crtc->line_time = line_time;
|
||||
amdgpu_crtc->wm_high = latency_watermark_a;
|
||||
|
||||
/* Save number of lines the linebuffer leads before the scanout */
|
||||
amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
|
||||
}
|
||||
|
||||
/* watermark setup */
|
||||
|
||||
@@ -1094,23 +1094,10 @@ static u32 dce_v8_0_latency_watermark(struct dce8_wm_params *wm)
|
||||
a.full = dfixed_const(available_bandwidth);
|
||||
b.full = dfixed_const(wm->num_heads);
|
||||
a.full = dfixed_div(a, b);
|
||||
tmp = div_u64((u64) dmif_size * (u64) wm->disp_clk, mc_latency + 512);
|
||||
tmp = min(dfixed_trunc(a), tmp);
|
||||
|
||||
b.full = dfixed_const(mc_latency + 512);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(b, c);
|
||||
|
||||
c.full = dfixed_const(dmif_size);
|
||||
b.full = dfixed_div(c, b);
|
||||
|
||||
tmp = min(dfixed_trunc(a), dfixed_trunc(b));
|
||||
|
||||
b.full = dfixed_const(1000);
|
||||
c.full = dfixed_const(wm->disp_clk);
|
||||
b.full = dfixed_div(c, b);
|
||||
c.full = dfixed_const(wm->bytes_per_pixel);
|
||||
b.full = dfixed_mul(b, c);
|
||||
|
||||
lb_fill_bw = min(tmp, dfixed_trunc(b));
|
||||
lb_fill_bw = min(tmp, wm->disp_clk * wm->bytes_per_pixel / 1000);
|
||||
|
||||
a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
|
||||
b.full = dfixed_const(1000);
|
||||
@@ -1218,14 +1205,14 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
|
||||
{
|
||||
struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
|
||||
struct dce8_wm_params wm_low, wm_high;
|
||||
u32 pixel_period;
|
||||
u32 active_time;
|
||||
u32 line_time = 0;
|
||||
u32 latency_watermark_a = 0, latency_watermark_b = 0;
|
||||
u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
|
||||
|
||||
if (amdgpu_crtc->base.enabled && num_heads && mode) {
|
||||
pixel_period = 1000000 / (u32)mode->clock;
|
||||
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
|
||||
active_time = 1000000UL * (u32)mode->crtc_hdisplay / (u32)mode->clock;
|
||||
line_time = min((u32) (1000000UL * (u32)mode->crtc_htotal / (u32)mode->clock), (u32)65535);
|
||||
|
||||
/* watermark for high clocks */
|
||||
if (adev->pm.dpm_enabled) {
|
||||
@@ -1240,7 +1227,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_high.disp_clk = mode->clock;
|
||||
wm_high.src_width = mode->crtc_hdisplay;
|
||||
wm_high.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_high.active_time = active_time;
|
||||
wm_high.blank_time = line_time - wm_high.active_time;
|
||||
wm_high.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
@@ -1279,7 +1266,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
|
||||
|
||||
wm_low.disp_clk = mode->clock;
|
||||
wm_low.src_width = mode->crtc_hdisplay;
|
||||
wm_low.active_time = mode->crtc_hdisplay * pixel_period;
|
||||
wm_low.active_time = active_time;
|
||||
wm_low.blank_time = line_time - wm_low.active_time;
|
||||
wm_low.interlaced = false;
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
|
||||
+281
-45
@@ -30,6 +30,7 @@
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_mode.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <linux/sync_file.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
@@ -292,6 +293,23 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
|
||||
|
||||
static void set_out_fence_for_crtc(struct drm_atomic_state *state,
|
||||
struct drm_crtc *crtc, s32 __user *fence_ptr)
|
||||
{
|
||||
state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
|
||||
}
|
||||
|
||||
static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
s32 __user *fence_ptr;
|
||||
|
||||
fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
|
||||
state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
|
||||
|
||||
return fence_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_set_mode_for_crtc - set mode for CRTC
|
||||
* @state: the CRTC whose incoming state to update
|
||||
@@ -496,6 +514,16 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
|
||||
&replaced);
|
||||
state->color_mgmt_changed |= replaced;
|
||||
return ret;
|
||||
} else if (property == config->prop_out_fence_ptr) {
|
||||
s32 __user *fence_ptr = u64_to_user_ptr(val);
|
||||
|
||||
if (!fence_ptr)
|
||||
return 0;
|
||||
|
||||
if (put_user(-1, fence_ptr))
|
||||
return -EFAULT;
|
||||
|
||||
set_out_fence_for_crtc(state->state, crtc, fence_ptr);
|
||||
} else if (crtc->funcs->atomic_set_property)
|
||||
return crtc->funcs->atomic_set_property(crtc, state, property, val);
|
||||
else
|
||||
@@ -538,6 +566,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
|
||||
*val = (state->ctm) ? state->ctm->base.id : 0;
|
||||
else if (property == config->gamma_lut_property)
|
||||
*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
|
||||
else if (property == config->prop_out_fence_ptr)
|
||||
*val = 0;
|
||||
else if (crtc->funcs->atomic_get_property)
|
||||
return crtc->funcs->atomic_get_property(crtc, state, property, val);
|
||||
else
|
||||
@@ -693,6 +723,17 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,
|
||||
drm_atomic_set_fb_for_plane(state, fb);
|
||||
if (fb)
|
||||
drm_framebuffer_unreference(fb);
|
||||
} else if (property == config->prop_in_fence_fd) {
|
||||
if (state->fence)
|
||||
return -EINVAL;
|
||||
|
||||
if (U642I64(val) == -1)
|
||||
return 0;
|
||||
|
||||
state->fence = sync_file_get_fence(val);
|
||||
if (!state->fence)
|
||||
return -EINVAL;
|
||||
|
||||
} else if (property == config->prop_crtc_id) {
|
||||
struct drm_crtc *crtc = drm_crtc_find(dev, val);
|
||||
return drm_atomic_set_crtc_for_plane(state, crtc);
|
||||
@@ -752,6 +793,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
|
||||
|
||||
if (property == config->prop_fb_id) {
|
||||
*val = (state->fb) ? state->fb->base.id : 0;
|
||||
} else if (property == config->prop_in_fence_fd) {
|
||||
*val = -1;
|
||||
} else if (property == config->prop_crtc_id) {
|
||||
*val = (state->crtc) ? state->crtc->base.id : 0;
|
||||
} else if (property == config->prop_crtc_x) {
|
||||
@@ -1151,6 +1194,36 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
|
||||
|
||||
/**
|
||||
* drm_atomic_set_fence_for_plane - set fence for plane
|
||||
* @plane_state: atomic state object for the plane
|
||||
* @fence: fence to use for the plane
|
||||
*
|
||||
* Helper to setup the plane_state fence in case it is not set yet.
|
||||
* By using this drivers doesn't need to worry if the user choose
|
||||
* implicit or explicit fencing.
|
||||
*
|
||||
* This function will not set the fence to the state if it was set
|
||||
* via explicit fencing interfaces on the atomic ioctl. It will
|
||||
* all drope the reference to the fence as we not storing it
|
||||
* anywhere.
|
||||
*
|
||||
* Otherwise, if plane_state->fence is not set this function we
|
||||
* just set it with the received implict fence.
|
||||
*/
|
||||
void
|
||||
drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
|
||||
struct fence *fence)
|
||||
{
|
||||
if (plane_state->fence) {
|
||||
fence_put(fence);
|
||||
return;
|
||||
}
|
||||
|
||||
plane_state->fence = fence;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
|
||||
|
||||
/**
|
||||
* drm_atomic_set_crtc_for_connector - set crtc for connector
|
||||
* @conn_state: atomic state object for the connector
|
||||
@@ -1467,11 +1540,9 @@ EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
|
||||
*/
|
||||
|
||||
static struct drm_pending_vblank_event *create_vblank_event(
|
||||
struct drm_device *dev, struct drm_file *file_priv,
|
||||
struct fence *fence, uint64_t user_data)
|
||||
struct drm_device *dev, uint64_t user_data)
|
||||
{
|
||||
struct drm_pending_vblank_event *e = NULL;
|
||||
int ret;
|
||||
|
||||
e = kzalloc(sizeof *e, GFP_KERNEL);
|
||||
if (!e)
|
||||
@@ -1481,17 +1552,6 @@ static struct drm_pending_vblank_event *create_vblank_event(
|
||||
e->event.base.length = sizeof(e->event);
|
||||
e->event.user_data = user_data;
|
||||
|
||||
if (file_priv) {
|
||||
ret = drm_event_reserve_init(dev, file_priv, &e->base,
|
||||
&e->event.base);
|
||||
if (ret) {
|
||||
kfree(e);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
e->base.fence = fence;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -1596,6 +1656,206 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_clean_old_fb);
|
||||
|
||||
/**
|
||||
* DOC: explicit fencing properties
|
||||
*
|
||||
* Explicit fencing allows userspace to control the buffer synchronization
|
||||
* between devices. A Fence or a group of fences are transfered to/from
|
||||
* userspace using Sync File fds and there are two DRM properties for that.
|
||||
* IN_FENCE_FD on each DRM Plane to send fences to the kernel and
|
||||
* OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
|
||||
*
|
||||
* As a contrast, with implicit fencing the kernel keeps track of any
|
||||
* ongoing rendering, and automatically ensures that the atomic update waits
|
||||
* for any pending rendering to complete. For shared buffers represented with
|
||||
* a struct &dma_buf this is tracked in &reservation_object structures.
|
||||
* Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org),
|
||||
* whereas explicit fencing is what Android wants.
|
||||
*
|
||||
* "IN_FENCE_FD”:
|
||||
* Use this property to pass a fence that DRM should wait on before
|
||||
* proceeding with the Atomic Commit request and show the framebuffer for
|
||||
* the plane on the screen. The fence can be either a normal fence or a
|
||||
* merged one, the sync_file framework will handle both cases and use a
|
||||
* fence_array if a merged fence is received. Passing -1 here means no
|
||||
* fences to wait on.
|
||||
*
|
||||
* If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag
|
||||
* it will only check if the Sync File is a valid one.
|
||||
*
|
||||
* On the driver side the fence is stored on the @fence parameter of
|
||||
* struct &drm_plane_state. Drivers which also support implicit fencing
|
||||
* should set the implicit fence using drm_atomic_set_fence_for_plane(),
|
||||
* to make sure there's consistent behaviour between drivers in precedence
|
||||
* of implicit vs. explicit fencing.
|
||||
*
|
||||
* "OUT_FENCE_PTR”:
|
||||
* Use this property to pass a file descriptor pointer to DRM. Once the
|
||||
* Atomic Commit request call returns OUT_FENCE_PTR will be filled with
|
||||
* the file descriptor number of a Sync File. This Sync File contains the
|
||||
* CRTC fence that will be signaled when all framebuffers present on the
|
||||
* Atomic Commit * request for that given CRTC are scanned out on the
|
||||
* screen.
|
||||
*
|
||||
* The Atomic Commit request fails if a invalid pointer is passed. If the
|
||||
* Atomic Commit request fails for any other reason the out fence fd
|
||||
* returned will be -1. On a Atomic Commit with the
|
||||
* DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1.
|
||||
*
|
||||
* Note that out-fences don't have a special interface to drivers and are
|
||||
* internally represented by a struct &drm_pending_vblank_event in struct
|
||||
* &drm_crtc_state, which is also used by the nonblocking atomic commit
|
||||
* helpers and for the DRM event handling for existing userspace.
|
||||
*/
|
||||
|
||||
struct drm_out_fence_state {
|
||||
s32 __user *out_fence_ptr;
|
||||
struct sync_file *sync_file;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int setup_out_fence(struct drm_out_fence_state *fence_state,
|
||||
struct fence *fence)
|
||||
{
|
||||
fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fence_state->fd < 0)
|
||||
return fence_state->fd;
|
||||
|
||||
if (put_user(fence_state->fd, fence_state->out_fence_ptr))
|
||||
return -EFAULT;
|
||||
|
||||
fence_state->sync_file = sync_file_create(fence);
|
||||
if (!fence_state->sync_file)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_crtc_signaling(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
struct drm_mode_atomic *arg,
|
||||
struct drm_file *file_priv,
|
||||
struct drm_out_fence_state **fence_state,
|
||||
unsigned int *num_fences)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int i, ret;
|
||||
|
||||
if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
|
||||
return 0;
|
||||
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
s32 __user *fence_ptr;
|
||||
|
||||
fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
|
||||
|
||||
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
|
||||
struct drm_pending_vblank_event *e;
|
||||
|
||||
e = create_vblank_event(dev, arg->user_data);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
crtc_state->event = e;
|
||||
}
|
||||
|
||||
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
struct drm_pending_vblank_event *e = crtc_state->event;
|
||||
|
||||
if (!file_priv)
|
||||
continue;
|
||||
|
||||
ret = drm_event_reserve_init(dev, file_priv, &e->base,
|
||||
&e->event.base);
|
||||
if (ret) {
|
||||
kfree(e);
|
||||
crtc_state->event = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (fence_ptr) {
|
||||
struct fence *fence;
|
||||
struct drm_out_fence_state *f;
|
||||
|
||||
f = krealloc(*fence_state, sizeof(**fence_state) *
|
||||
(*num_fences + 1), GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&f[*num_fences], 0, sizeof(*f));
|
||||
|
||||
f[*num_fences].out_fence_ptr = fence_ptr;
|
||||
*fence_state = f;
|
||||
|
||||
fence = drm_crtc_create_fence(crtc);
|
||||
if (!fence)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = setup_out_fence(&f[(*num_fences)++], fence);
|
||||
if (ret) {
|
||||
fence_put(fence);
|
||||
return ret;
|
||||
}
|
||||
|
||||
crtc_state->event->base.fence = fence;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void complete_crtc_signaling(struct drm_device *dev,
|
||||
struct drm_atomic_state *state,
|
||||
struct drm_out_fence_state *fence_state,
|
||||
unsigned int num_fences,
|
||||
bool install_fds)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int i;
|
||||
|
||||
if (install_fds) {
|
||||
for (i = 0; i < num_fences; i++)
|
||||
fd_install(fence_state[i].fd,
|
||||
fence_state[i].sync_file->file);
|
||||
|
||||
kfree(fence_state);
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct drm_pending_vblank_event *event = crtc_state->event;
|
||||
/*
|
||||
* Free the allocated event. drm_atomic_helper_setup_commit
|
||||
* can allocate an event too, so only free it if it's ours
|
||||
* to prevent a double free in drm_atomic_state_clear.
|
||||
*/
|
||||
if (event && (event->base.fence || event->base.file_priv)) {
|
||||
drm_event_cancel_free(dev, &event->base);
|
||||
crtc_state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fence_state)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_fences; i++) {
|
||||
if (fence_state[i].sync_file)
|
||||
fput(fence_state[i].sync_file->file);
|
||||
if (fence_state[i].fd >= 0)
|
||||
put_unused_fd(fence_state[i].fd);
|
||||
|
||||
/* If this fails log error to the user */
|
||||
if (fence_state[i].out_fence_ptr &&
|
||||
put_user(-1, fence_state[i].out_fence_ptr))
|
||||
DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
|
||||
}
|
||||
|
||||
kfree(fence_state);
|
||||
}
|
||||
|
||||
int drm_mode_atomic_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
@@ -1608,11 +1868,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_plane *plane;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_out_fence_state *fence_state = NULL;
|
||||
unsigned plane_mask;
|
||||
int ret = 0;
|
||||
unsigned int i, j;
|
||||
unsigned int i, j, num_fences = 0;
|
||||
|
||||
/* disallow for drivers not supporting atomic: */
|
||||
if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
|
||||
@@ -1727,20 +1986,10 @@ retry:
|
||||
drm_mode_object_unreference(obj);
|
||||
}
|
||||
|
||||
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct drm_pending_vblank_event *e;
|
||||
|
||||
e = create_vblank_event(dev, file_priv, NULL,
|
||||
arg->user_data);
|
||||
if (!e) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
crtc_state->event = e;
|
||||
}
|
||||
}
|
||||
ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state,
|
||||
&num_fences);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
|
||||
/*
|
||||
@@ -1757,20 +2006,7 @@ retry:
|
||||
out:
|
||||
drm_atomic_clean_old_fb(dev, plane_mask, ret);
|
||||
|
||||
if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
/*
|
||||
* Free the allocated event. drm_atomic_helper_setup_commit
|
||||
* can allocate an event too, so only free it if it's ours
|
||||
* to prevent a double free in drm_atomic_state_clear.
|
||||
*/
|
||||
for_each_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct drm_pending_vblank_event *event = crtc_state->event;
|
||||
if (event && (event->base.fence || event->base.file_priv)) {
|
||||
drm_event_cancel_free(dev, &event->base);
|
||||
crtc_state->event = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
complete_crtc_signaling(dev, state, fence_state, num_fences, !ret);
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
drm_atomic_state_clear(state);
|
||||
|
||||
@@ -3166,6 +3166,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
|
||||
{
|
||||
if (state->fb)
|
||||
drm_framebuffer_unreference(state->fb);
|
||||
|
||||
if (state->fence)
|
||||
fence_put(state->fence);
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/fence.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
@@ -141,6 +142,54 @@ static void drm_crtc_unregister_all(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static const struct fence_ops drm_crtc_fence_ops;
|
||||
|
||||
static struct drm_crtc *fence_to_crtc(struct fence *fence)
|
||||
{
|
||||
BUG_ON(fence->ops != &drm_crtc_fence_ops);
|
||||
return container_of(fence->lock, struct drm_crtc, fence_lock);
|
||||
}
|
||||
|
||||
static const char *drm_crtc_fence_get_driver_name(struct fence *fence)
|
||||
{
|
||||
struct drm_crtc *crtc = fence_to_crtc(fence);
|
||||
|
||||
return crtc->dev->driver->name;
|
||||
}
|
||||
|
||||
static const char *drm_crtc_fence_get_timeline_name(struct fence *fence)
|
||||
{
|
||||
struct drm_crtc *crtc = fence_to_crtc(fence);
|
||||
|
||||
return crtc->timeline_name;
|
||||
}
|
||||
|
||||
static bool drm_crtc_fence_enable_signaling(struct fence *fence)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct fence_ops drm_crtc_fence_ops = {
|
||||
.get_driver_name = drm_crtc_fence_get_driver_name,
|
||||
.get_timeline_name = drm_crtc_fence_get_timeline_name,
|
||||
.enable_signaling = drm_crtc_fence_enable_signaling,
|
||||
.wait = fence_default_wait,
|
||||
};
|
||||
|
||||
struct fence *drm_crtc_create_fence(struct drm_crtc *crtc)
|
||||
{
|
||||
struct fence *fence;
|
||||
|
||||
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
||||
if (!fence)
|
||||
return NULL;
|
||||
|
||||
fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock,
|
||||
crtc->fence_context, ++crtc->fence_seqno);
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_crtc_init_with_planes - Initialise a new CRTC object with
|
||||
* specified primary and cursor planes.
|
||||
@@ -198,6 +247,11 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
crtc->fence_context = fence_context_alloc(1);
|
||||
spin_lock_init(&crtc->fence_lock);
|
||||
snprintf(crtc->timeline_name, sizeof(crtc->timeline_name),
|
||||
"CRTC:%d-%s", crtc->base.id, crtc->name);
|
||||
|
||||
crtc->base.properties = &crtc->properties;
|
||||
|
||||
list_add_tail(&crtc->head, &config->crtc_list);
|
||||
@@ -213,6 +267,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
|
||||
drm_object_attach_property(&crtc->base, config->prop_active, 0);
|
||||
drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
|
||||
drm_object_attach_property(&crtc->base,
|
||||
config->prop_out_fence_ptr, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -365,6 +421,18 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
|
||||
return -ENOMEM;
|
||||
dev->mode_config.prop_fb_id = prop;
|
||||
|
||||
prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
|
||||
"IN_FENCE_FD", -1, INT_MAX);
|
||||
if (!prop)
|
||||
return -ENOMEM;
|
||||
dev->mode_config.prop_in_fence_fd = prop;
|
||||
|
||||
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
|
||||
"OUT_FENCE_PTR", 0, U64_MAX);
|
||||
if (!prop)
|
||||
return -ENOMEM;
|
||||
dev->mode_config.prop_out_fence_ptr = prop;
|
||||
|
||||
prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
|
||||
"CRTC_ID", DRM_MODE_OBJECT_CRTC);
|
||||
if (!prop)
|
||||
|
||||
@@ -41,6 +41,8 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_framebuffer *fb);
|
||||
|
||||
struct fence *drm_crtc_create_fence(struct drm_crtc *crtc);
|
||||
|
||||
void drm_fb_release(struct drm_file *file_priv);
|
||||
|
||||
/* dumb buffer support IOCTLs */
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
#define EDID_QUIRK_FORCE_12BPC (1 << 9)
|
||||
/* Force 6bpc */
|
||||
#define EDID_QUIRK_FORCE_6BPC (1 << 10)
|
||||
/* Force 10bpc */
|
||||
#define EDID_QUIRK_FORCE_10BPC (1 << 11)
|
||||
|
||||
struct detailed_mode_closure {
|
||||
struct drm_connector *connector;
|
||||
@@ -118,6 +120,9 @@ static const struct edid_quirk {
|
||||
{ "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
|
||||
EDID_QUIRK_DETAILED_IN_CM },
|
||||
|
||||
/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
|
||||
{ "LGD", 764, EDID_QUIRK_FORCE_10BPC },
|
||||
|
||||
/* LG Philips LCD LP154W01-A5 */
|
||||
{ "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
|
||||
{ "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
|
||||
@@ -4105,6 +4110,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||
if (quirks & EDID_QUIRK_FORCE_8BPC)
|
||||
connector->display_info.bpc = 8;
|
||||
|
||||
if (quirks & EDID_QUIRK_FORCE_10BPC)
|
||||
connector->display_info.bpc = 10;
|
||||
|
||||
if (quirks & EDID_QUIRK_FORCE_12BPC)
|
||||
connector->display_info.bpc = 12;
|
||||
|
||||
|
||||
@@ -18,13 +18,16 @@
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/reservation.h>
|
||||
|
||||
#define DEFAULT_FBDEFIO_DELAY_MS 50
|
||||
#ifdef CONFIG_DRM_CMA_FBDEV_BUFFER_NUM
|
||||
@@ -270,6 +273,38 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
|
||||
|
||||
/**
|
||||
* drm_fb_cma_prepare_fb() - Prepare CMA framebuffer
|
||||
* @plane: Which plane
|
||||
* @state: Plane state attach fence to
|
||||
*
|
||||
* This should be put into prepare_fb hook of struct &drm_plane_helper_funcs .
|
||||
*
|
||||
* This function checks if the plane FB has an dma-buf attached, extracts
|
||||
* the exclusive fence and attaches it to plane state for the atomic helper
|
||||
* to wait on.
|
||||
*
|
||||
* There is no need for cleanup_fb for CMA based framebuffer drivers.
|
||||
*/
|
||||
int drm_fb_cma_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
struct dma_buf *dma_buf;
|
||||
struct fence *fence;
|
||||
|
||||
if ((plane->state->fb == state->fb) || !state->fb)
|
||||
return 0;
|
||||
|
||||
dma_buf = drm_fb_cma_get_gem_obj(state->fb, 0)->base.dma_buf;
|
||||
if (dma_buf) {
|
||||
fence = reservation_object_get_excl_rcu(dma_buf->resv);
|
||||
drm_atomic_set_fence_for_plane(state, fence);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_fb_cma_prepare_fb);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m)
|
||||
{
|
||||
|
||||
@@ -663,6 +663,10 @@ void drm_event_cancel_free(struct drm_device *dev,
|
||||
list_del(&p->pending_link);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
if (p->fence)
|
||||
fence_put(p->fence);
|
||||
|
||||
kfree(p);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_event_cancel_free);
|
||||
|
||||
@@ -137,6 +137,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
|
||||
drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
|
||||
drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
|
||||
drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
|
||||
drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
|
||||
drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
|
||||
|
||||
@@ -420,6 +420,11 @@ int i915_gem_init_stolen(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (intel_vgpu_active(dev_priv)) {
|
||||
DRM_INFO("iGVT-g active, disabling use of stolen memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INTEL_IOMMU
|
||||
if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) {
|
||||
DRM_INFO("DMAR active, disabling use of stolen memory\n");
|
||||
|
||||
@@ -130,7 +130,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode)
|
||||
poll = false;
|
||||
}
|
||||
|
||||
if (list_empty(&therm->alarm.head) && poll)
|
||||
if (poll)
|
||||
nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm);
|
||||
spin_unlock_irqrestore(&therm->lock, flags);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target)
|
||||
spin_unlock_irqrestore(&fan->lock, flags);
|
||||
|
||||
/* schedule next fan update, if not at target speed already */
|
||||
if (list_empty(&fan->alarm.head) && target != duty) {
|
||||
if (target != duty) {
|
||||
u16 bump_period = fan->bios.bump_period;
|
||||
u16 slow_down_period = fan->bios.slow_down_period;
|
||||
u64 delay;
|
||||
|
||||
@@ -53,7 +53,7 @@ nvkm_fantog_update(struct nvkm_fantog *fan, int percent)
|
||||
duty = !nvkm_gpio_get(gpio, 0, DCB_GPIO_FAN, 0xff);
|
||||
nvkm_gpio_set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
|
||||
|
||||
if (list_empty(&fan->alarm.head) && percent != (duty * 100)) {
|
||||
if (percent != (duty * 100)) {
|
||||
u64 next_change = (percent * fan->period_us) / 100;
|
||||
if (!duty)
|
||||
next_change = fan->period_us - next_change;
|
||||
|
||||
@@ -185,7 +185,7 @@ alarm_timer_callback(struct nvkm_alarm *alarm)
|
||||
spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags);
|
||||
|
||||
/* schedule the next poll in one second */
|
||||
if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head))
|
||||
if (therm->func->temp_get(therm) >= 0)
|
||||
nvkm_timer_alarm(tmr, 1000000000ULL, alarm);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,23 +36,29 @@ nvkm_timer_alarm_trigger(struct nvkm_timer *tmr)
|
||||
unsigned long flags;
|
||||
LIST_HEAD(exec);
|
||||
|
||||
/* move any due alarms off the pending list */
|
||||
/* Process pending alarms. */
|
||||
spin_lock_irqsave(&tmr->lock, flags);
|
||||
list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) {
|
||||
if (alarm->timestamp <= nvkm_timer_read(tmr))
|
||||
list_move_tail(&alarm->head, &exec);
|
||||
/* Have we hit the earliest alarm that hasn't gone off? */
|
||||
if (alarm->timestamp > nvkm_timer_read(tmr)) {
|
||||
/* Schedule it. If we didn't race, we're done. */
|
||||
tmr->func->alarm_init(tmr, alarm->timestamp);
|
||||
if (alarm->timestamp > nvkm_timer_read(tmr))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move to completed list. We'll drop the lock before
|
||||
* executing the callback so it can reschedule itself.
|
||||
*/
|
||||
list_move_tail(&alarm->head, &exec);
|
||||
}
|
||||
|
||||
/* reschedule interrupt for next alarm time */
|
||||
if (!list_empty(&tmr->alarms)) {
|
||||
alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head);
|
||||
tmr->func->alarm_init(tmr, alarm->timestamp);
|
||||
} else {
|
||||
/* Shut down interrupt if no more pending alarms. */
|
||||
if (list_empty(&tmr->alarms))
|
||||
tmr->func->alarm_fini(tmr);
|
||||
}
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
|
||||
/* execute any pending alarm handlers */
|
||||
/* Execute completed callbacks. */
|
||||
list_for_each_entry_safe(alarm, atemp, &exec, head) {
|
||||
list_del_init(&alarm->head);
|
||||
alarm->func(alarm);
|
||||
@@ -65,24 +71,37 @@ nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm)
|
||||
struct nvkm_alarm *list;
|
||||
unsigned long flags;
|
||||
|
||||
alarm->timestamp = nvkm_timer_read(tmr) + nsec;
|
||||
|
||||
/* append new alarm to list, in soonest-alarm-first order */
|
||||
/* Remove alarm from pending list.
|
||||
*
|
||||
* This both protects against the corruption of the list,
|
||||
* and implements alarm rescheduling/cancellation.
|
||||
*/
|
||||
spin_lock_irqsave(&tmr->lock, flags);
|
||||
if (!nsec) {
|
||||
if (!list_empty(&alarm->head))
|
||||
list_del(&alarm->head);
|
||||
} else {
|
||||
list_del_init(&alarm->head);
|
||||
|
||||
if (nsec) {
|
||||
/* Insert into pending list, ordered earliest to latest. */
|
||||
alarm->timestamp = nvkm_timer_read(tmr) + nsec;
|
||||
list_for_each_entry(list, &tmr->alarms, head) {
|
||||
if (list->timestamp > alarm->timestamp)
|
||||
break;
|
||||
}
|
||||
|
||||
list_add_tail(&alarm->head, &list->head);
|
||||
|
||||
/* Update HW if this is now the earliest alarm. */
|
||||
list = list_first_entry(&tmr->alarms, typeof(*list), head);
|
||||
if (list == alarm) {
|
||||
tmr->func->alarm_init(tmr, alarm->timestamp);
|
||||
/* This shouldn't happen if callers aren't stupid.
|
||||
*
|
||||
* Worst case scenario is that it'll take roughly
|
||||
* 4 seconds for the next alarm to trigger.
|
||||
*/
|
||||
WARN_ON(alarm->timestamp <= nvkm_timer_read(tmr));
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&tmr->lock, flags);
|
||||
|
||||
/* process pending alarms */
|
||||
nvkm_timer_alarm_trigger(tmr);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -76,8 +76,8 @@ nv04_timer_intr(struct nvkm_timer *tmr)
|
||||
u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0);
|
||||
|
||||
if (stat & 0x00000001) {
|
||||
nvkm_timer_alarm_trigger(tmr);
|
||||
nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001);
|
||||
nvkm_timer_alarm_trigger(tmr);
|
||||
stat &= ~0x00000001;
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -28,6 +28,8 @@
|
||||
#define UHID_NAME "uhid"
|
||||
#define UHID_BUFSIZE 32
|
||||
|
||||
static DEFINE_MUTEX(uhid_open_mutex);
|
||||
|
||||
struct uhid_device {
|
||||
struct mutex devlock;
|
||||
bool running;
|
||||
@@ -142,15 +144,26 @@ static void uhid_hid_stop(struct hid_device *hid)
|
||||
static int uhid_hid_open(struct hid_device *hid)
|
||||
{
|
||||
struct uhid_device *uhid = hid->driver_data;
|
||||
int retval = 0;
|
||||
|
||||
return uhid_queue_event(uhid, UHID_OPEN);
|
||||
mutex_lock(&uhid_open_mutex);
|
||||
if (!hid->open++) {
|
||||
retval = uhid_queue_event(uhid, UHID_OPEN);
|
||||
if (retval)
|
||||
hid->open--;
|
||||
}
|
||||
mutex_unlock(&uhid_open_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void uhid_hid_close(struct hid_device *hid)
|
||||
{
|
||||
struct uhid_device *uhid = hid->driver_data;
|
||||
|
||||
uhid_queue_event(uhid, UHID_CLOSE);
|
||||
mutex_lock(&uhid_open_mutex);
|
||||
if (!--hid->open)
|
||||
uhid_queue_event(uhid, UHID_CLOSE);
|
||||
mutex_unlock(&uhid_open_mutex);
|
||||
}
|
||||
|
||||
static int uhid_hid_parse(struct hid_device *hid)
|
||||
|
||||
@@ -217,7 +217,15 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
|
||||
if (ret < 0 || value < 0)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->poll.report_id,
|
||||
st->poll.index, sizeof(value), &value);
|
||||
if (ret < 0 || value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
st->poll_interval = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
|
||||
|
||||
@@ -259,7 +267,16 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
|
||||
if (ret < 0 || value < 0)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->sensitivity.report_id,
|
||||
st->sensitivity.index, sizeof(value),
|
||||
&value);
|
||||
if (ret < 0 || value < 0)
|
||||
return -EINVAL;
|
||||
|
||||
st->raw_hystersis = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
|
||||
|
||||
@@ -355,6 +372,9 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
|
||||
/* Default unit of measure is milliseconds */
|
||||
if (st->poll.units == 0)
|
||||
st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND;
|
||||
|
||||
st->poll_interval = -1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -377,6 +397,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
|
||||
HID_USAGE_SENSOR_PROY_POWER_STATE,
|
||||
&st->power_state);
|
||||
|
||||
st->raw_hystersis = -1;
|
||||
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
|
||||
|
||||
@@ -51,6 +51,8 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
|
||||
st->report_state.report_id,
|
||||
st->report_state.index,
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
|
||||
|
||||
poll_value = hid_sensor_read_poll_value(st);
|
||||
} else {
|
||||
int val;
|
||||
|
||||
@@ -87,9 +89,7 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
|
||||
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
sizeof(state_val), &state_val);
|
||||
if (state)
|
||||
poll_value = hid_sensor_read_poll_value(st);
|
||||
if (poll_value > 0)
|
||||
if (state && poll_value)
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
return 0;
|
||||
@@ -127,6 +127,20 @@ static void hid_sensor_set_power_work(struct work_struct *work)
|
||||
struct hid_sensor_common *attrb = container_of(work,
|
||||
struct hid_sensor_common,
|
||||
work);
|
||||
|
||||
if (attrb->poll_interval >= 0)
|
||||
sensor_hub_set_feature(attrb->hsdev, attrb->poll.report_id,
|
||||
attrb->poll.index,
|
||||
sizeof(attrb->poll_interval),
|
||||
&attrb->poll_interval);
|
||||
|
||||
if (attrb->raw_hystersis >= 0)
|
||||
sensor_hub_set_feature(attrb->hsdev,
|
||||
attrb->sensitivity.report_id,
|
||||
attrb->sensitivity.index,
|
||||
sizeof(attrb->raw_hystersis),
|
||||
&attrb->raw_hystersis);
|
||||
|
||||
_hid_sensor_power_state(attrb, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,9 +184,9 @@ static const struct iio_chan_spec_ext_info ad7303_ext_info[] = {
|
||||
.address = (chan), \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = '8', \
|
||||
.storagebits = '8', \
|
||||
.shift = '0', \
|
||||
.realbits = 8, \
|
||||
.storagebits = 8, \
|
||||
.shift = 0, \
|
||||
}, \
|
||||
.ext_info = ad7303_ext_info, \
|
||||
}
|
||||
|
||||
@@ -175,11 +175,12 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data,
|
||||
}
|
||||
H6 = sign_extend32(tmp, 7);
|
||||
|
||||
var = ((s32)data->t_fine) - 76800;
|
||||
var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15)
|
||||
* (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10)
|
||||
+ 2097152) * H2 + 8192) >> 14);
|
||||
var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4;
|
||||
var = ((s32)data->t_fine) - (s32)76800;
|
||||
var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var))
|
||||
+ (s32)16384) >> 15) * (((((((var * H6) >> 10)
|
||||
* (((var * (s32)H3) >> 11) + (s32)32768)) >> 10)
|
||||
+ (s32)2097152) * H2 + 8192) >> 14);
|
||||
var -= ((((var >> 15) * (var >> 15)) >> 7) * (s32)H1) >> 4;
|
||||
|
||||
return var >> 12;
|
||||
};
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#define AS3935_TUNE_CAP 0x08
|
||||
#define AS3935_CALIBRATE 0x3D
|
||||
|
||||
#define AS3935_WRITE_DATA BIT(15)
|
||||
#define AS3935_READ_DATA BIT(14)
|
||||
#define AS3935_ADDRESS(x) ((x) << 8)
|
||||
|
||||
@@ -105,7 +104,7 @@ static int as3935_write(struct as3935_state *st,
|
||||
{
|
||||
u8 *buf = st->buf;
|
||||
|
||||
buf[0] = (AS3935_WRITE_DATA | AS3935_ADDRESS(reg)) >> 8;
|
||||
buf[0] = AS3935_ADDRESS(reg) >> 8;
|
||||
buf[1] = val;
|
||||
|
||||
return spi_write(st->spi, buf, 2);
|
||||
|
||||
@@ -444,8 +444,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
|
||||
fl6.saddr = src_in->sin6_addr;
|
||||
fl6.flowi6_oif = addr->bound_dev_if;
|
||||
|
||||
dst = ip6_route_output(addr->net, NULL, &fl6);
|
||||
if ((ret = dst->error))
|
||||
ret = ipv6_stub->ipv6_dst_lookup(addr->net, NULL, &dst, &fl6);
|
||||
if (ret < 0)
|
||||
goto put;
|
||||
|
||||
rt = (struct rt6_info *)dst;
|
||||
|
||||
@@ -751,6 +751,9 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
|
||||
/* release the cpu */
|
||||
hfi1_put_proc_affinity(fdata->rec_cpu_num);
|
||||
|
||||
/* clean up rcv side */
|
||||
hfi1_user_exp_rcv_free(fdata);
|
||||
|
||||
/*
|
||||
* Clear any left over, unhandled events so the next process that
|
||||
* gets this context doesn't get confused.
|
||||
@@ -790,7 +793,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
|
||||
|
||||
dd->rcd[uctxt->ctxt] = NULL;
|
||||
|
||||
hfi1_user_exp_rcv_free(fdata);
|
||||
hfi1_user_exp_rcv_grp_free(uctxt);
|
||||
hfi1_clear_ctxt_pkey(dd, uctxt->ctxt);
|
||||
|
||||
uctxt->rcvwait_to = 0;
|
||||
|
||||
@@ -1757,6 +1757,7 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
|
||||
!HFI1_CAP_KGET_MASK(rcd->flags, MULTI_PKT_EGR)) {
|
||||
dd_dev_err(dd, "ctxt%u: Failed to allocate eager buffers\n",
|
||||
rcd->ctxt);
|
||||
ret = -ENOMEM;
|
||||
goto bail_rcvegrbuf_phys;
|
||||
}
|
||||
|
||||
|
||||
@@ -250,36 +250,40 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt)
|
||||
{
|
||||
struct tid_group *grp, *gptr;
|
||||
|
||||
list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list,
|
||||
list) {
|
||||
list_del_init(&grp->list);
|
||||
kfree(grp);
|
||||
}
|
||||
hfi1_clear_tids(uctxt);
|
||||
}
|
||||
|
||||
int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd)
|
||||
{
|
||||
struct hfi1_ctxtdata *uctxt = fd->uctxt;
|
||||
struct tid_group *grp, *gptr;
|
||||
|
||||
if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags))
|
||||
return 0;
|
||||
/*
|
||||
* The notifier would have been removed when the process'es mm
|
||||
* was freed.
|
||||
*/
|
||||
if (fd->handler)
|
||||
if (fd->handler) {
|
||||
hfi1_mmu_rb_unregister(fd->handler);
|
||||
|
||||
kfree(fd->invalid_tids);
|
||||
|
||||
if (!uctxt->cnt) {
|
||||
} else {
|
||||
if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list))
|
||||
unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd);
|
||||
if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list))
|
||||
unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd);
|
||||
list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list,
|
||||
list) {
|
||||
list_del_init(&grp->list);
|
||||
kfree(grp);
|
||||
}
|
||||
hfi1_clear_tids(uctxt);
|
||||
}
|
||||
|
||||
kfree(fd->invalid_tids);
|
||||
fd->invalid_tids = NULL;
|
||||
|
||||
kfree(fd->entry_to_rb);
|
||||
fd->entry_to_rb = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
(tid) |= EXP_TID_SET(field, (value)); \
|
||||
} while (0)
|
||||
|
||||
void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt);
|
||||
int hfi1_user_exp_rcv_init(struct file *);
|
||||
int hfi1_user_exp_rcv_free(struct hfi1_filedata *);
|
||||
int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *);
|
||||
|
||||
@@ -1828,7 +1828,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
|
||||
klms[i].va = cpu_to_be64(sg_dma_address(sg) + sg_offset);
|
||||
klms[i].bcount = cpu_to_be32(sg_dma_len(sg) - sg_offset);
|
||||
klms[i].key = cpu_to_be32(lkey);
|
||||
mr->ibmr.length += sg_dma_len(sg);
|
||||
mr->ibmr.length += sg_dma_len(sg) - sg_offset;
|
||||
|
||||
sg_offset = 0;
|
||||
}
|
||||
|
||||
@@ -2049,11 +2049,14 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
|
||||
if (context_copied(context)) {
|
||||
u16 did_old = context_domain_id(context);
|
||||
|
||||
if (did_old >= 0 && did_old < cap_ndoms(iommu->cap))
|
||||
if (did_old >= 0 && did_old < cap_ndoms(iommu->cap)) {
|
||||
iommu->flush.flush_context(iommu, did_old,
|
||||
(((u16)bus) << 8) | devfn,
|
||||
DMA_CCMD_MASK_NOBIT,
|
||||
DMA_CCMD_DEVICE_INVL);
|
||||
iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
|
||||
DMA_TLB_DSI_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
pgd = domain->pgd;
|
||||
|
||||
@@ -357,6 +357,7 @@ config DM_LOG_USERSPACE
|
||||
config DM_RAID
|
||||
tristate "RAID 1/4/5/6/10 target"
|
||||
depends on BLK_DEV_DM
|
||||
select MD_RAID0
|
||||
select MD_RAID1
|
||||
select MD_RAID10
|
||||
select MD_RAID456
|
||||
|
||||
+23
-12
@@ -215,7 +215,7 @@ static DEFINE_SPINLOCK(param_spinlock);
|
||||
* Buffers are freed after this timeout
|
||||
*/
|
||||
static unsigned dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS;
|
||||
static unsigned dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
|
||||
static unsigned long dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
|
||||
|
||||
static unsigned long dm_bufio_peak_allocated;
|
||||
static unsigned long dm_bufio_allocated_kmem_cache;
|
||||
@@ -923,10 +923,11 @@ static void __get_memory_limit(struct dm_bufio_client *c,
|
||||
{
|
||||
unsigned long buffers;
|
||||
|
||||
if (ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch) {
|
||||
mutex_lock(&dm_bufio_clients_lock);
|
||||
__cache_size_refresh();
|
||||
mutex_unlock(&dm_bufio_clients_lock);
|
||||
if (unlikely(ACCESS_ONCE(dm_bufio_cache_size) != dm_bufio_cache_size_latch)) {
|
||||
if (mutex_trylock(&dm_bufio_clients_lock)) {
|
||||
__cache_size_refresh();
|
||||
mutex_unlock(&dm_bufio_clients_lock);
|
||||
}
|
||||
}
|
||||
|
||||
buffers = dm_bufio_cache_size_per_client >>
|
||||
@@ -1540,10 +1541,10 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned get_retain_buffers(struct dm_bufio_client *c)
|
||||
static unsigned long get_retain_buffers(struct dm_bufio_client *c)
|
||||
{
|
||||
unsigned retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
|
||||
return retain_bytes / c->block_size;
|
||||
unsigned long retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
|
||||
return retain_bytes >> (c->sectors_per_block_bits + SECTOR_SHIFT);
|
||||
}
|
||||
|
||||
static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
|
||||
@@ -1553,7 +1554,7 @@ static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
|
||||
struct dm_buffer *b, *tmp;
|
||||
unsigned long freed = 0;
|
||||
unsigned long count = nr_to_scan;
|
||||
unsigned retain_target = get_retain_buffers(c);
|
||||
unsigned long retain_target = get_retain_buffers(c);
|
||||
|
||||
for (l = 0; l < LIST_SIZE; l++) {
|
||||
list_for_each_entry_safe_reverse(b, tmp, &c->lru[l], lru_list) {
|
||||
@@ -1779,11 +1780,19 @@ static bool older_than(struct dm_buffer *b, unsigned long age_hz)
|
||||
static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
|
||||
{
|
||||
struct dm_buffer *b, *tmp;
|
||||
unsigned retain_target = get_retain_buffers(c);
|
||||
unsigned count;
|
||||
unsigned long retain_target = get_retain_buffers(c);
|
||||
unsigned long count;
|
||||
LIST_HEAD(write_list);
|
||||
|
||||
dm_bufio_lock(c);
|
||||
|
||||
__check_watermark(c, &write_list);
|
||||
if (unlikely(!list_empty(&write_list))) {
|
||||
dm_bufio_unlock(c);
|
||||
__flush_write_list(&write_list);
|
||||
dm_bufio_lock(c);
|
||||
}
|
||||
|
||||
count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
|
||||
list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_CLEAN], lru_list) {
|
||||
if (count <= retain_target)
|
||||
@@ -1808,6 +1817,8 @@ static void cleanup_old_buffers(void)
|
||||
|
||||
mutex_lock(&dm_bufio_clients_lock);
|
||||
|
||||
__cache_size_refresh();
|
||||
|
||||
list_for_each_entry(c, &dm_bufio_all_clients, client_list)
|
||||
__evict_old_buffers(c, max_age_hz);
|
||||
|
||||
@@ -1930,7 +1941,7 @@ MODULE_PARM_DESC(max_cache_size_bytes, "Size of metadata cache");
|
||||
module_param_named(max_age_seconds, dm_bufio_max_age, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(max_age_seconds, "Max age of a buffer in seconds");
|
||||
|
||||
module_param_named(retain_bytes, dm_bufio_retain_bytes, uint, S_IRUGO | S_IWUSR);
|
||||
module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(retain_bytes, "Try to keep at least this many bytes cached in memory");
|
||||
|
||||
module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, S_IRUGO | S_IWUSR);
|
||||
|
||||
@@ -1383,17 +1383,19 @@ void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
|
||||
|
||||
int dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown)
|
||||
{
|
||||
int r;
|
||||
int r = -EINVAL;
|
||||
flags_mutator mutator = (clean_shutdown ? set_clean_shutdown :
|
||||
clear_clean_shutdown);
|
||||
|
||||
WRITE_LOCK(cmd);
|
||||
if (cmd->fail_io)
|
||||
goto out;
|
||||
|
||||
r = __commit_transaction(cmd, mutator);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = __begin_transaction(cmd);
|
||||
|
||||
out:
|
||||
WRITE_UNLOCK(cmd);
|
||||
return r;
|
||||
@@ -1405,7 +1407,8 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd,
|
||||
int r = -EINVAL;
|
||||
|
||||
READ_LOCK(cmd);
|
||||
r = dm_sm_get_nr_free(cmd->metadata_sm, result);
|
||||
if (!cmd->fail_io)
|
||||
r = dm_sm_get_nr_free(cmd->metadata_sm, result);
|
||||
READ_UNLOCK(cmd);
|
||||
|
||||
return r;
|
||||
@@ -1417,7 +1420,8 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
|
||||
int r = -EINVAL;
|
||||
|
||||
READ_LOCK(cmd);
|
||||
r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
|
||||
if (!cmd->fail_io)
|
||||
r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
|
||||
READ_UNLOCK(cmd);
|
||||
|
||||
return r;
|
||||
|
||||
+12
-5
@@ -119,7 +119,8 @@ static struct kmem_cache *_mpio_cache;
|
||||
|
||||
static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
|
||||
static void trigger_event(struct work_struct *work);
|
||||
static void activate_path(struct work_struct *work);
|
||||
static void activate_or_offline_path(struct pgpath *pgpath);
|
||||
static void activate_path_work(struct work_struct *work);
|
||||
static void process_queued_bios(struct work_struct *work);
|
||||
|
||||
/*-----------------------------------------------
|
||||
@@ -144,7 +145,7 @@ static struct pgpath *alloc_pgpath(void)
|
||||
|
||||
if (pgpath) {
|
||||
pgpath->is_active = true;
|
||||
INIT_DELAYED_WORK(&pgpath->activate_path, activate_path);
|
||||
INIT_DELAYED_WORK(&pgpath->activate_path, activate_path_work);
|
||||
}
|
||||
|
||||
return pgpath;
|
||||
@@ -1515,10 +1516,8 @@ out:
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
static void activate_path(struct work_struct *work)
|
||||
static void activate_or_offline_path(struct pgpath *pgpath)
|
||||
{
|
||||
struct pgpath *pgpath =
|
||||
container_of(work, struct pgpath, activate_path.work);
|
||||
struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
|
||||
|
||||
if (pgpath->is_active && !blk_queue_dying(q))
|
||||
@@ -1527,6 +1526,14 @@ static void activate_path(struct work_struct *work)
|
||||
pg_init_done(pgpath, SCSI_DH_DEV_OFFLINED);
|
||||
}
|
||||
|
||||
static void activate_path_work(struct work_struct *work)
|
||||
{
|
||||
struct pgpath *pgpath =
|
||||
container_of(work, struct pgpath, activate_path.work);
|
||||
|
||||
activate_or_offline_path(pgpath);
|
||||
}
|
||||
|
||||
static int noretry_error(int error)
|
||||
{
|
||||
switch (error) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user