mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
Merge "Merge 6.1.7 into android14-6.1" into android14-6.1
This commit is contained in:
@@ -32,7 +32,7 @@ properties:
|
||||
- description: Display byte clock
|
||||
- description: Display byte interface clock
|
||||
- description: Display pixel clock
|
||||
- description: Display escape clock
|
||||
- description: Display core clock
|
||||
- description: Display AHB clock
|
||||
- description: Display AXI clock
|
||||
|
||||
@@ -134,8 +134,6 @@ required:
|
||||
- phy-names
|
||||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
- power-domains
|
||||
- operating-points-v2
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@@ -69,7 +69,6 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- vdds-supply
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- vcca-supply
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ properties:
|
||||
vddio-supply:
|
||||
description: Phandle to vdd-io regulator device node.
|
||||
|
||||
qcom,dsi-phy-regulator-ldo-mode:
|
||||
type: boolean
|
||||
description: Indicates if the LDO mode PHY regulator is wanted.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks.
|
||||
|
||||
Contact: Harry Wentland, Alex Deucher
|
||||
|
||||
vmwgfx: Replace hashtable with Linux' implementation
|
||||
----------------------------------------------------
|
||||
|
||||
The vmwgfx driver uses its own hashtable implementation. Replace the
|
||||
code with Linux' implementation and update the callers. It's mostly a
|
||||
refactoring task, but the interfaces are different.
|
||||
|
||||
Contact: Zack Rusin, Thomas Zimmermann <tzimmermann@suse.de>
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Bootsplash
|
||||
==========
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from sphinx.util.pycompat import execfile_
|
||||
from sphinx.util.osutil import fs_encoding
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
def loadConfig(namespace):
|
||||
@@ -48,7 +48,9 @@ def loadConfig(namespace):
|
||||
sys.stdout.write("load additional sphinx-config: %s\n" % config_file)
|
||||
config = namespace.copy()
|
||||
config['__file__'] = config_file
|
||||
execfile_(config_file, config)
|
||||
with open(config_file, 'rb') as f:
|
||||
code = compile(f.read(), fs_encoding, 'exec')
|
||||
exec(code, config)
|
||||
del config['__file__']
|
||||
namespace.update(config)
|
||||
else:
|
||||
|
||||
@@ -8255,6 +8255,20 @@ CPU[EAX=1]:ECX[24] (TSC_DEADLINE) is not reported by ``KVM_GET_SUPPORTED_CPUID``
|
||||
It can be enabled if ``KVM_CAP_TSC_DEADLINE_TIMER`` is present and the kernel
|
||||
has enabled in-kernel emulation of the local APIC.
|
||||
|
||||
CPU topology
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Several CPUID values include topology information for the host CPU:
|
||||
0x0b and 0x1f for Intel systems, 0x8000001e for AMD systems. Different
|
||||
versions of KVM return different values for this information and userspace
|
||||
should not rely on it. Currently they return all zeroes.
|
||||
|
||||
If userspace wishes to set up a guest topology, it should be careful that
|
||||
the values of these three leaves differ for each CPU. In particular,
|
||||
the APIC ID is found in EDX for all subleaves of 0x0b and 0x1f, and in EAX
|
||||
for 0x8000001e; the latter also encodes the core id and node id in bits
|
||||
7:0 of EBX and ECX respectively.
|
||||
|
||||
Obsolete ioctls and capabilities
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 6
|
||||
SUBLEVEL = 7
|
||||
EXTRAVERSION =
|
||||
NAME = Hurr durr I'ma ninja sloth
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ __ll_sc__cmpxchg_double##name(unsigned long old1, \
|
||||
" cbnz %w0, 1b\n" \
|
||||
" " #mb "\n" \
|
||||
"2:" \
|
||||
: "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr) \
|
||||
: "=&r" (tmp), "=&r" (ret), "+Q" (*(__uint128_t *)ptr) \
|
||||
: "r" (old1), "r" (old2), "r" (new1), "r" (new2) \
|
||||
: cl); \
|
||||
\
|
||||
|
||||
@@ -311,7 +311,7 @@ __lse__cmpxchg_double##name(unsigned long old1, \
|
||||
" eor %[old2], %[old2], %[oldval2]\n" \
|
||||
" orr %[old1], %[old1], %[old2]" \
|
||||
: [old1] "+&r" (x0), [old2] "+&r" (x1), \
|
||||
[v] "+Q" (*(unsigned long *)ptr) \
|
||||
[v] "+Q" (*(__uint128_t *)ptr) \
|
||||
: [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \
|
||||
[oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \
|
||||
: cl); \
|
||||
|
||||
@@ -378,8 +378,26 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
|
||||
|
||||
static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vcpu_abt_iss1tw(vcpu))
|
||||
return true;
|
||||
if (kvm_vcpu_abt_iss1tw(vcpu)) {
|
||||
/*
|
||||
* Only a permission fault on a S1PTW should be
|
||||
* considered as a write. Otherwise, page tables baked
|
||||
* in a read-only memslot will result in an exception
|
||||
* being delivered in the guest.
|
||||
*
|
||||
* The drawback is that we end-up faulting twice if the
|
||||
* guest is using any of HW AF/DB: a translation fault
|
||||
* to map the page containing the PT (read only at
|
||||
* first), then a permission fault to allow the flags
|
||||
* to be set.
|
||||
*/
|
||||
switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
|
||||
case ESR_ELx_FSC_PERM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (kvm_vcpu_trap_is_iabt(vcpu))
|
||||
return false;
|
||||
|
||||
@@ -682,7 +682,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
||||
#define pud_leaf(pud) (pud_present(pud) && !pud_table(pud))
|
||||
#define pud_valid(pud) pte_valid(pud_pte(pud))
|
||||
#define pud_user(pud) pte_user(pud_pte(pud))
|
||||
|
||||
#define pud_user_exec(pud) pte_user_exec(pud_pte(pud))
|
||||
|
||||
static inline void set_pud(pud_t *pudp, pud_t pud)
|
||||
{
|
||||
@@ -863,12 +863,12 @@ static inline bool pte_user_accessible_page(pte_t pte)
|
||||
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd)
|
||||
{
|
||||
return pmd_leaf(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
|
||||
return pmd_leaf(pmd) && !pmd_present_invalid(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(pud_t pud)
|
||||
{
|
||||
return pud_leaf(pud) && pud_user(pud);
|
||||
return pud_leaf(pud) && (pud_user(pud) || pud_user_exec(pud));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -8,28 +8,27 @@
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/mte.h>
|
||||
|
||||
#define for_each_mte_vma(vmi, vma) \
|
||||
#define for_each_mte_vma(cprm, i, m) \
|
||||
if (system_supports_mte()) \
|
||||
for_each_vma(vmi, vma) \
|
||||
if (vma->vm_flags & VM_MTE)
|
||||
for (i = 0, m = cprm->vma_meta; \
|
||||
i < cprm->vma_count; \
|
||||
i++, m = cprm->vma_meta + i) \
|
||||
if (m->flags & VM_MTE)
|
||||
|
||||
static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
|
||||
static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
|
||||
{
|
||||
if (vma->vm_flags & VM_DONTDUMP)
|
||||
return 0;
|
||||
|
||||
return vma_pages(vma) * MTE_PAGE_TAG_STORAGE;
|
||||
return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
|
||||
}
|
||||
|
||||
/* Derived from dump_user_range(); start/end must be page-aligned */
|
||||
static int mte_dump_tag_range(struct coredump_params *cprm,
|
||||
unsigned long start, unsigned long end)
|
||||
unsigned long start, unsigned long len)
|
||||
{
|
||||
int ret = 1;
|
||||
unsigned long addr;
|
||||
void *tags = NULL;
|
||||
|
||||
for (addr = start; addr < end; addr += PAGE_SIZE) {
|
||||
for (addr = start; addr < start + len; addr += PAGE_SIZE) {
|
||||
struct page *page = get_dump_page(addr);
|
||||
|
||||
/*
|
||||
@@ -65,7 +64,6 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
|
||||
mte_save_page_tags(page_address(page), tags);
|
||||
put_page(page);
|
||||
if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
|
||||
mte_free_tag_storage(tags);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@@ -77,13 +75,13 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
|
||||
return ret;
|
||||
}
|
||||
|
||||
Elf_Half elf_core_extra_phdrs(void)
|
||||
Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
int i;
|
||||
struct core_vma_metadata *m;
|
||||
int vma_count = 0;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma)
|
||||
for_each_mte_vma(cprm, i, m)
|
||||
vma_count++;
|
||||
|
||||
return vma_count;
|
||||
@@ -91,18 +89,18 @@ Elf_Half elf_core_extra_phdrs(void)
|
||||
|
||||
int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
int i;
|
||||
struct core_vma_metadata *m;
|
||||
|
||||
for_each_mte_vma(vmi, vma) {
|
||||
for_each_mte_vma(cprm, i, m) {
|
||||
struct elf_phdr phdr;
|
||||
|
||||
phdr.p_type = PT_AARCH64_MEMTAG_MTE;
|
||||
phdr.p_offset = offset;
|
||||
phdr.p_vaddr = vma->vm_start;
|
||||
phdr.p_vaddr = m->start;
|
||||
phdr.p_paddr = 0;
|
||||
phdr.p_filesz = mte_vma_tag_dump_size(vma);
|
||||
phdr.p_memsz = vma->vm_end - vma->vm_start;
|
||||
phdr.p_filesz = mte_vma_tag_dump_size(m);
|
||||
phdr.p_memsz = m->end - m->start;
|
||||
offset += phdr.p_filesz;
|
||||
phdr.p_flags = 0;
|
||||
phdr.p_align = 0;
|
||||
@@ -114,28 +112,25 @@ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t elf_core_extra_data_size(void)
|
||||
size_t elf_core_extra_data_size(struct coredump_params *cprm)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
int i;
|
||||
struct core_vma_metadata *m;
|
||||
size_t data_size = 0;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
|
||||
for_each_mte_vma(vmi, vma)
|
||||
data_size += mte_vma_tag_dump_size(vma);
|
||||
for_each_mte_vma(cprm, i, m)
|
||||
data_size += mte_vma_tag_dump_size(m);
|
||||
|
||||
return data_size;
|
||||
}
|
||||
|
||||
int elf_core_write_extra_data(struct coredump_params *cprm)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, current->mm, 0);
|
||||
int i;
|
||||
struct core_vma_metadata *m;
|
||||
|
||||
for_each_mte_vma(vmi, vma) {
|
||||
if (vma->vm_flags & VM_DONTDUMP)
|
||||
continue;
|
||||
|
||||
if (!mte_dump_tag_range(cprm, vma->vm_start, vma->vm_end))
|
||||
for_each_mte_vma(cprm, i, m) {
|
||||
if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1364,7 +1364,7 @@ enum aarch64_regset {
|
||||
#ifdef CONFIG_ARM64_SVE
|
||||
REGSET_SVE,
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_SVE
|
||||
#ifdef CONFIG_ARM64_SME
|
||||
REGSET_SSVE,
|
||||
REGSET_ZA,
|
||||
#endif
|
||||
|
||||
@@ -280,7 +280,12 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
||||
|
||||
vl = task_get_sme_vl(current);
|
||||
} else {
|
||||
if (!system_supports_sve())
|
||||
/*
|
||||
* A SME only system use SVE for streaming mode so can
|
||||
* have a SVE formatted context with a zero VL and no
|
||||
* payload data.
|
||||
*/
|
||||
if (!system_supports_sve() && !system_supports_sme())
|
||||
return -EINVAL;
|
||||
|
||||
vl = task_get_sve_vl(current);
|
||||
@@ -729,7 +734,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (system_supports_sve()) {
|
||||
if (system_supports_sve() || system_supports_sme()) {
|
||||
unsigned int vq = 0;
|
||||
|
||||
if (add_all || test_thread_flag(TIF_SVE) ||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <asm/elf.h>
|
||||
|
||||
|
||||
Elf64_Half elf_core_extra_phdrs(void)
|
||||
Elf64_Half elf_core_extra_phdrs(struct coredump_params *cprm)
|
||||
{
|
||||
return GATE_EHDR->e_phnum;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t elf_core_extra_data_size(void)
|
||||
size_t elf_core_extra_data_size(struct coredump_params *cprm)
|
||||
{
|
||||
const struct elf_phdr *const gate_phdrs =
|
||||
(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
|
||||
|
||||
@@ -137,7 +137,7 @@ struct imc_pmu {
|
||||
* are inited.
|
||||
*/
|
||||
struct imc_pmu_ref {
|
||||
struct mutex lock;
|
||||
spinlock_t lock;
|
||||
unsigned int id;
|
||||
int refc;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <asm/cputhreads.h>
|
||||
#include <asm/smp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* Nest IMC data structures and variables */
|
||||
|
||||
@@ -21,7 +22,7 @@
|
||||
* Used to avoid races in counting the nest-pmu units during hotplug
|
||||
* register and unregister
|
||||
*/
|
||||
static DEFINE_MUTEX(nest_init_lock);
|
||||
static DEFINE_SPINLOCK(nest_init_lock);
|
||||
static DEFINE_PER_CPU(struct imc_pmu_ref *, local_nest_imc_refc);
|
||||
static struct imc_pmu **per_nest_pmu_arr;
|
||||
static cpumask_t nest_imc_cpumask;
|
||||
@@ -50,7 +51,7 @@ static int trace_imc_mem_size;
|
||||
* core and trace-imc
|
||||
*/
|
||||
static struct imc_pmu_ref imc_global_refc = {
|
||||
.lock = __MUTEX_INITIALIZER(imc_global_refc.lock),
|
||||
.lock = __SPIN_LOCK_INITIALIZER(imc_global_refc.lock),
|
||||
.id = 0,
|
||||
.refc = 0,
|
||||
};
|
||||
@@ -400,7 +401,7 @@ static int ppc_nest_imc_cpu_offline(unsigned int cpu)
|
||||
get_hard_smp_processor_id(cpu));
|
||||
/*
|
||||
* If this is the last cpu in this chip then, skip the reference
|
||||
* count mutex lock and make the reference count on this chip zero.
|
||||
* count lock and make the reference count on this chip zero.
|
||||
*/
|
||||
ref = get_nest_pmu_ref(cpu);
|
||||
if (!ref)
|
||||
@@ -462,15 +463,15 @@ static void nest_imc_counters_release(struct perf_event *event)
|
||||
/*
|
||||
* See if we need to disable the nest PMU.
|
||||
* If no events are currently in use, then we have to take a
|
||||
* mutex to ensure that we don't race with another task doing
|
||||
* lock to ensure that we don't race with another task doing
|
||||
* enable or disable the nest counters.
|
||||
*/
|
||||
ref = get_nest_pmu_ref(event->cpu);
|
||||
if (!ref)
|
||||
return;
|
||||
|
||||
/* Take the mutex lock for this node and then decrement the reference count */
|
||||
mutex_lock(&ref->lock);
|
||||
/* Take the lock for this node and then decrement the reference count */
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
/*
|
||||
* The scenario where this is true is, when perf session is
|
||||
@@ -482,7 +483,7 @@ static void nest_imc_counters_release(struct perf_event *event)
|
||||
* an OPAL call to disable the engine in that node.
|
||||
*
|
||||
*/
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
return;
|
||||
}
|
||||
ref->refc--;
|
||||
@@ -490,7 +491,7 @@ static void nest_imc_counters_release(struct perf_event *event)
|
||||
rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,
|
||||
get_hard_smp_processor_id(event->cpu));
|
||||
if (rc) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("nest-imc: Unable to stop the counters for core %d\n", node_id);
|
||||
return;
|
||||
}
|
||||
@@ -498,7 +499,7 @@ static void nest_imc_counters_release(struct perf_event *event)
|
||||
WARN(1, "nest-imc: Invalid event reference count\n");
|
||||
ref->refc = 0;
|
||||
}
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
}
|
||||
|
||||
static int nest_imc_event_init(struct perf_event *event)
|
||||
@@ -557,26 +558,25 @@ static int nest_imc_event_init(struct perf_event *event)
|
||||
|
||||
/*
|
||||
* Get the imc_pmu_ref struct for this node.
|
||||
* Take the mutex lock and then increment the count of nest pmu events
|
||||
* inited.
|
||||
* Take the lock and then increment the count of nest pmu events inited.
|
||||
*/
|
||||
ref = get_nest_pmu_ref(event->cpu);
|
||||
if (!ref)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_NEST,
|
||||
get_hard_smp_processor_id(event->cpu));
|
||||
if (rc) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("nest-imc: Unable to start the counters for node %d\n",
|
||||
node_id);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
++ref->refc;
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
|
||||
event->destroy = nest_imc_counters_release;
|
||||
return 0;
|
||||
@@ -612,9 +612,8 @@ static int core_imc_mem_init(int cpu, int size)
|
||||
return -ENOMEM;
|
||||
mem_info->vbase = page_address(page);
|
||||
|
||||
/* Init the mutex */
|
||||
core_imc_refc[core_id].id = core_id;
|
||||
mutex_init(&core_imc_refc[core_id].lock);
|
||||
spin_lock_init(&core_imc_refc[core_id].lock);
|
||||
|
||||
rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,
|
||||
__pa((void *)mem_info->vbase),
|
||||
@@ -703,9 +702,8 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
|
||||
perf_pmu_migrate_context(&core_imc_pmu->pmu, cpu, ncpu);
|
||||
} else {
|
||||
/*
|
||||
* If this is the last cpu in this core then, skip taking refernce
|
||||
* count mutex lock for this core and directly zero "refc" for
|
||||
* this core.
|
||||
* If this is the last cpu in this core then skip taking reference
|
||||
* count lock for this core and directly zero "refc" for this core.
|
||||
*/
|
||||
opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
|
||||
get_hard_smp_processor_id(cpu));
|
||||
@@ -720,11 +718,11 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
|
||||
* last cpu in this core and core-imc event running
|
||||
* in this cpu.
|
||||
*/
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
if (imc_global_refc.id == IMC_DOMAIN_CORE)
|
||||
imc_global_refc.refc--;
|
||||
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -739,7 +737,7 @@ static int core_imc_pmu_cpumask_init(void)
|
||||
|
||||
static void reset_global_refc(struct perf_event *event)
|
||||
{
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
imc_global_refc.refc--;
|
||||
|
||||
/*
|
||||
@@ -751,7 +749,7 @@ static void reset_global_refc(struct perf_event *event)
|
||||
imc_global_refc.refc = 0;
|
||||
imc_global_refc.id = 0;
|
||||
}
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
}
|
||||
|
||||
static void core_imc_counters_release(struct perf_event *event)
|
||||
@@ -764,17 +762,17 @@ static void core_imc_counters_release(struct perf_event *event)
|
||||
/*
|
||||
* See if we need to disable the IMC PMU.
|
||||
* If no events are currently in use, then we have to take a
|
||||
* mutex to ensure that we don't race with another task doing
|
||||
* lock to ensure that we don't race with another task doing
|
||||
* enable or disable the core counters.
|
||||
*/
|
||||
core_id = event->cpu / threads_per_core;
|
||||
|
||||
/* Take the mutex lock and decrement the refernce count for this core */
|
||||
/* Take the lock and decrement the refernce count for this core */
|
||||
ref = &core_imc_refc[core_id];
|
||||
if (!ref)
|
||||
return;
|
||||
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
/*
|
||||
* The scenario where this is true is, when perf session is
|
||||
@@ -786,7 +784,7 @@ static void core_imc_counters_release(struct perf_event *event)
|
||||
* an OPAL call to disable the engine in that core.
|
||||
*
|
||||
*/
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
return;
|
||||
}
|
||||
ref->refc--;
|
||||
@@ -794,7 +792,7 @@ static void core_imc_counters_release(struct perf_event *event)
|
||||
rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
|
||||
get_hard_smp_processor_id(event->cpu));
|
||||
if (rc) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("IMC: Unable to stop the counters for core %d\n", core_id);
|
||||
return;
|
||||
}
|
||||
@@ -802,7 +800,7 @@ static void core_imc_counters_release(struct perf_event *event)
|
||||
WARN(1, "core-imc: Invalid event reference count\n");
|
||||
ref->refc = 0;
|
||||
}
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
|
||||
reset_global_refc(event);
|
||||
}
|
||||
@@ -840,7 +838,6 @@ static int core_imc_event_init(struct perf_event *event)
|
||||
if ((!pcmi->vbase))
|
||||
return -ENODEV;
|
||||
|
||||
/* Get the core_imc mutex for this core */
|
||||
ref = &core_imc_refc[core_id];
|
||||
if (!ref)
|
||||
return -EINVAL;
|
||||
@@ -848,22 +845,22 @@ static int core_imc_event_init(struct perf_event *event)
|
||||
/*
|
||||
* Core pmu units are enabled only when it is used.
|
||||
* See if this is triggered for the first time.
|
||||
* If yes, take the mutex lock and enable the core counters.
|
||||
* If yes, take the lock and enable the core counters.
|
||||
* If not, just increment the count in core_imc_refc struct.
|
||||
*/
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
|
||||
get_hard_smp_processor_id(event->cpu));
|
||||
if (rc) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("core-imc: Unable to start the counters for core %d\n",
|
||||
core_id);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
++ref->refc;
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
|
||||
/*
|
||||
* Since the system can run either in accumulation or trace-mode
|
||||
@@ -874,7 +871,7 @@ static int core_imc_event_init(struct perf_event *event)
|
||||
* to know whether any other trace/thread imc
|
||||
* events are running.
|
||||
*/
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_CORE) {
|
||||
/*
|
||||
* No other trace/thread imc events are running in
|
||||
@@ -883,10 +880,10 @@ static int core_imc_event_init(struct perf_event *event)
|
||||
imc_global_refc.id = IMC_DOMAIN_CORE;
|
||||
imc_global_refc.refc++;
|
||||
} else {
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
|
||||
event->hw.event_base = (u64)pcmi->vbase + (config & IMC_EVENT_OFFSET_MASK);
|
||||
event->destroy = core_imc_counters_release;
|
||||
@@ -958,10 +955,10 @@ static int ppc_thread_imc_cpu_offline(unsigned int cpu)
|
||||
mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
|
||||
|
||||
/* Reduce the refc if thread-imc event running on this cpu */
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
if (imc_global_refc.id == IMC_DOMAIN_THREAD)
|
||||
imc_global_refc.refc--;
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1001,7 +998,7 @@ static int thread_imc_event_init(struct perf_event *event)
|
||||
if (!target)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
/*
|
||||
* Check if any other trace/core imc events are running in the
|
||||
* system, if not set the global id to thread-imc.
|
||||
@@ -1010,10 +1007,10 @@ static int thread_imc_event_init(struct perf_event *event)
|
||||
imc_global_refc.id = IMC_DOMAIN_THREAD;
|
||||
imc_global_refc.refc++;
|
||||
} else {
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
|
||||
event->pmu->task_ctx_nr = perf_sw_context;
|
||||
event->destroy = reset_global_refc;
|
||||
@@ -1135,25 +1132,25 @@ static int thread_imc_event_add(struct perf_event *event, int flags)
|
||||
/*
|
||||
* imc pmus are enabled only when it is used.
|
||||
* See if this is triggered for the first time.
|
||||
* If yes, take the mutex lock and enable the counters.
|
||||
* If yes, take the lock and enable the counters.
|
||||
* If not, just increment the count in ref count struct.
|
||||
*/
|
||||
ref = &core_imc_refc[core_id];
|
||||
if (!ref)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
if (opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
|
||||
get_hard_smp_processor_id(smp_processor_id()))) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("thread-imc: Unable to start the counter\
|
||||
for core %d\n", core_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
++ref->refc;
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1170,12 +1167,12 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
ref->refc--;
|
||||
if (ref->refc == 0) {
|
||||
if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
|
||||
get_hard_smp_processor_id(smp_processor_id()))) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("thread-imc: Unable to stop the counters\
|
||||
for core %d\n", core_id);
|
||||
return;
|
||||
@@ -1183,7 +1180,7 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
|
||||
} else if (ref->refc < 0) {
|
||||
ref->refc = 0;
|
||||
}
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
|
||||
/* Set bit 0 of LDBAR to zero, to stop posting updates to memory */
|
||||
mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
|
||||
@@ -1224,9 +1221,8 @@ static int trace_imc_mem_alloc(int cpu_id, int size)
|
||||
}
|
||||
}
|
||||
|
||||
/* Init the mutex, if not already */
|
||||
trace_imc_refc[core_id].id = core_id;
|
||||
mutex_init(&trace_imc_refc[core_id].lock);
|
||||
spin_lock_init(&trace_imc_refc[core_id].lock);
|
||||
|
||||
mtspr(SPRN_LDBAR, 0);
|
||||
return 0;
|
||||
@@ -1246,10 +1242,10 @@ static int ppc_trace_imc_cpu_offline(unsigned int cpu)
|
||||
* Reduce the refc if any trace-imc event running
|
||||
* on this cpu.
|
||||
*/
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
if (imc_global_refc.id == IMC_DOMAIN_TRACE)
|
||||
imc_global_refc.refc--;
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1371,17 +1367,17 @@ static int trace_imc_event_add(struct perf_event *event, int flags)
|
||||
}
|
||||
|
||||
mtspr(SPRN_LDBAR, ldbar_value);
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
if (ref->refc == 0) {
|
||||
if (opal_imc_counters_start(OPAL_IMC_COUNTERS_TRACE,
|
||||
get_hard_smp_processor_id(smp_processor_id()))) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("trace-imc: Unable to start the counters for core %d\n", core_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
++ref->refc;
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1414,19 +1410,19 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ref->lock);
|
||||
spin_lock(&ref->lock);
|
||||
ref->refc--;
|
||||
if (ref->refc == 0) {
|
||||
if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_TRACE,
|
||||
get_hard_smp_processor_id(smp_processor_id()))) {
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
pr_err("trace-imc: Unable to stop the counters for core %d\n", core_id);
|
||||
return;
|
||||
}
|
||||
} else if (ref->refc < 0) {
|
||||
ref->refc = 0;
|
||||
}
|
||||
mutex_unlock(&ref->lock);
|
||||
spin_unlock(&ref->lock);
|
||||
|
||||
trace_imc_event_stop(event, flags);
|
||||
}
|
||||
@@ -1448,7 +1444,7 @@ static int trace_imc_event_init(struct perf_event *event)
|
||||
* no other thread is running any core/thread imc
|
||||
* events
|
||||
*/
|
||||
mutex_lock(&imc_global_refc.lock);
|
||||
spin_lock(&imc_global_refc.lock);
|
||||
if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_TRACE) {
|
||||
/*
|
||||
* No core/thread imc events are running in the
|
||||
@@ -1457,10 +1453,10 @@ static int trace_imc_event_init(struct perf_event *event)
|
||||
imc_global_refc.id = IMC_DOMAIN_TRACE;
|
||||
imc_global_refc.refc++;
|
||||
} else {
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_unlock(&imc_global_refc.lock);
|
||||
spin_unlock(&imc_global_refc.lock);
|
||||
|
||||
event->hw.idx = -1;
|
||||
|
||||
@@ -1533,10 +1529,10 @@ static int init_nest_pmu_ref(void)
|
||||
i = 0;
|
||||
for_each_node(nid) {
|
||||
/*
|
||||
* Mutex lock to avoid races while tracking the number of
|
||||
* Take the lock to avoid races while tracking the number of
|
||||
* sessions using the chip's nest pmu units.
|
||||
*/
|
||||
mutex_init(&nest_imc_refc[i].lock);
|
||||
spin_lock_init(&nest_imc_refc[i].lock);
|
||||
|
||||
/*
|
||||
* Loop to init the "id" with the node_id. Variable "i" initialized to
|
||||
@@ -1633,7 +1629,7 @@ static void imc_common_mem_free(struct imc_pmu *pmu_ptr)
|
||||
static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
|
||||
{
|
||||
if (pmu_ptr->domain == IMC_DOMAIN_NEST) {
|
||||
mutex_lock(&nest_init_lock);
|
||||
spin_lock(&nest_init_lock);
|
||||
if (nest_pmus == 1) {
|
||||
cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);
|
||||
kfree(nest_imc_refc);
|
||||
@@ -1643,7 +1639,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
|
||||
|
||||
if (nest_pmus > 0)
|
||||
nest_pmus--;
|
||||
mutex_unlock(&nest_init_lock);
|
||||
spin_unlock(&nest_init_lock);
|
||||
}
|
||||
|
||||
/* Free core_imc memory */
|
||||
@@ -1800,11 +1796,11 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
|
||||
* rest. To handle the cpuhotplug callback unregister, we track
|
||||
* the number of nest pmus in "nest_pmus".
|
||||
*/
|
||||
mutex_lock(&nest_init_lock);
|
||||
spin_lock(&nest_init_lock);
|
||||
if (nest_pmus == 0) {
|
||||
ret = init_nest_pmu_ref();
|
||||
if (ret) {
|
||||
mutex_unlock(&nest_init_lock);
|
||||
spin_unlock(&nest_init_lock);
|
||||
kfree(per_nest_pmu_arr);
|
||||
per_nest_pmu_arr = NULL;
|
||||
goto err_free_mem;
|
||||
@@ -1812,7 +1808,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
|
||||
/* Register for cpu hotplug notification. */
|
||||
ret = nest_pmu_cpumask_init();
|
||||
if (ret) {
|
||||
mutex_unlock(&nest_init_lock);
|
||||
spin_unlock(&nest_init_lock);
|
||||
kfree(nest_imc_refc);
|
||||
kfree(per_nest_pmu_arr);
|
||||
per_nest_pmu_arr = NULL;
|
||||
@@ -1820,7 +1816,7 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
|
||||
}
|
||||
}
|
||||
nest_pmus++;
|
||||
mutex_unlock(&nest_init_lock);
|
||||
spin_unlock(&nest_init_lock);
|
||||
break;
|
||||
case IMC_DOMAIN_CORE:
|
||||
ret = core_imc_pmu_cpumask_init();
|
||||
|
||||
@@ -131,19 +131,21 @@ struct hws_combined_entry {
|
||||
struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
|
||||
} __packed;
|
||||
|
||||
struct hws_trailer_entry {
|
||||
union {
|
||||
struct {
|
||||
unsigned int f:1; /* 0 - Block Full Indicator */
|
||||
unsigned int a:1; /* 1 - Alert request control */
|
||||
unsigned int t:1; /* 2 - Timestamp format */
|
||||
unsigned int :29; /* 3 - 31: Reserved */
|
||||
unsigned int bsdes:16; /* 32-47: size of basic SDE */
|
||||
unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
|
||||
};
|
||||
unsigned long long flags; /* 0 - 63: All indicators */
|
||||
union hws_trailer_header {
|
||||
struct {
|
||||
unsigned int f:1; /* 0 - Block Full Indicator */
|
||||
unsigned int a:1; /* 1 - Alert request control */
|
||||
unsigned int t:1; /* 2 - Timestamp format */
|
||||
unsigned int :29; /* 3 - 31: Reserved */
|
||||
unsigned int bsdes:16; /* 32-47: size of basic SDE */
|
||||
unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
|
||||
unsigned long long overflow; /* 64 - Overflow Count */
|
||||
};
|
||||
unsigned long long overflow; /* 64 - sample Overflow count */
|
||||
__uint128_t val;
|
||||
};
|
||||
|
||||
struct hws_trailer_entry {
|
||||
union hws_trailer_header header; /* 0 - 15 Flags + Overflow Count */
|
||||
unsigned char timestamp[16]; /* 16 - 31 timestamp */
|
||||
unsigned long long reserved1; /* 32 -Reserved */
|
||||
unsigned long long reserved2; /* */
|
||||
@@ -290,14 +292,11 @@ static inline unsigned long sample_rate_to_freq(struct hws_qsi_info_block *qsi,
|
||||
return USEC_PER_SEC * qsi->cpu_speed / rate;
|
||||
}
|
||||
|
||||
#define SDB_TE_ALERT_REQ_MASK 0x4000000000000000UL
|
||||
#define SDB_TE_BUFFER_FULL_MASK 0x8000000000000000UL
|
||||
|
||||
/* Return TOD timestamp contained in an trailer entry */
|
||||
static inline unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
|
||||
{
|
||||
/* TOD in STCKE format */
|
||||
if (te->t)
|
||||
if (te->header.t)
|
||||
return *((unsigned long long *) &te->timestamp[1]);
|
||||
|
||||
/* TOD in STCK format */
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
pcp_op_T__ *ptr__; \
|
||||
preempt_disable_notrace(); \
|
||||
ptr__ = raw_cpu_ptr(&(pcp)); \
|
||||
prev__ = *ptr__; \
|
||||
prev__ = READ_ONCE(*ptr__); \
|
||||
do { \
|
||||
old__ = prev__; \
|
||||
new__ = old__ op (val); \
|
||||
|
||||
@@ -187,8 +187,6 @@ static int kexec_file_add_ipl_report(struct kimage *image,
|
||||
|
||||
data->memsz = ALIGN(data->memsz, PAGE_SIZE);
|
||||
buf.mem = data->memsz;
|
||||
if (image->type == KEXEC_TYPE_CRASH)
|
||||
buf.mem += crashk_res.start;
|
||||
|
||||
ptr = (void *)ipl_cert_list_addr;
|
||||
end = ptr + ipl_cert_list_size;
|
||||
@@ -225,6 +223,9 @@ static int kexec_file_add_ipl_report(struct kimage *image,
|
||||
data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
|
||||
*lc_ipl_parmblock_ptr = (__u32)buf.mem;
|
||||
|
||||
if (image->type == KEXEC_TYPE_CRASH)
|
||||
buf.mem += crashk_res.start;
|
||||
|
||||
ret = kexec_add_buffer(&buf);
|
||||
out:
|
||||
return ret;
|
||||
|
||||
@@ -163,14 +163,15 @@ static void free_sampling_buffer(struct sf_buffer *sfb)
|
||||
|
||||
static int alloc_sample_data_block(unsigned long *sdbt, gfp_t gfp_flags)
|
||||
{
|
||||
unsigned long sdb, *trailer;
|
||||
struct hws_trailer_entry *te;
|
||||
unsigned long sdb;
|
||||
|
||||
/* Allocate and initialize sample-data-block */
|
||||
sdb = get_zeroed_page(gfp_flags);
|
||||
if (!sdb)
|
||||
return -ENOMEM;
|
||||
trailer = trailer_entry_ptr(sdb);
|
||||
*trailer = SDB_TE_ALERT_REQ_MASK;
|
||||
te = (struct hws_trailer_entry *)trailer_entry_ptr(sdb);
|
||||
te->header.a = 1;
|
||||
|
||||
/* Link SDB into the sample-data-block-table */
|
||||
*sdbt = sdb;
|
||||
@@ -1206,7 +1207,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
|
||||
"%s: Found unknown"
|
||||
" sampling data entry: te->f %i"
|
||||
" basic.def %#4x (%p)\n", __func__,
|
||||
te->f, sample->def, sample);
|
||||
te->header.f, sample->def, sample);
|
||||
/* Sample slot is not yet written or other record.
|
||||
*
|
||||
* This condition can occur if the buffer was reused
|
||||
@@ -1217,7 +1218,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
|
||||
* that are not full. Stop processing if the first
|
||||
* invalid format was detected.
|
||||
*/
|
||||
if (!te->f)
|
||||
if (!te->header.f)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1227,6 +1228,16 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
|
||||
}
|
||||
}
|
||||
|
||||
static inline __uint128_t __cdsg(__uint128_t *ptr, __uint128_t old, __uint128_t new)
|
||||
{
|
||||
asm volatile(
|
||||
" cdsg %[old],%[new],%[ptr]\n"
|
||||
: [old] "+d" (old), [ptr] "+QS" (*ptr)
|
||||
: [new] "d" (new)
|
||||
: "memory", "cc");
|
||||
return old;
|
||||
}
|
||||
|
||||
/* hw_perf_event_update() - Process sampling buffer
|
||||
* @event: The perf event
|
||||
* @flush_all: Flag to also flush partially filled sample-data-blocks
|
||||
@@ -1243,10 +1254,11 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
|
||||
*/
|
||||
static void hw_perf_event_update(struct perf_event *event, int flush_all)
|
||||
{
|
||||
unsigned long long event_overflow, sampl_overflow, num_sdb;
|
||||
union hws_trailer_header old, prev, new;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
struct hws_trailer_entry *te;
|
||||
unsigned long *sdbt;
|
||||
unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags;
|
||||
int done;
|
||||
|
||||
/*
|
||||
@@ -1266,25 +1278,25 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
|
||||
te = (struct hws_trailer_entry *) trailer_entry_ptr(*sdbt);
|
||||
|
||||
/* Leave loop if no more work to do (block full indicator) */
|
||||
if (!te->f) {
|
||||
if (!te->header.f) {
|
||||
done = 1;
|
||||
if (!flush_all)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the sample overflow count */
|
||||
if (te->overflow)
|
||||
if (te->header.overflow)
|
||||
/* Account sample overflows and, if a particular limit
|
||||
* is reached, extend the sampling buffer.
|
||||
* For details, see sfb_account_overflows().
|
||||
*/
|
||||
sampl_overflow += te->overflow;
|
||||
sampl_overflow += te->header.overflow;
|
||||
|
||||
/* Timestamps are valid for full sample-data-blocks only */
|
||||
debug_sprintf_event(sfdbg, 6, "%s: sdbt %#lx "
|
||||
"overflow %llu timestamp %#llx\n",
|
||||
__func__, (unsigned long)sdbt, te->overflow,
|
||||
(te->f) ? trailer_timestamp(te) : 0ULL);
|
||||
__func__, (unsigned long)sdbt, te->header.overflow,
|
||||
(te->header.f) ? trailer_timestamp(te) : 0ULL);
|
||||
|
||||
/* Collect all samples from a single sample-data-block and
|
||||
* flag if an (perf) event overflow happened. If so, the PMU
|
||||
@@ -1294,12 +1306,16 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
|
||||
num_sdb++;
|
||||
|
||||
/* Reset trailer (using compare-double-and-swap) */
|
||||
/* READ_ONCE() 16 byte header */
|
||||
prev.val = __cdsg(&te->header.val, 0, 0);
|
||||
do {
|
||||
te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
|
||||
te_flags |= SDB_TE_ALERT_REQ_MASK;
|
||||
} while (!cmpxchg_double(&te->flags, &te->overflow,
|
||||
te->flags, te->overflow,
|
||||
te_flags, 0ULL));
|
||||
old.val = prev.val;
|
||||
new.val = prev.val;
|
||||
new.f = 0;
|
||||
new.a = 1;
|
||||
new.overflow = 0;
|
||||
prev.val = __cdsg(&te->header.val, old.val, new.val);
|
||||
} while (prev.val != old.val);
|
||||
|
||||
/* Advance to next sample-data-block */
|
||||
sdbt++;
|
||||
@@ -1384,7 +1400,7 @@ static void aux_output_end(struct perf_output_handle *handle)
|
||||
range_scan = AUX_SDB_NUM_ALERT(aux);
|
||||
for (i = 0, idx = aux->head; i < range_scan; i++, idx++) {
|
||||
te = aux_sdb_trailer(aux, idx);
|
||||
if (!(te->flags & SDB_TE_BUFFER_FULL_MASK))
|
||||
if (!te->header.f)
|
||||
break;
|
||||
}
|
||||
/* i is num of SDBs which are full */
|
||||
@@ -1392,7 +1408,7 @@ static void aux_output_end(struct perf_output_handle *handle)
|
||||
|
||||
/* Remove alert indicators in the buffer */
|
||||
te = aux_sdb_trailer(aux, aux->alert_mark);
|
||||
te->flags &= ~SDB_TE_ALERT_REQ_MASK;
|
||||
te->header.a = 0;
|
||||
|
||||
debug_sprintf_event(sfdbg, 6, "%s: SDBs %ld range %ld head %ld\n",
|
||||
__func__, i, range_scan, aux->head);
|
||||
@@ -1437,9 +1453,9 @@ static int aux_output_begin(struct perf_output_handle *handle,
|
||||
idx = aux->empty_mark + 1;
|
||||
for (i = 0; i < range_scan; i++, idx++) {
|
||||
te = aux_sdb_trailer(aux, idx);
|
||||
te->flags &= ~(SDB_TE_BUFFER_FULL_MASK |
|
||||
SDB_TE_ALERT_REQ_MASK);
|
||||
te->overflow = 0;
|
||||
te->header.f = 0;
|
||||
te->header.a = 0;
|
||||
te->header.overflow = 0;
|
||||
}
|
||||
/* Save the position of empty SDBs */
|
||||
aux->empty_mark = aux->head + range - 1;
|
||||
@@ -1448,7 +1464,7 @@ static int aux_output_begin(struct perf_output_handle *handle,
|
||||
/* Set alert indicator */
|
||||
aux->alert_mark = aux->head + range/2 - 1;
|
||||
te = aux_sdb_trailer(aux, aux->alert_mark);
|
||||
te->flags = te->flags | SDB_TE_ALERT_REQ_MASK;
|
||||
te->header.a = 1;
|
||||
|
||||
/* Reset hardware buffer head */
|
||||
head = AUX_SDB_INDEX(aux, aux->head);
|
||||
@@ -1475,14 +1491,17 @@ static int aux_output_begin(struct perf_output_handle *handle,
|
||||
static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
|
||||
unsigned long long *overflow)
|
||||
{
|
||||
unsigned long long orig_overflow, orig_flags, new_flags;
|
||||
union hws_trailer_header old, prev, new;
|
||||
struct hws_trailer_entry *te;
|
||||
|
||||
te = aux_sdb_trailer(aux, alert_index);
|
||||
/* READ_ONCE() 16 byte header */
|
||||
prev.val = __cdsg(&te->header.val, 0, 0);
|
||||
do {
|
||||
orig_flags = te->flags;
|
||||
*overflow = orig_overflow = te->overflow;
|
||||
if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
|
||||
old.val = prev.val;
|
||||
new.val = prev.val;
|
||||
*overflow = old.overflow;
|
||||
if (old.f) {
|
||||
/*
|
||||
* SDB is already set by hardware.
|
||||
* Abort and try to set somewhere
|
||||
@@ -1490,10 +1509,10 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
new_flags = orig_flags | SDB_TE_ALERT_REQ_MASK;
|
||||
} while (!cmpxchg_double(&te->flags, &te->overflow,
|
||||
orig_flags, orig_overflow,
|
||||
new_flags, 0ULL));
|
||||
new.a = 1;
|
||||
new.overflow = 0;
|
||||
prev.val = __cdsg(&te->header.val, old.val, new.val);
|
||||
} while (prev.val != old.val);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1522,8 +1541,9 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
|
||||
static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
|
||||
unsigned long long *overflow)
|
||||
{
|
||||
unsigned long long orig_overflow, orig_flags, new_flags;
|
||||
unsigned long i, range_scan, idx, idx_old;
|
||||
union hws_trailer_header old, prev, new;
|
||||
unsigned long long orig_overflow;
|
||||
struct hws_trailer_entry *te;
|
||||
|
||||
debug_sprintf_event(sfdbg, 6, "%s: range %ld head %ld alert %ld "
|
||||
@@ -1554,17 +1574,20 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
|
||||
idx_old = idx = aux->empty_mark + 1;
|
||||
for (i = 0; i < range_scan; i++, idx++) {
|
||||
te = aux_sdb_trailer(aux, idx);
|
||||
/* READ_ONCE() 16 byte header */
|
||||
prev.val = __cdsg(&te->header.val, 0, 0);
|
||||
do {
|
||||
orig_flags = te->flags;
|
||||
orig_overflow = te->overflow;
|
||||
new_flags = orig_flags & ~SDB_TE_BUFFER_FULL_MASK;
|
||||
old.val = prev.val;
|
||||
new.val = prev.val;
|
||||
orig_overflow = old.overflow;
|
||||
new.f = 0;
|
||||
new.overflow = 0;
|
||||
if (idx == aux->alert_mark)
|
||||
new_flags |= SDB_TE_ALERT_REQ_MASK;
|
||||
new.a = 1;
|
||||
else
|
||||
new_flags &= ~SDB_TE_ALERT_REQ_MASK;
|
||||
} while (!cmpxchg_double(&te->flags, &te->overflow,
|
||||
orig_flags, orig_overflow,
|
||||
new_flags, 0ULL));
|
||||
new.a = 0;
|
||||
prev.val = __cdsg(&te->header.val, old.val, new.val);
|
||||
} while (prev.val != old.val);
|
||||
*overflow += orig_overflow;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ intcall:
|
||||
movw %dx, %si
|
||||
movw %sp, %di
|
||||
movw $11, %cx
|
||||
rep; movsd
|
||||
rep; movsl
|
||||
|
||||
/* Pop full state from the stack */
|
||||
popal
|
||||
@@ -67,7 +67,7 @@ intcall:
|
||||
jz 4f
|
||||
movw %sp, %si
|
||||
movw $11, %cx
|
||||
rep; movsd
|
||||
rep; movsl
|
||||
4: addw $44, %sp
|
||||
|
||||
/* Restore state and return */
|
||||
|
||||
@@ -146,6 +146,30 @@ static inline struct rmid_entry *__rmid_entry(u32 rmid)
|
||||
return entry;
|
||||
}
|
||||
|
||||
static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val)
|
||||
{
|
||||
u64 msr_val;
|
||||
|
||||
/*
|
||||
* As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
|
||||
* with a valid event code for supported resource type and the bits
|
||||
* IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
|
||||
* IA32_QM_CTR.data (bits 61:0) reports the monitored data.
|
||||
* IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
|
||||
* are error bits.
|
||||
*/
|
||||
wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
|
||||
rdmsrl(MSR_IA32_QM_CTR, msr_val);
|
||||
|
||||
if (msr_val & RMID_VAL_ERROR)
|
||||
return -EIO;
|
||||
if (msr_val & RMID_VAL_UNAVAIL)
|
||||
return -EINVAL;
|
||||
|
||||
*val = msr_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
|
||||
u32 rmid,
|
||||
enum resctrl_event_id eventid)
|
||||
@@ -172,8 +196,12 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
|
||||
struct arch_mbm_state *am;
|
||||
|
||||
am = get_arch_mbm_state(hw_dom, rmid, eventid);
|
||||
if (am)
|
||||
if (am) {
|
||||
memset(am, 0, sizeof(*am));
|
||||
|
||||
/* Record any initial, non-zero count value. */
|
||||
__rmid_read(rmid, eventid, &am->prev_msr);
|
||||
}
|
||||
}
|
||||
|
||||
static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
|
||||
@@ -191,25 +219,14 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
|
||||
struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
|
||||
struct arch_mbm_state *am;
|
||||
u64 msr_val, chunks;
|
||||
int ret;
|
||||
|
||||
if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
|
||||
* with a valid event code for supported resource type and the bits
|
||||
* IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
|
||||
* IA32_QM_CTR.data (bits 61:0) reports the monitored data.
|
||||
* IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
|
||||
* are error bits.
|
||||
*/
|
||||
wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
|
||||
rdmsrl(MSR_IA32_QM_CTR, msr_val);
|
||||
|
||||
if (msr_val & RMID_VAL_ERROR)
|
||||
return -EIO;
|
||||
if (msr_val & RMID_VAL_UNAVAIL)
|
||||
return -EINVAL;
|
||||
ret = __rmid_read(rmid, eventid, &msr_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
am = get_arch_mbm_state(hw_dom, rmid, eventid);
|
||||
if (am) {
|
||||
|
||||
@@ -580,8 +580,10 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
|
||||
/*
|
||||
* Ensure the task's closid and rmid are written before determining if
|
||||
* the task is current that will decide if it will be interrupted.
|
||||
* This pairs with the full barrier between the rq->curr update and
|
||||
* resctrl_sched_in() during context switch.
|
||||
*/
|
||||
barrier();
|
||||
smp_mb();
|
||||
|
||||
/*
|
||||
* By now, the task's closid and rmid are set. If the task is current
|
||||
@@ -2401,6 +2403,14 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
|
||||
WRITE_ONCE(t->closid, to->closid);
|
||||
WRITE_ONCE(t->rmid, to->mon.rmid);
|
||||
|
||||
/*
|
||||
* Order the closid/rmid stores above before the loads
|
||||
* in task_curr(). This pairs with the full barrier
|
||||
* between the rq->curr update and resctrl_sched_in()
|
||||
* during context switch.
|
||||
*/
|
||||
smp_mb();
|
||||
|
||||
/*
|
||||
* If the task is on a CPU, set the CPU in the mask.
|
||||
* The detection is inaccurate as tasks might move or
|
||||
|
||||
@@ -759,15 +759,21 @@ struct kvm_cpuid_array {
|
||||
int nent;
|
||||
};
|
||||
|
||||
static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
|
||||
u32 function, u32 index)
|
||||
static struct kvm_cpuid_entry2 *get_next_cpuid(struct kvm_cpuid_array *array)
|
||||
{
|
||||
struct kvm_cpuid_entry2 *entry;
|
||||
|
||||
if (array->nent >= array->maxnent)
|
||||
return NULL;
|
||||
|
||||
entry = &array->entries[array->nent++];
|
||||
return &array->entries[array->nent++];
|
||||
}
|
||||
|
||||
static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
|
||||
u32 function, u32 index)
|
||||
{
|
||||
struct kvm_cpuid_entry2 *entry = get_next_cpuid(array);
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->function = function;
|
||||
@@ -945,22 +951,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
||||
entry->edx = edx.full;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Per Intel's SDM, the 0x1f is a superset of 0xb,
|
||||
* thus they can be handled by common code.
|
||||
*/
|
||||
case 0x1f:
|
||||
case 0xb:
|
||||
/*
|
||||
* Populate entries until the level type (ECX[15:8]) of the
|
||||
* previous entry is zero. Note, CPUID EAX.{0x1f,0xb}.0 is
|
||||
* the starting entry, filled by the primary do_host_cpuid().
|
||||
* No topology; a valid topology is indicated by the presence
|
||||
* of subleaf 1.
|
||||
*/
|
||||
for (i = 1; entry->ecx & 0xff00; ++i) {
|
||||
entry = do_host_cpuid(array, function, i);
|
||||
if (!entry)
|
||||
goto out;
|
||||
}
|
||||
entry->eax = entry->ebx = entry->ecx = 0;
|
||||
break;
|
||||
case 0xd: {
|
||||
u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm();
|
||||
@@ -1193,6 +1190,9 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
||||
entry->ebx = entry->ecx = entry->edx = 0;
|
||||
break;
|
||||
case 0x8000001e:
|
||||
/* Do not return host topology information. */
|
||||
entry->eax = entry->ebx = entry->ecx = 0;
|
||||
entry->edx = 0; /* reserved */
|
||||
break;
|
||||
case 0x8000001F:
|
||||
if (!kvm_cpu_cap_has(X86_FEATURE_SEV)) {
|
||||
|
||||
@@ -434,7 +434,8 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
|
||||
u8 mtrr_type, uniform;
|
||||
|
||||
mtrr_type = mtrr_type_lookup(start, end, &uniform);
|
||||
if (mtrr_type != MTRR_TYPE_WRBACK)
|
||||
if (mtrr_type != MTRR_TYPE_WRBACK &&
|
||||
mtrr_type != MTRR_TYPE_INVALID)
|
||||
return _PAGE_CACHE_MODE_UC_MINUS;
|
||||
|
||||
return _PAGE_CACHE_MODE_WB;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <asm/elf.h>
|
||||
|
||||
|
||||
Elf32_Half elf_core_extra_phdrs(void)
|
||||
Elf32_Half elf_core_extra_phdrs(struct coredump_params *cprm)
|
||||
{
|
||||
return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t elf_core_extra_data_size(void)
|
||||
size_t elf_core_extra_data_size(struct coredump_params *cprm)
|
||||
{
|
||||
if ( vsyscall_ehdr ) {
|
||||
const struct elfhdr *const ehdrp =
|
||||
|
||||
@@ -358,11 +358,13 @@ struct bio *__bio_split_to_limits(struct bio *bio, struct queue_limits *lim,
|
||||
default:
|
||||
split = bio_split_rw(bio, lim, nr_segs, bs,
|
||||
get_max_io_size(bio, lim) << SECTOR_SHIFT);
|
||||
if (IS_ERR(split))
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (split) {
|
||||
/* there isn't chance to merge the splitted bio */
|
||||
/* there isn't chance to merge the split bio */
|
||||
split->bi_opf |= REQ_NOMERGE;
|
||||
|
||||
blkcg_bio_issue_init(split);
|
||||
|
||||
@@ -2919,8 +2919,11 @@ void blk_mq_submit_bio(struct bio *bio)
|
||||
blk_status_t ret;
|
||||
|
||||
bio = blk_queue_bounce(bio, q);
|
||||
if (bio_may_exceed_limits(bio, &q->limits))
|
||||
if (bio_may_exceed_limits(bio, &q->limits)) {
|
||||
bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
|
||||
if (!bio)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bio_integrity_prep(bio))
|
||||
return;
|
||||
|
||||
@@ -75,7 +75,8 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
|
||||
}
|
||||
|
||||
#define FIND_CHILD_MIN_SCORE 1
|
||||
#define FIND_CHILD_MAX_SCORE 2
|
||||
#define FIND_CHILD_MID_SCORE 2
|
||||
#define FIND_CHILD_MAX_SCORE 3
|
||||
|
||||
static int match_any(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
@@ -96,8 +97,17 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
|
||||
if (status == AE_NOT_FOUND)
|
||||
if (status == AE_NOT_FOUND) {
|
||||
/*
|
||||
* Special case: backlight device objects without _STA are
|
||||
* preferred to other objects with the same _ADR value, because
|
||||
* it is more likely that they are actually useful.
|
||||
*/
|
||||
if (adev->pnp.type.backlight)
|
||||
return FIND_CHILD_MID_SCORE;
|
||||
|
||||
return FIND_CHILD_MIN_SCORE;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1370,9 +1370,12 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
|
||||
* Some devices don't reliably have _HIDs & _CIDs, so add
|
||||
* synthetic HIDs to make sure drivers can find them.
|
||||
*/
|
||||
if (acpi_is_video_device(handle))
|
||||
if (acpi_is_video_device(handle)) {
|
||||
acpi_add_id(pnp, ACPI_VIDEO_HID);
|
||||
else if (acpi_bay_match(handle))
|
||||
pnp->type.backlight = 1;
|
||||
break;
|
||||
}
|
||||
if (acpi_bay_match(handle))
|
||||
acpi_add_id(pnp, ACPI_BAY_HID);
|
||||
else if (acpi_dock_match(handle))
|
||||
acpi_add_id(pnp, ACPI_DOCK_HID);
|
||||
|
||||
@@ -50,6 +50,10 @@ static void acpi_video_parse_cmdline(void)
|
||||
acpi_backlight_cmdline = acpi_backlight_video;
|
||||
if (!strcmp("native", acpi_video_backlight_string))
|
||||
acpi_backlight_cmdline = acpi_backlight_native;
|
||||
if (!strcmp("nvidia_wmi_ec", acpi_video_backlight_string))
|
||||
acpi_backlight_cmdline = acpi_backlight_nvidia_wmi_ec;
|
||||
if (!strcmp("apple_gmux", acpi_video_backlight_string))
|
||||
acpi_backlight_cmdline = acpi_backlight_apple_gmux;
|
||||
if (!strcmp("none", acpi_video_backlight_string))
|
||||
acpi_backlight_cmdline = acpi_backlight_none;
|
||||
}
|
||||
|
||||
@@ -1607,6 +1607,8 @@ void drbd_submit_bio(struct bio *bio)
|
||||
struct drbd_device *device = bio->bi_bdev->bd_disk->private_data;
|
||||
|
||||
bio = bio_split_to_limits(bio);
|
||||
if (!bio)
|
||||
return;
|
||||
|
||||
/*
|
||||
* what we "blindly" assume:
|
||||
|
||||
@@ -587,6 +587,8 @@ static void ps3vram_submit_bio(struct bio *bio)
|
||||
dev_dbg(&dev->core, "%s\n", __func__);
|
||||
|
||||
bio = bio_split_to_limits(bio);
|
||||
if (!bio)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
busy = !bio_list_empty(&priv->list);
|
||||
|
||||
@@ -307,6 +307,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
|
||||
max_perf = min_perf;
|
||||
|
||||
amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true);
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static int amd_get_min_freq(struct amd_cpudata *cpudata)
|
||||
|
||||
@@ -394,17 +394,16 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
|
||||
* Then restart the workq on the new delay
|
||||
*/
|
||||
void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
|
||||
unsigned long value)
|
||||
unsigned long msec)
|
||||
{
|
||||
unsigned long jiffs = msecs_to_jiffies(value);
|
||||
edac_dev->poll_msec = msec;
|
||||
edac_dev->delay = msecs_to_jiffies(msec);
|
||||
|
||||
if (value == 1000)
|
||||
jiffs = round_jiffies_relative(value);
|
||||
|
||||
edac_dev->poll_msec = value;
|
||||
edac_dev->delay = jiffs;
|
||||
|
||||
edac_mod_work(&edac_dev->work, jiffs);
|
||||
/* See comment in edac_device_workq_setup() above */
|
||||
if (edac_dev->poll_msec == 1000)
|
||||
edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
|
||||
else
|
||||
edac_mod_work(&edac_dev->work, edac_dev->delay);
|
||||
}
|
||||
|
||||
int edac_device_alloc_index(void)
|
||||
|
||||
@@ -52,7 +52,7 @@ bool edac_stop_work(struct delayed_work *work);
|
||||
bool edac_mod_work(struct delayed_work *work, unsigned long delay);
|
||||
|
||||
extern void edac_device_reset_delay_period(struct edac_device_ctl_info
|
||||
*edac_dev, unsigned long value);
|
||||
*edac_dev, unsigned long msec);
|
||||
extern void edac_mc_reset_delay_period(unsigned long value);
|
||||
|
||||
/*
|
||||
|
||||
@@ -374,8 +374,8 @@ static int __init efisubsys_init(void)
|
||||
efi_kobj = kobject_create_and_add("efi", firmware_kobj);
|
||||
if (!efi_kobj) {
|
||||
pr_err("efi: Firmware registration failed.\n");
|
||||
destroy_workqueue(efi_rts_wq);
|
||||
return -ENOMEM;
|
||||
error = -ENOMEM;
|
||||
goto err_destroy_wq;
|
||||
}
|
||||
|
||||
if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
|
||||
@@ -423,7 +423,10 @@ err_unregister:
|
||||
generic_ops_unregister();
|
||||
err_put:
|
||||
kobject_put(efi_kobj);
|
||||
destroy_workqueue(efi_rts_wq);
|
||||
err_destroy_wq:
|
||||
if (efi_rts_wq)
|
||||
destroy_workqueue(efi_rts_wq);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ struct efi_runtime_work efi_rts_work;
|
||||
\
|
||||
if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \
|
||||
pr_warn_once("EFI Runtime Services are disabled!\n"); \
|
||||
efi_rts_work.status = EFI_DEVICE_ERROR; \
|
||||
goto exit; \
|
||||
} \
|
||||
\
|
||||
|
||||
@@ -440,6 +440,9 @@ static const struct file_operations psci_debugfs_ops = {
|
||||
|
||||
static int __init psci_debugfs_init(void)
|
||||
{
|
||||
if (!invoke_psci_fn || !psci_ops.get_version)
|
||||
return 0;
|
||||
|
||||
return PTR_ERR_OR_ZERO(debugfs_create_file("psci", 0444, NULL, NULL,
|
||||
&psci_debugfs_ops));
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <generated/utsrelease.h>
|
||||
#include <linux/pci-p2pdma.h>
|
||||
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
@@ -89,6 +90,8 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
|
||||
#define AMDGPU_MAX_RETRY_LIMIT 2
|
||||
#define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL)
|
||||
|
||||
static const struct drm_driver amdgpu_kms_driver;
|
||||
|
||||
const char *amdgpu_asic_name[] = {
|
||||
"TAHITI",
|
||||
"PITCAIRN",
|
||||
@@ -3677,6 +3680,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Get rid of things like offb */
|
||||
r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Enable TMZ based on IP_VERSION */
|
||||
amdgpu_gmc_tmz_set(adev);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
@@ -2123,11 +2122,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get rid of things like offb */
|
||||
ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev);
|
||||
if (IS_ERR(adev))
|
||||
return PTR_ERR(adev);
|
||||
|
||||
@@ -468,8 +468,9 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
|
||||
return true;
|
||||
|
||||
fail:
|
||||
DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
|
||||
man->size);
|
||||
if (man)
|
||||
DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
|
||||
man->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -882,7 +882,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
|
||||
kfree(rsv);
|
||||
|
||||
list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
|
||||
drm_buddy_free_list(&mgr->mm, &rsv->blocks);
|
||||
drm_buddy_free_list(&mgr->mm, &rsv->allocated);
|
||||
kfree(rsv);
|
||||
}
|
||||
drm_buddy_fini(&mgr->mm);
|
||||
|
||||
@@ -322,6 +322,7 @@ soc21_asic_reset_method(struct amdgpu_device *adev)
|
||||
switch (adev->ip_versions[MP1_HWIP][0]) {
|
||||
case IP_VERSION(13, 0, 0):
|
||||
case IP_VERSION(13, 0, 7):
|
||||
case IP_VERSION(13, 0, 10):
|
||||
return AMD_RESET_METHOD_MODE1;
|
||||
case IP_VERSION(13, 0, 4):
|
||||
return AMD_RESET_METHOD_MODE2;
|
||||
@@ -652,6 +653,16 @@ static int soc21_common_early_init(void *handle)
|
||||
}
|
||||
adev->external_rev_id = adev->rev_id + 0x20;
|
||||
break;
|
||||
case IP_VERSION(11, 0, 4):
|
||||
adev->cg_flags = AMD_CG_SUPPORT_VCN_MGCG |
|
||||
AMD_CG_SUPPORT_JPEG_MGCG;
|
||||
adev->pg_flags = AMD_PG_SUPPORT_VCN |
|
||||
AMD_PG_SUPPORT_VCN_DPG |
|
||||
AMD_PG_SUPPORT_GFX_PG |
|
||||
AMD_PG_SUPPORT_JPEG;
|
||||
adev->external_rev_id = adev->rev_id + 0x1;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* FIXME: not supported yet */
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1919,8 +1919,9 @@ int dcn32_populate_dml_pipes_from_context(
|
||||
timing = &pipe->stream->timing;
|
||||
|
||||
pipes[pipe_cnt].pipe.src.gpuvm = true;
|
||||
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
|
||||
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
|
||||
DC_FP_START();
|
||||
dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt);
|
||||
DC_FP_END();
|
||||
pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
|
||||
pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet
|
||||
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
|
||||
|
||||
@@ -2546,3 +2546,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
|
||||
}
|
||||
}
|
||||
|
||||
void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
|
||||
int pipe_cnt)
|
||||
{
|
||||
dc_assert_fp_enabled();
|
||||
|
||||
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
|
||||
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
|
||||
}
|
||||
|
||||
@@ -73,4 +73,7 @@ int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
|
||||
|
||||
void dcn32_patch_dpm_table(struct clk_bw_params *bw_params);
|
||||
|
||||
void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
|
||||
int pipe_cnt);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,22 +67,21 @@ int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
|
||||
int vega10_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr,
|
||||
uint32_t *speed)
|
||||
{
|
||||
uint32_t current_rpm;
|
||||
uint32_t percent = 0;
|
||||
struct amdgpu_device *adev = hwmgr->adev;
|
||||
uint32_t duty100, duty;
|
||||
uint64_t tmp64;
|
||||
|
||||
if (hwmgr->thermal_controller.fanInfo.bNoFan)
|
||||
return 0;
|
||||
duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
|
||||
CG_FDO_CTRL1, FMAX_DUTY100);
|
||||
duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
|
||||
CG_THERMAL_STATUS, FDO_PWM_DUTY);
|
||||
|
||||
if (vega10_get_current_rpm(hwmgr, ¤t_rpm))
|
||||
return -1;
|
||||
if (!duty100)
|
||||
return -EINVAL;
|
||||
|
||||
if (hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usMaxFanRPM != 0)
|
||||
percent = current_rpm * 255 /
|
||||
hwmgr->thermal_controller.
|
||||
advanceFanControlParameters.usMaxFanRPM;
|
||||
|
||||
*speed = MIN(percent, 255);
|
||||
tmp64 = (uint64_t)duty * 255;
|
||||
do_div(tmp64, duty100);
|
||||
*speed = MIN((uint32_t)tmp64, 255);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -568,6 +568,10 @@ struct smu_context
|
||||
u32 param_reg;
|
||||
u32 msg_reg;
|
||||
u32 resp_reg;
|
||||
|
||||
u32 debug_param_reg;
|
||||
u32 debug_msg_reg;
|
||||
u32 debug_resp_reg;
|
||||
};
|
||||
|
||||
struct i2c_adapter;
|
||||
|
||||
@@ -131,7 +131,13 @@
|
||||
#define PPSMC_MSG_EnableAudioStutterWA 0x44
|
||||
#define PPSMC_MSG_PowerUpUmsch 0x45
|
||||
#define PPSMC_MSG_PowerDownUmsch 0x46
|
||||
#define PPSMC_Message_Count 0x47
|
||||
#define PPSMC_MSG_SetDcsArch 0x47
|
||||
#define PPSMC_MSG_TriggerVFFLR 0x48
|
||||
#define PPSMC_MSG_SetNumBadMemoryPagesRetired 0x49
|
||||
#define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A
|
||||
#define PPSMC_MSG_SetPriorityDeltaGain 0x4B
|
||||
#define PPSMC_MSG_AllowIHHostInterrupt 0x4C
|
||||
#define PPSMC_Message_Count 0x4D
|
||||
|
||||
//Debug Dump Message
|
||||
#define DEBUGSMC_MSG_TestMessage 0x1
|
||||
|
||||
@@ -239,7 +239,10 @@
|
||||
__SMU_DUMMY_MAP(DriverMode2Reset), \
|
||||
__SMU_DUMMY_MAP(GetGfxOffStatus), \
|
||||
__SMU_DUMMY_MAP(GetGfxOffEntryCount), \
|
||||
__SMU_DUMMY_MAP(LogGfxOffResidency),
|
||||
__SMU_DUMMY_MAP(LogGfxOffResidency), \
|
||||
__SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired), \
|
||||
__SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel), \
|
||||
__SMU_DUMMY_MAP(AllowGpo),
|
||||
|
||||
#undef __SMU_DUMMY_MAP
|
||||
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
|
||||
|
||||
@@ -273,6 +273,9 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu);
|
||||
|
||||
int smu_v13_0_run_btc(struct smu_context *smu);
|
||||
|
||||
int smu_v13_0_gpo_control(struct smu_context *smu,
|
||||
bool enablement);
|
||||
|
||||
int smu_v13_0_deep_sleep_control(struct smu_context *smu,
|
||||
bool enablement);
|
||||
|
||||
|
||||
@@ -1258,7 +1258,8 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
|
||||
uint32_t speed)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
uint32_t tach_period, crystal_clock_freq;
|
||||
uint32_t crystal_clock_freq = 2500;
|
||||
uint32_t tach_period;
|
||||
int ret;
|
||||
|
||||
if (!speed)
|
||||
@@ -1268,7 +1269,6 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
crystal_clock_freq = amdgpu_asic_get_xclk(adev);
|
||||
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
|
||||
WREG32_SOC15(THM, 0, regCG_TACH_CTRL,
|
||||
REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL),
|
||||
@@ -2148,6 +2148,21 @@ int smu_v13_0_run_btc(struct smu_context *smu)
|
||||
return res;
|
||||
}
|
||||
|
||||
int smu_v13_0_gpo_control(struct smu_context *smu,
|
||||
bool enablement)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_AllowGpo,
|
||||
enablement ? 1 : 0,
|
||||
NULL);
|
||||
if (res)
|
||||
dev_err(smu->adev->dev, "SetGpoAllow %d failed!\n", enablement);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int smu_v13_0_deep_sleep_control(struct smu_context *smu,
|
||||
bool enablement)
|
||||
{
|
||||
@@ -2249,6 +2264,10 @@ bool smu_v13_0_baco_is_support(struct smu_context *smu)
|
||||
!smu_baco->platform_support)
|
||||
return false;
|
||||
|
||||
/* return true if ASIC is in BACO state already */
|
||||
if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER)
|
||||
return true;
|
||||
|
||||
if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) &&
|
||||
!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
|
||||
return false;
|
||||
|
||||
@@ -70,6 +70,26 @@
|
||||
|
||||
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_66 0x0282
|
||||
#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_82 0x0292
|
||||
#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_90 0x029a
|
||||
#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_75 0x028b
|
||||
#define mmMP1_SMN_C2PMSG_75_BASE_IDX 0
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_53 0x0275
|
||||
#define mmMP1_SMN_C2PMSG_53_BASE_IDX 0
|
||||
|
||||
#define mmMP1_SMN_C2PMSG_54 0x0276
|
||||
#define mmMP1_SMN_C2PMSG_54_BASE_IDX 0
|
||||
|
||||
#define DEBUGSMC_MSG_Mode1Reset 2
|
||||
|
||||
static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = {
|
||||
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
|
||||
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1),
|
||||
@@ -121,6 +141,10 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
|
||||
MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0),
|
||||
MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
|
||||
MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
|
||||
MSG_MAP(SetNumBadMemoryPagesRetired, PPSMC_MSG_SetNumBadMemoryPagesRetired, 0),
|
||||
MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel,
|
||||
PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel, 0),
|
||||
MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
|
||||
@@ -189,6 +213,7 @@ static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] =
|
||||
FEA_MAP(SOC_PCC),
|
||||
[SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
|
||||
[SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
|
||||
[SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
|
||||
@@ -1878,6 +1903,69 @@ static int smu_v13_0_0_set_df_cstate(struct smu_context *smu,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
|
||||
ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
|
||||
else
|
||||
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL);
|
||||
|
||||
if (!ret)
|
||||
msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82);
|
||||
smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66);
|
||||
smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
|
||||
|
||||
smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53);
|
||||
smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75);
|
||||
smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54);
|
||||
}
|
||||
|
||||
static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu,
|
||||
uint32_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* message SMU to update the bad page number on SMUBUS */
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetNumBadMemoryPagesRetired,
|
||||
size, NULL);
|
||||
if (ret)
|
||||
dev_err(smu->adev->dev,
|
||||
"[%s] failed to message SMU to update bad memory pages number\n",
|
||||
__func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_v13_0_0_send_bad_mem_channel_flag(struct smu_context *smu,
|
||||
uint32_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* message SMU to update the bad channel info on SMUBUS */
|
||||
ret = smu_cmn_send_smc_msg_with_param(smu,
|
||||
SMU_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,
|
||||
size, NULL);
|
||||
if (ret)
|
||||
dev_err(smu->adev->dev,
|
||||
"[%s] failed to message SMU to update bad memory pages channel info\n",
|
||||
__func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
|
||||
.get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
|
||||
.set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
|
||||
@@ -1945,9 +2033,12 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
|
||||
.baco_enter = smu_v13_0_0_baco_enter,
|
||||
.baco_exit = smu_v13_0_0_baco_exit,
|
||||
.mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported,
|
||||
.mode1_reset = smu_v13_0_mode1_reset,
|
||||
.mode1_reset = smu_v13_0_0_mode1_reset,
|
||||
.set_mp1_state = smu_v13_0_0_set_mp1_state,
|
||||
.set_df_cstate = smu_v13_0_0_set_df_cstate,
|
||||
.send_hbm_bad_pages_num = smu_v13_0_0_smu_send_bad_mem_page_num,
|
||||
.send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
|
||||
.gpo_control = smu_v13_0_gpo_control,
|
||||
};
|
||||
|
||||
void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
|
||||
@@ -1959,5 +2050,5 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)
|
||||
smu->table_map = smu_v13_0_0_table_map;
|
||||
smu->pwr_src_map = smu_v13_0_0_pwr_src_map;
|
||||
smu->workload_map = smu_v13_0_0_workload_map;
|
||||
smu_v13_0_set_smu_mailbox_registers(smu);
|
||||
smu_v13_0_0_set_smu_mailbox_registers(smu);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
|
||||
MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0),
|
||||
MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
|
||||
MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
|
||||
MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
|
||||
@@ -191,6 +192,7 @@ static struct cmn2asic_mapping smu_v13_0_7_feature_mask_map[SMU_FEATURE_COUNT] =
|
||||
FEA_MAP(SOC_PCC),
|
||||
[SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
|
||||
[SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
|
||||
[SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
|
||||
};
|
||||
|
||||
static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {
|
||||
@@ -1711,6 +1713,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
|
||||
.mode1_reset = smu_v13_0_mode1_reset,
|
||||
.set_mp1_state = smu_v13_0_7_set_mp1_state,
|
||||
.set_df_cstate = smu_v13_0_7_set_df_cstate,
|
||||
.gpo_control = smu_v13_0_gpo_control,
|
||||
};
|
||||
|
||||
void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu)
|
||||
|
||||
@@ -233,6 +233,18 @@ static void __smu_cmn_send_msg(struct smu_context *smu,
|
||||
WREG32(smu->msg_reg, msg);
|
||||
}
|
||||
|
||||
static int __smu_cmn_send_debug_msg(struct smu_context *smu,
|
||||
u32 msg,
|
||||
u32 param)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
WREG32(smu->debug_param_reg, param);
|
||||
WREG32(smu->debug_msg_reg, msg);
|
||||
WREG32(smu->debug_resp_reg, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* smu_cmn_send_msg_without_waiting -- send the message; don't wait for status
|
||||
* @smu: pointer to an SMU context
|
||||
@@ -386,6 +398,12 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
|
||||
read_arg);
|
||||
}
|
||||
|
||||
int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
|
||||
uint32_t msg)
|
||||
{
|
||||
return __smu_cmn_send_debug_msg(smu, msg, 0);
|
||||
}
|
||||
|
||||
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
|
||||
enum smu_cmn2asic_mapping_type type,
|
||||
uint32_t index)
|
||||
|
||||
@@ -42,6 +42,9 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
|
||||
enum smu_message_type msg,
|
||||
uint32_t *read_arg);
|
||||
|
||||
int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
|
||||
uint32_t msg);
|
||||
|
||||
int smu_cmn_wait_for_response(struct smu_context *smu);
|
||||
|
||||
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
|
||||
|
||||
@@ -38,6 +38,25 @@ static void drm_block_free(struct drm_buddy *mm,
|
||||
kmem_cache_free(slab_blocks, block);
|
||||
}
|
||||
|
||||
static void list_insert_sorted(struct drm_buddy *mm,
|
||||
struct drm_buddy_block *block)
|
||||
{
|
||||
struct drm_buddy_block *node;
|
||||
struct list_head *head;
|
||||
|
||||
head = &mm->free_list[drm_buddy_block_order(block)];
|
||||
if (list_empty(head)) {
|
||||
list_add(&block->link, head);
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(node, head, link)
|
||||
if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node))
|
||||
break;
|
||||
|
||||
__list_add(&block->link, node->link.prev, &node->link);
|
||||
}
|
||||
|
||||
static void mark_allocated(struct drm_buddy_block *block)
|
||||
{
|
||||
block->header &= ~DRM_BUDDY_HEADER_STATE;
|
||||
@@ -52,8 +71,7 @@ static void mark_free(struct drm_buddy *mm,
|
||||
block->header &= ~DRM_BUDDY_HEADER_STATE;
|
||||
block->header |= DRM_BUDDY_FREE;
|
||||
|
||||
list_add(&block->link,
|
||||
&mm->free_list[drm_buddy_block_order(block)]);
|
||||
list_insert_sorted(mm, block);
|
||||
}
|
||||
|
||||
static void mark_split(struct drm_buddy_block *block)
|
||||
@@ -387,20 +405,26 @@ err_undo:
|
||||
}
|
||||
|
||||
static struct drm_buddy_block *
|
||||
get_maxblock(struct list_head *head)
|
||||
get_maxblock(struct drm_buddy *mm, unsigned int order)
|
||||
{
|
||||
struct drm_buddy_block *max_block = NULL, *node;
|
||||
unsigned int i;
|
||||
|
||||
max_block = list_first_entry_or_null(head,
|
||||
struct drm_buddy_block,
|
||||
link);
|
||||
if (!max_block)
|
||||
return NULL;
|
||||
for (i = order; i <= mm->max_order; ++i) {
|
||||
if (!list_empty(&mm->free_list[i])) {
|
||||
node = list_last_entry(&mm->free_list[i],
|
||||
struct drm_buddy_block,
|
||||
link);
|
||||
if (!max_block) {
|
||||
max_block = node;
|
||||
continue;
|
||||
}
|
||||
|
||||
list_for_each_entry(node, head, link) {
|
||||
if (drm_buddy_block_offset(node) >
|
||||
drm_buddy_block_offset(max_block))
|
||||
max_block = node;
|
||||
if (drm_buddy_block_offset(node) >
|
||||
drm_buddy_block_offset(max_block)) {
|
||||
max_block = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max_block;
|
||||
@@ -412,20 +436,23 @@ alloc_from_freelist(struct drm_buddy *mm,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct drm_buddy_block *block = NULL;
|
||||
unsigned int i;
|
||||
unsigned int tmp;
|
||||
int err;
|
||||
|
||||
for (i = order; i <= mm->max_order; ++i) {
|
||||
if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
|
||||
block = get_maxblock(&mm->free_list[i]);
|
||||
if (block)
|
||||
break;
|
||||
} else {
|
||||
block = list_first_entry_or_null(&mm->free_list[i],
|
||||
struct drm_buddy_block,
|
||||
link);
|
||||
if (block)
|
||||
break;
|
||||
if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
|
||||
block = get_maxblock(mm, order);
|
||||
if (block)
|
||||
/* Store the obtained block order */
|
||||
tmp = drm_buddy_block_order(block);
|
||||
} else {
|
||||
for (tmp = order; tmp <= mm->max_order; ++tmp) {
|
||||
if (!list_empty(&mm->free_list[tmp])) {
|
||||
block = list_last_entry(&mm->free_list[tmp],
|
||||
struct drm_buddy_block,
|
||||
link);
|
||||
if (block)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,18 +461,18 @@ alloc_from_freelist(struct drm_buddy *mm,
|
||||
|
||||
BUG_ON(!drm_buddy_block_is_free(block));
|
||||
|
||||
while (i != order) {
|
||||
while (tmp != order) {
|
||||
err = split_block(mm, block);
|
||||
if (unlikely(err))
|
||||
goto err_undo;
|
||||
|
||||
block = block->right;
|
||||
i--;
|
||||
tmp--;
|
||||
}
|
||||
return block;
|
||||
|
||||
err_undo:
|
||||
if (i != order)
|
||||
if (tmp != order)
|
||||
__drm_buddy_free(mm, block);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
@@ -1688,6 +1688,10 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
|
||||
init_contexts(&i915->gem.contexts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this implicitly consumes the ctx reference, by placing
|
||||
* the ctx in the context_xa.
|
||||
*/
|
||||
static void gem_context_register(struct i915_gem_context *ctx,
|
||||
struct drm_i915_file_private *fpriv,
|
||||
u32 id)
|
||||
@@ -1703,10 +1707,6 @@ static void gem_context_register(struct i915_gem_context *ctx,
|
||||
snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
|
||||
current->comm, pid_nr(ctx->pid));
|
||||
|
||||
/* And finally expose ourselves to userspace via the idr */
|
||||
old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
|
||||
WARN_ON(old);
|
||||
|
||||
spin_lock(&ctx->client->ctx_lock);
|
||||
list_add_tail_rcu(&ctx->client_link, &ctx->client->ctx_list);
|
||||
spin_unlock(&ctx->client->ctx_lock);
|
||||
@@ -1714,6 +1714,10 @@ static void gem_context_register(struct i915_gem_context *ctx,
|
||||
spin_lock(&i915->gem.contexts.lock);
|
||||
list_add_tail(&ctx->link, &i915->gem.contexts.list);
|
||||
spin_unlock(&i915->gem.contexts.lock);
|
||||
|
||||
/* And finally expose ourselves to userspace via the idr */
|
||||
old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
|
||||
WARN_ON(old);
|
||||
}
|
||||
|
||||
int i915_gem_context_open(struct drm_i915_private *i915,
|
||||
@@ -2199,14 +2203,22 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv,
|
||||
if (IS_ERR(ctx))
|
||||
return ctx;
|
||||
|
||||
/*
|
||||
* One for the xarray and one for the caller. We need to grab
|
||||
* the reference *prior* to making the ctx visble to userspace
|
||||
* in gem_context_register(), as at any point after that
|
||||
* userspace can try to race us with another thread destroying
|
||||
* the context under our feet.
|
||||
*/
|
||||
i915_gem_context_get(ctx);
|
||||
|
||||
gem_context_register(ctx, file_priv, id);
|
||||
|
||||
old = xa_erase(&file_priv->proto_context_xa, id);
|
||||
GEM_BUG_ON(old != pc);
|
||||
proto_context_close(file_priv->dev_priv, pc);
|
||||
|
||||
/* One for the xarray and one for the caller */
|
||||
return i915_gem_context_get(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct i915_gem_context *
|
||||
|
||||
@@ -1343,8 +1343,13 @@ int intel_engines_init(struct intel_gt *gt)
|
||||
return err;
|
||||
|
||||
err = setup(engine);
|
||||
if (err)
|
||||
if (err) {
|
||||
intel_engine_cleanup_common(engine);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The backend should now be responsible for cleanup */
|
||||
GEM_BUG_ON(engine->release == NULL);
|
||||
|
||||
err = engine_init_common(engine);
|
||||
if (err)
|
||||
|
||||
@@ -22,11 +22,9 @@ bool is_object_gt(struct kobject *kobj)
|
||||
return !strncmp(kobj->name, "gt", 2);
|
||||
}
|
||||
|
||||
struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
|
||||
struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
|
||||
const char *name)
|
||||
{
|
||||
struct kobject *kobj = &dev->kobj;
|
||||
|
||||
/*
|
||||
* We are interested at knowing from where the interface
|
||||
* has been called, whether it's called from gt/ or from
|
||||
@@ -38,6 +36,7 @@ struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
|
||||
* "struct drm_i915_private *" type.
|
||||
*/
|
||||
if (!is_object_gt(kobj)) {
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
|
||||
|
||||
return to_gt(i915);
|
||||
@@ -51,18 +50,18 @@ static struct kobject *gt_get_parent_obj(struct intel_gt *gt)
|
||||
return >->i915->drm.primary->kdev->kobj;
|
||||
}
|
||||
|
||||
static ssize_t id_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
|
||||
return sysfs_emit(buf, "%u\n", gt->info.id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
static struct kobj_attribute attr_id = __ATTR_RO(id);
|
||||
|
||||
static struct attribute *id_attrs[] = {
|
||||
&dev_attr_id.attr,
|
||||
&attr_id.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(id);
|
||||
|
||||
@@ -30,7 +30,7 @@ static inline struct intel_gt *kobj_to_gt(struct kobject *kobj)
|
||||
|
||||
void intel_gt_sysfs_register(struct intel_gt *gt);
|
||||
void intel_gt_sysfs_unregister(struct intel_gt *gt);
|
||||
struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev,
|
||||
struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj,
|
||||
const char *name);
|
||||
|
||||
#endif /* SYSFS_GT_H */
|
||||
|
||||
@@ -24,14 +24,15 @@ enum intel_gt_sysfs_op {
|
||||
};
|
||||
|
||||
static int
|
||||
sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
|
||||
sysfs_gt_attribute_w_func(struct kobject *kobj, struct attribute *attr,
|
||||
int (func)(struct intel_gt *gt, u32 val), u32 val)
|
||||
{
|
||||
struct intel_gt *gt;
|
||||
int ret;
|
||||
|
||||
if (!is_object_gt(&dev->kobj)) {
|
||||
if (!is_object_gt(kobj)) {
|
||||
int i;
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
|
||||
|
||||
for_each_gt(gt, i915, i) {
|
||||
@@ -40,7 +41,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
|
||||
ret = func(gt, val);
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
|
||||
static u32
|
||||
sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
|
||||
sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr,
|
||||
u32 (func)(struct intel_gt *gt),
|
||||
enum intel_gt_sysfs_op op)
|
||||
{
|
||||
@@ -57,8 +58,9 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
ret = (op == INTEL_GT_SYSFS_MAX) ? 0 : (u32) -1;
|
||||
|
||||
if (!is_object_gt(&dev->kobj)) {
|
||||
if (!is_object_gt(kobj)) {
|
||||
int i;
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *i915 = kdev_minor_to_i915(dev);
|
||||
|
||||
for_each_gt(gt, i915, i) {
|
||||
@@ -77,7 +79,7 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
gt = intel_gt_sysfs_get_drvdata(kobj, attr->name);
|
||||
ret = func(gt);
|
||||
}
|
||||
|
||||
@@ -92,6 +94,76 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr,
|
||||
#define sysfs_gt_attribute_r_max_func(d, a, f) \
|
||||
sysfs_gt_attribute_r_func(d, a, f, INTEL_GT_SYSFS_MAX)
|
||||
|
||||
#define INTEL_GT_SYSFS_SHOW(_name, _attr_type) \
|
||||
static ssize_t _name##_show_common(struct kobject *kobj, \
|
||||
struct attribute *attr, char *buff) \
|
||||
{ \
|
||||
u32 val = sysfs_gt_attribute_r_##_attr_type##_func(kobj, attr, \
|
||||
__##_name##_show); \
|
||||
\
|
||||
return sysfs_emit(buff, "%u\n", val); \
|
||||
} \
|
||||
static ssize_t _name##_show(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buff) \
|
||||
{ \
|
||||
return _name ##_show_common(kobj, &attr->attr, buff); \
|
||||
} \
|
||||
static ssize_t _name##_dev_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buff) \
|
||||
{ \
|
||||
return _name##_show_common(&dev->kobj, &attr->attr, buff); \
|
||||
}
|
||||
|
||||
#define INTEL_GT_SYSFS_STORE(_name, _func) \
|
||||
static ssize_t _name##_store_common(struct kobject *kobj, \
|
||||
struct attribute *attr, \
|
||||
const char *buff, size_t count) \
|
||||
{ \
|
||||
int ret; \
|
||||
u32 val; \
|
||||
\
|
||||
ret = kstrtou32(buff, 0, &val); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
\
|
||||
ret = sysfs_gt_attribute_w_func(kobj, attr, _func, val); \
|
||||
\
|
||||
return ret ?: count; \
|
||||
} \
|
||||
static ssize_t _name##_store(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, const char *buff, \
|
||||
size_t count) \
|
||||
{ \
|
||||
return _name##_store_common(kobj, &attr->attr, buff, count); \
|
||||
} \
|
||||
static ssize_t _name##_dev_store(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buff, size_t count) \
|
||||
{ \
|
||||
return _name##_store_common(&dev->kobj, &attr->attr, buff, count); \
|
||||
}
|
||||
|
||||
#define INTEL_GT_SYSFS_SHOW_MAX(_name) INTEL_GT_SYSFS_SHOW(_name, max)
|
||||
#define INTEL_GT_SYSFS_SHOW_MIN(_name) INTEL_GT_SYSFS_SHOW(_name, min)
|
||||
|
||||
#define INTEL_GT_ATTR_RW(_name) \
|
||||
static struct kobj_attribute attr_##_name = __ATTR_RW(_name)
|
||||
|
||||
#define INTEL_GT_ATTR_RO(_name) \
|
||||
static struct kobj_attribute attr_##_name = __ATTR_RO(_name)
|
||||
|
||||
#define INTEL_GT_DUAL_ATTR_RW(_name) \
|
||||
static struct device_attribute dev_attr_##_name = __ATTR(_name, 0644, \
|
||||
_name##_dev_show, \
|
||||
_name##_dev_store); \
|
||||
INTEL_GT_ATTR_RW(_name)
|
||||
|
||||
#define INTEL_GT_DUAL_ATTR_RO(_name) \
|
||||
static struct device_attribute dev_attr_##_name = __ATTR(_name, 0444, \
|
||||
_name##_dev_show, \
|
||||
NULL); \
|
||||
INTEL_GT_ATTR_RO(_name)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 get_residency(struct intel_gt *gt, i915_reg_t reg)
|
||||
{
|
||||
@@ -104,11 +176,8 @@ static u32 get_residency(struct intel_gt *gt, i915_reg_t reg)
|
||||
return DIV_ROUND_CLOSEST_ULL(res, 1000);
|
||||
}
|
||||
|
||||
static ssize_t rc6_enable_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
static u8 get_rc6_mask(struct intel_gt *gt)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
u8 mask = 0;
|
||||
|
||||
if (HAS_RC6(gt->i915))
|
||||
@@ -118,7 +187,25 @@ static ssize_t rc6_enable_show(struct device *dev,
|
||||
if (HAS_RC6pp(gt->i915))
|
||||
mask |= BIT(2);
|
||||
|
||||
return sysfs_emit(buff, "%x\n", mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t rc6_enable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
|
||||
return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
|
||||
}
|
||||
|
||||
static ssize_t rc6_enable_dev_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name);
|
||||
|
||||
return sysfs_emit(buff, "%x\n", get_rc6_mask(gt));
|
||||
}
|
||||
|
||||
static u32 __rc6_residency_ms_show(struct intel_gt *gt)
|
||||
@@ -126,97 +213,79 @@ static u32 __rc6_residency_ms_show(struct intel_gt *gt)
|
||||
return get_residency(gt, GEN6_GT_GFX_RC6);
|
||||
}
|
||||
|
||||
static ssize_t rc6_residency_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
|
||||
__rc6_residency_ms_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rc6_residency);
|
||||
}
|
||||
|
||||
static u32 __rc6p_residency_ms_show(struct intel_gt *gt)
|
||||
{
|
||||
return get_residency(gt, GEN6_GT_GFX_RC6p);
|
||||
}
|
||||
|
||||
static ssize_t rc6p_residency_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
u32 rc6p_residency = sysfs_gt_attribute_r_min_func(dev, attr,
|
||||
__rc6p_residency_ms_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rc6p_residency);
|
||||
}
|
||||
|
||||
static u32 __rc6pp_residency_ms_show(struct intel_gt *gt)
|
||||
{
|
||||
return get_residency(gt, GEN6_GT_GFX_RC6pp);
|
||||
}
|
||||
|
||||
static ssize_t rc6pp_residency_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
u32 rc6pp_residency = sysfs_gt_attribute_r_min_func(dev, attr,
|
||||
__rc6pp_residency_ms_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rc6pp_residency);
|
||||
}
|
||||
|
||||
static u32 __media_rc6_residency_ms_show(struct intel_gt *gt)
|
||||
{
|
||||
return get_residency(gt, VLV_GT_MEDIA_RC6);
|
||||
}
|
||||
|
||||
static ssize_t media_rc6_residency_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr,
|
||||
__media_rc6_residency_ms_show);
|
||||
INTEL_GT_SYSFS_SHOW_MIN(rc6_residency_ms);
|
||||
INTEL_GT_SYSFS_SHOW_MIN(rc6p_residency_ms);
|
||||
INTEL_GT_SYSFS_SHOW_MIN(rc6pp_residency_ms);
|
||||
INTEL_GT_SYSFS_SHOW_MIN(media_rc6_residency_ms);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rc6_residency);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(rc6_enable);
|
||||
static DEVICE_ATTR_RO(rc6_residency_ms);
|
||||
static DEVICE_ATTR_RO(rc6p_residency_ms);
|
||||
static DEVICE_ATTR_RO(rc6pp_residency_ms);
|
||||
static DEVICE_ATTR_RO(media_rc6_residency_ms);
|
||||
INTEL_GT_DUAL_ATTR_RO(rc6_enable);
|
||||
INTEL_GT_DUAL_ATTR_RO(rc6_residency_ms);
|
||||
INTEL_GT_DUAL_ATTR_RO(rc6p_residency_ms);
|
||||
INTEL_GT_DUAL_ATTR_RO(rc6pp_residency_ms);
|
||||
INTEL_GT_DUAL_ATTR_RO(media_rc6_residency_ms);
|
||||
|
||||
static struct attribute *rc6_attrs[] = {
|
||||
&attr_rc6_enable.attr,
|
||||
&attr_rc6_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *rc6p_attrs[] = {
|
||||
&attr_rc6p_residency_ms.attr,
|
||||
&attr_rc6pp_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *media_rc6_attrs[] = {
|
||||
&attr_media_rc6_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *rc6_dev_attrs[] = {
|
||||
&dev_attr_rc6_enable.attr,
|
||||
&dev_attr_rc6_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *rc6p_attrs[] = {
|
||||
static struct attribute *rc6p_dev_attrs[] = {
|
||||
&dev_attr_rc6p_residency_ms.attr,
|
||||
&dev_attr_rc6pp_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *media_rc6_attrs[] = {
|
||||
static struct attribute *media_rc6_dev_attrs[] = {
|
||||
&dev_attr_media_rc6_residency_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group rc6_attr_group[] = {
|
||||
{ .attrs = rc6_attrs, },
|
||||
{ .name = power_group_name, .attrs = rc6_attrs, },
|
||||
{ .name = power_group_name, .attrs = rc6_dev_attrs, },
|
||||
};
|
||||
|
||||
static const struct attribute_group rc6p_attr_group[] = {
|
||||
{ .attrs = rc6p_attrs, },
|
||||
{ .name = power_group_name, .attrs = rc6p_attrs, },
|
||||
{ .name = power_group_name, .attrs = rc6p_dev_attrs, },
|
||||
};
|
||||
|
||||
static const struct attribute_group media_rc6_attr_group[] = {
|
||||
{ .attrs = media_rc6_attrs, },
|
||||
{ .name = power_group_name, .attrs = media_rc6_attrs, },
|
||||
{ .name = power_group_name, .attrs = media_rc6_dev_attrs, },
|
||||
};
|
||||
|
||||
static int __intel_gt_sysfs_create_group(struct kobject *kobj,
|
||||
@@ -271,104 +340,34 @@ static u32 __act_freq_mhz_show(struct intel_gt *gt)
|
||||
return intel_rps_read_actual_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t act_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 actual_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__act_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", actual_freq);
|
||||
}
|
||||
|
||||
static u32 __cur_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_requested_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t cur_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 cur_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__cur_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", cur_freq);
|
||||
}
|
||||
|
||||
static u32 __boost_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_boost_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t boost_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
u32 boost_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__boost_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", boost_freq);
|
||||
}
|
||||
|
||||
static int __boost_freq_mhz_store(struct intel_gt *gt, u32 val)
|
||||
{
|
||||
return intel_rps_set_boost_frequency(>->rps, val);
|
||||
}
|
||||
|
||||
static ssize_t boost_freq_mhz_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
u32 val;
|
||||
|
||||
ret = kstrtou32(buff, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_gt_attribute_w_func(dev, attr,
|
||||
__boost_freq_mhz_store, val) ?: count;
|
||||
}
|
||||
|
||||
static u32 __rp0_freq_mhz_show(struct intel_gt *gt)
|
||||
static u32 __RP0_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_rp0_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t RP0_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 rp0_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__rp0_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rp0_freq);
|
||||
}
|
||||
|
||||
static u32 __rp1_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_rp1_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t RP1_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 rp1_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__rp1_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rp1_freq);
|
||||
}
|
||||
|
||||
static u32 __rpn_freq_mhz_show(struct intel_gt *gt)
|
||||
static u32 __RPn_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_rpn_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t RPn_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
static u32 __RP1_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
u32 rpn_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__rpn_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rpn_freq);
|
||||
return intel_rps_get_rp1_frequency(>->rps);
|
||||
}
|
||||
|
||||
static u32 __max_freq_mhz_show(struct intel_gt *gt)
|
||||
@@ -376,71 +375,21 @@ static u32 __max_freq_mhz_show(struct intel_gt *gt)
|
||||
return intel_rps_get_max_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t max_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 max_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__max_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", max_freq);
|
||||
}
|
||||
|
||||
static int __set_max_freq(struct intel_gt *gt, u32 val)
|
||||
{
|
||||
return intel_rps_set_max_frequency(>->rps, val);
|
||||
}
|
||||
|
||||
static ssize_t max_freq_mhz_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = kstrtou32(buff, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_gt_attribute_w_func(dev, attr, __set_max_freq, val);
|
||||
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static u32 __min_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
return intel_rps_get_min_frequency(>->rps);
|
||||
}
|
||||
|
||||
static ssize_t min_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 min_freq = sysfs_gt_attribute_r_min_func(dev, attr,
|
||||
__min_freq_mhz_show);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", min_freq);
|
||||
}
|
||||
|
||||
static int __set_min_freq(struct intel_gt *gt, u32 val)
|
||||
{
|
||||
return intel_rps_set_min_frequency(>->rps, val);
|
||||
}
|
||||
|
||||
static ssize_t min_freq_mhz_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = kstrtou32(buff, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_gt_attribute_w_func(dev, attr, __set_min_freq, val);
|
||||
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
|
||||
{
|
||||
struct intel_rps *rps = >->rps;
|
||||
@@ -448,23 +397,31 @@ static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt)
|
||||
return intel_gpu_freq(rps, rps->efficient_freq);
|
||||
}
|
||||
|
||||
static ssize_t vlv_rpe_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buff)
|
||||
{
|
||||
u32 rpe_freq = sysfs_gt_attribute_r_max_func(dev, attr,
|
||||
__vlv_rpe_freq_mhz_show);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(act_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(boost_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(cur_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(RP0_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(RP1_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(RPn_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(max_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MIN(min_freq_mhz);
|
||||
INTEL_GT_SYSFS_SHOW_MAX(vlv_rpe_freq_mhz);
|
||||
INTEL_GT_SYSFS_STORE(boost_freq_mhz, __boost_freq_mhz_store);
|
||||
INTEL_GT_SYSFS_STORE(max_freq_mhz, __set_max_freq);
|
||||
INTEL_GT_SYSFS_STORE(min_freq_mhz, __set_min_freq);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", rpe_freq);
|
||||
}
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store, _show_dev, _store_dev) \
|
||||
static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, \
|
||||
_show_dev, _store_dev); \
|
||||
static struct kobj_attribute attr_rps_##_name = __ATTR(rps_##_name, _mode, \
|
||||
_show, _store)
|
||||
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store) \
|
||||
static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, _show, _store); \
|
||||
static struct device_attribute dev_attr_rps_##_name = __ATTR(rps_##_name, _mode, _show, _store)
|
||||
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \
|
||||
INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL)
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \
|
||||
INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store)
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \
|
||||
INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL, \
|
||||
_name##_dev_show, NULL)
|
||||
#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \
|
||||
INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store, \
|
||||
_name##_dev_show, _name##_dev_store)
|
||||
|
||||
/* The below macros generate static structures */
|
||||
INTEL_GT_RPS_SYSFS_ATTR_RO(act_freq_mhz);
|
||||
@@ -475,32 +432,31 @@ INTEL_GT_RPS_SYSFS_ATTR_RO(RP1_freq_mhz);
|
||||
INTEL_GT_RPS_SYSFS_ATTR_RO(RPn_freq_mhz);
|
||||
INTEL_GT_RPS_SYSFS_ATTR_RW(max_freq_mhz);
|
||||
INTEL_GT_RPS_SYSFS_ATTR_RW(min_freq_mhz);
|
||||
INTEL_GT_RPS_SYSFS_ATTR_RO(vlv_rpe_freq_mhz);
|
||||
|
||||
static DEVICE_ATTR_RO(vlv_rpe_freq_mhz);
|
||||
|
||||
#define GEN6_ATTR(s) { \
|
||||
&dev_attr_##s##_act_freq_mhz.attr, \
|
||||
&dev_attr_##s##_cur_freq_mhz.attr, \
|
||||
&dev_attr_##s##_boost_freq_mhz.attr, \
|
||||
&dev_attr_##s##_max_freq_mhz.attr, \
|
||||
&dev_attr_##s##_min_freq_mhz.attr, \
|
||||
&dev_attr_##s##_RP0_freq_mhz.attr, \
|
||||
&dev_attr_##s##_RP1_freq_mhz.attr, \
|
||||
&dev_attr_##s##_RPn_freq_mhz.attr, \
|
||||
#define GEN6_ATTR(p, s) { \
|
||||
&p##attr_##s##_act_freq_mhz.attr, \
|
||||
&p##attr_##s##_cur_freq_mhz.attr, \
|
||||
&p##attr_##s##_boost_freq_mhz.attr, \
|
||||
&p##attr_##s##_max_freq_mhz.attr, \
|
||||
&p##attr_##s##_min_freq_mhz.attr, \
|
||||
&p##attr_##s##_RP0_freq_mhz.attr, \
|
||||
&p##attr_##s##_RP1_freq_mhz.attr, \
|
||||
&p##attr_##s##_RPn_freq_mhz.attr, \
|
||||
NULL, \
|
||||
}
|
||||
|
||||
#define GEN6_RPS_ATTR GEN6_ATTR(rps)
|
||||
#define GEN6_GT_ATTR GEN6_ATTR(gt)
|
||||
#define GEN6_RPS_ATTR GEN6_ATTR(, rps)
|
||||
#define GEN6_GT_ATTR GEN6_ATTR(dev_, gt)
|
||||
|
||||
static const struct attribute * const gen6_rps_attrs[] = GEN6_RPS_ATTR;
|
||||
static const struct attribute * const gen6_gt_attrs[] = GEN6_GT_ATTR;
|
||||
|
||||
static ssize_t punit_req_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t punit_req_freq_mhz_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
u32 preq = intel_rps_read_punit_req_frequency(>->rps);
|
||||
|
||||
return sysfs_emit(buff, "%u\n", preq);
|
||||
@@ -508,17 +464,17 @@ static ssize_t punit_req_freq_mhz_show(struct device *dev,
|
||||
|
||||
struct intel_gt_bool_throttle_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf);
|
||||
i915_reg_t reg32;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
static ssize_t throttle_reason_bool_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t throttle_reason_bool_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
struct intel_gt_bool_throttle_attr *t_attr =
|
||||
(struct intel_gt_bool_throttle_attr *) attr;
|
||||
bool val = rps_read_mask_mmio(>->rps, t_attr->reg32, t_attr->mask);
|
||||
@@ -534,7 +490,7 @@ struct intel_gt_bool_throttle_attr attr_##sysfs_func__ = { \
|
||||
.mask = mask__, \
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(punit_req_freq_mhz);
|
||||
INTEL_GT_ATTR_RO(punit_req_freq_mhz);
|
||||
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_status, GT0_PERF_LIMIT_REASONS_MASK);
|
||||
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl1, POWER_LIMIT_1_MASK);
|
||||
static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl2, POWER_LIMIT_2_MASK);
|
||||
@@ -597,8 +553,8 @@ static const struct attribute *throttle_reason_attrs[] = {
|
||||
#define U8_8_VAL_MASK 0xffff
|
||||
#define U8_8_SCALE_TO_VALUE "0.00390625"
|
||||
|
||||
static ssize_t freq_factor_scale_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t freq_factor_scale_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
return sysfs_emit(buff, "%s\n", U8_8_SCALE_TO_VALUE);
|
||||
@@ -610,11 +566,11 @@ static u32 media_ratio_mode_to_factor(u32 mode)
|
||||
return !mode ? mode : 256 / mode;
|
||||
}
|
||||
|
||||
static ssize_t media_freq_factor_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t media_freq_factor_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
struct intel_guc_slpc *slpc = >->uc.guc.slpc;
|
||||
intel_wakeref_t wakeref;
|
||||
u32 mode;
|
||||
@@ -641,11 +597,11 @@ static ssize_t media_freq_factor_show(struct device *dev,
|
||||
return sysfs_emit(buff, "%u\n", media_ratio_mode_to_factor(mode));
|
||||
}
|
||||
|
||||
static ssize_t media_freq_factor_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t media_freq_factor_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
struct intel_guc_slpc *slpc = >->uc.guc.slpc;
|
||||
u32 factor, mode;
|
||||
int err;
|
||||
@@ -670,11 +626,11 @@ static ssize_t media_freq_factor_store(struct device *dev,
|
||||
return err ?: count;
|
||||
}
|
||||
|
||||
static ssize_t media_RP0_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t media_RP0_freq_mhz_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
@@ -691,11 +647,11 @@ static ssize_t media_RP0_freq_mhz_show(struct device *dev,
|
||||
return sysfs_emit(buff, "%u\n", val);
|
||||
}
|
||||
|
||||
static ssize_t media_RPn_freq_mhz_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
static ssize_t media_RPn_freq_mhz_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buff)
|
||||
{
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name);
|
||||
struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name);
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
@@ -712,17 +668,17 @@ static ssize_t media_RPn_freq_mhz_show(struct device *dev,
|
||||
return sysfs_emit(buff, "%u\n", val);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(media_freq_factor);
|
||||
static struct device_attribute dev_attr_media_freq_factor_scale =
|
||||
INTEL_GT_ATTR_RW(media_freq_factor);
|
||||
static struct kobj_attribute attr_media_freq_factor_scale =
|
||||
__ATTR(media_freq_factor.scale, 0444, freq_factor_scale_show, NULL);
|
||||
static DEVICE_ATTR_RO(media_RP0_freq_mhz);
|
||||
static DEVICE_ATTR_RO(media_RPn_freq_mhz);
|
||||
INTEL_GT_ATTR_RO(media_RP0_freq_mhz);
|
||||
INTEL_GT_ATTR_RO(media_RPn_freq_mhz);
|
||||
|
||||
static const struct attribute *media_perf_power_attrs[] = {
|
||||
&dev_attr_media_freq_factor.attr,
|
||||
&dev_attr_media_freq_factor_scale.attr,
|
||||
&dev_attr_media_RP0_freq_mhz.attr,
|
||||
&dev_attr_media_RPn_freq_mhz.attr,
|
||||
&attr_media_freq_factor.attr,
|
||||
&attr_media_freq_factor_scale.attr,
|
||||
&attr_media_RP0_freq_mhz.attr,
|
||||
&attr_media_RPn_freq_mhz.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -754,20 +710,29 @@ static const struct attribute * const rps_defaults_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj,
|
||||
const struct attribute * const *attrs)
|
||||
static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj)
|
||||
{
|
||||
const struct attribute * const *attrs;
|
||||
struct attribute *vlv_attr;
|
||||
int ret;
|
||||
|
||||
if (GRAPHICS_VER(gt->i915) < 6)
|
||||
return 0;
|
||||
|
||||
if (is_object_gt(kobj)) {
|
||||
attrs = gen6_rps_attrs;
|
||||
vlv_attr = &attr_rps_vlv_rpe_freq_mhz.attr;
|
||||
} else {
|
||||
attrs = gen6_gt_attrs;
|
||||
vlv_attr = &dev_attr_gt_vlv_rpe_freq_mhz.attr;
|
||||
}
|
||||
|
||||
ret = sysfs_create_files(kobj, attrs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915))
|
||||
ret = sysfs_create_file(kobj, &dev_attr_vlv_rpe_freq_mhz.attr);
|
||||
ret = sysfs_create_file(kobj, vlv_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -778,9 +743,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
|
||||
|
||||
intel_sysfs_rc6_init(gt, kobj);
|
||||
|
||||
ret = is_object_gt(kobj) ?
|
||||
intel_sysfs_rps_init(gt, kobj, gen6_rps_attrs) :
|
||||
intel_sysfs_rps_init(gt, kobj, gen6_gt_attrs);
|
||||
ret = intel_sysfs_rps_init(gt, kobj);
|
||||
if (ret)
|
||||
drm_warn(>->i915->drm,
|
||||
"failed to create gt%u RPS sysfs files (%pe)",
|
||||
@@ -790,7 +753,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
|
||||
if (!is_object_gt(kobj))
|
||||
return;
|
||||
|
||||
ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr);
|
||||
ret = sysfs_create_file(kobj, &attr_punit_req_freq_mhz.attr);
|
||||
if (ret)
|
||||
drm_warn(>->i915->drm,
|
||||
"failed to create gt%u punit_req_freq_mhz sysfs (%pe)",
|
||||
|
||||
@@ -278,6 +278,7 @@ out:
|
||||
static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
|
||||
{
|
||||
struct intel_uncore *uncore = gt->uncore;
|
||||
int loops = 2;
|
||||
int err;
|
||||
|
||||
/*
|
||||
@@ -285,18 +286,39 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
|
||||
* for fifo space for the write or forcewake the chip for
|
||||
* the read
|
||||
*/
|
||||
intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
|
||||
do {
|
||||
intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
|
||||
|
||||
/* Wait for the device to ack the reset requests */
|
||||
err = __intel_wait_for_register_fw(uncore,
|
||||
GEN6_GDRST, hw_domain_mask, 0,
|
||||
500, 0,
|
||||
NULL);
|
||||
/*
|
||||
* Wait for the device to ack the reset requests.
|
||||
*
|
||||
* On some platforms, e.g. Jasperlake, we see that the
|
||||
* engine register state is not cleared until shortly after
|
||||
* GDRST reports completion, causing a failure as we try
|
||||
* to immediately resume while the internal state is still
|
||||
* in flux. If we immediately repeat the reset, the second
|
||||
* reset appears to serialise with the first, and since
|
||||
* it is a no-op, the registers should retain their reset
|
||||
* value. However, there is still a concern that upon
|
||||
* leaving the second reset, the internal engine state
|
||||
* is still in flux and not ready for resuming.
|
||||
*/
|
||||
err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
|
||||
hw_domain_mask, 0,
|
||||
2000, 0,
|
||||
NULL);
|
||||
} while (err == 0 && --loops);
|
||||
if (err)
|
||||
GT_TRACE(gt,
|
||||
"Wait for 0x%08x engines reset failed\n",
|
||||
hw_domain_mask);
|
||||
|
||||
/*
|
||||
* As we have observed that the engine state is still volatile
|
||||
* after GDRST is acked, impose a small delay to let everything settle.
|
||||
*/
|
||||
udelay(50);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -2114,7 +2114,7 @@ int i915_vma_unbind_async(struct i915_vma *vma, bool trylock_vm)
|
||||
if (!obj->mm.rsgt)
|
||||
return -EBUSY;
|
||||
|
||||
err = dma_resv_reserve_fences(obj->base.resv, 1);
|
||||
err = dma_resv_reserve_fences(obj->base.resv, 2);
|
||||
if (err)
|
||||
return -EBUSY;
|
||||
|
||||
|
||||
@@ -29,11 +29,9 @@ enum {
|
||||
ADRENO_FW_MAX,
|
||||
};
|
||||
|
||||
enum adreno_quirks {
|
||||
ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
|
||||
ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
|
||||
ADRENO_QUIRK_LMLOADKILL_DISABLE = 3,
|
||||
};
|
||||
#define ADRENO_QUIRK_TWO_PASS_USE_WFI BIT(0)
|
||||
#define ADRENO_QUIRK_FAULT_DETECT_MASK BIT(1)
|
||||
#define ADRENO_QUIRK_LMLOADKILL_DISABLE BIT(2)
|
||||
|
||||
struct adreno_rev {
|
||||
uint8_t core;
|
||||
@@ -65,7 +63,7 @@ struct adreno_info {
|
||||
const char *name;
|
||||
const char *fw[ADRENO_FW_MAX];
|
||||
uint32_t gmem;
|
||||
enum adreno_quirks quirks;
|
||||
u64 quirks;
|
||||
struct msm_gpu *(*init)(struct drm_device *dev);
|
||||
const char *zapfw;
|
||||
u32 inactive_period;
|
||||
|
||||
@@ -132,7 +132,6 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
|
||||
* dpu_encoder_phys_wb_setup_fb - setup output framebuffer
|
||||
* @phys_enc: Pointer to physical encoder
|
||||
* @fb: Pointer to output framebuffer
|
||||
* @wb_roi: Pointer to output region of interest
|
||||
*/
|
||||
static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
|
||||
struct drm_framebuffer *fb)
|
||||
@@ -692,7 +691,7 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
|
||||
|
||||
/**
|
||||
* dpu_encoder_phys_wb_init - initialize writeback encoder
|
||||
* @init: Pointer to init info structure with initialization params
|
||||
* @p: Pointer to init info structure with initialization params
|
||||
*/
|
||||
struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
|
||||
struct dpu_enc_phys_init_params *p)
|
||||
|
||||
@@ -423,6 +423,10 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux)
|
||||
|
||||
isr = dp_catalog_aux_get_irq(aux->catalog);
|
||||
|
||||
/* no interrupts pending, return immediately */
|
||||
if (!isr)
|
||||
return;
|
||||
|
||||
if (!aux->cmd_busy)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1271,7 +1271,7 @@ void msm_drv_shutdown(struct platform_device *pdev)
|
||||
* msm_drm_init, drm_dev->registered is used as an indicator that the
|
||||
* shutdown will be successful.
|
||||
*/
|
||||
if (drm && drm->registered)
|
||||
if (drm && drm->registered && priv->kms)
|
||||
drm_atomic_helper_shutdown(drm);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,15 +46,17 @@ struct msm_mdss {
|
||||
static int msm_mdss_parse_data_bus_icc_path(struct device *dev,
|
||||
struct msm_mdss *msm_mdss)
|
||||
{
|
||||
struct icc_path *path0 = of_icc_get(dev, "mdp0-mem");
|
||||
struct icc_path *path1 = of_icc_get(dev, "mdp1-mem");
|
||||
struct icc_path *path0;
|
||||
struct icc_path *path1;
|
||||
|
||||
path0 = of_icc_get(dev, "mdp0-mem");
|
||||
if (IS_ERR_OR_NULL(path0))
|
||||
return PTR_ERR_OR_ZERO(path0);
|
||||
|
||||
msm_mdss->path[0] = path0;
|
||||
msm_mdss->num_paths = 1;
|
||||
|
||||
path1 = of_icc_get(dev, "mdp1-mem");
|
||||
if (!IS_ERR_OR_NULL(path1)) {
|
||||
msm_mdss->path[1] = path1;
|
||||
msm_mdss->num_paths++;
|
||||
|
||||
@@ -358,10 +358,18 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
|
||||
drm_gem_object_release(obj);
|
||||
return ret;
|
||||
}
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
|
||||
rc->bo_handle = handle;
|
||||
|
||||
/*
|
||||
* The handle owns the reference now. But we must drop our
|
||||
* remaining reference *after* we no longer need to dereference
|
||||
* the obj. Otherwise userspace could guess the handle and
|
||||
* race closing it from another thread.
|
||||
*/
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -723,11 +731,18 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
|
||||
drm_gem_object_release(obj);
|
||||
return ret;
|
||||
}
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
rc_blob->res_handle = bo->hw_res_handle;
|
||||
rc_blob->bo_handle = handle;
|
||||
|
||||
/*
|
||||
* The handle owns the reference now. But we must drop our
|
||||
* remaining reference *after* we no longer need to dereference
|
||||
* the obj. Otherwise userspace could guess the handle and
|
||||
* race closing it from another thread.
|
||||
*/
|
||||
drm_gem_object_put(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \
|
||||
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
|
||||
vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \
|
||||
vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
|
||||
vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -44,16 +44,20 @@
|
||||
|
||||
#define pr_fmt(fmt) "[TTM] " fmt
|
||||
|
||||
#include "ttm_object.h"
|
||||
#include "vmwgfx_drv.h"
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/module.h>
|
||||
#include "ttm_object.h"
|
||||
#include "vmwgfx_drv.h"
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
MODULE_IMPORT_NS(DMA_BUF);
|
||||
|
||||
#define VMW_TTM_OBJECT_REF_HT_ORDER 10
|
||||
|
||||
/**
|
||||
* struct ttm_object_file
|
||||
*
|
||||
@@ -74,16 +78,14 @@ struct ttm_object_file {
|
||||
struct ttm_object_device *tdev;
|
||||
spinlock_t lock;
|
||||
struct list_head ref_list;
|
||||
struct vmwgfx_open_hash ref_hash;
|
||||
DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER);
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct ttm_object_device
|
||||
*
|
||||
* @object_lock: lock that protects the object_hash hash table.
|
||||
*
|
||||
* @object_hash: hash table for fast lookup of object global names.
|
||||
* @object_lock: lock that protects idr.
|
||||
*
|
||||
* @object_count: Per device object count.
|
||||
*
|
||||
@@ -92,7 +94,6 @@ struct ttm_object_file {
|
||||
|
||||
struct ttm_object_device {
|
||||
spinlock_t object_lock;
|
||||
struct vmwgfx_open_hash object_hash;
|
||||
atomic_t object_count;
|
||||
struct dma_buf_ops ops;
|
||||
void (*dmabuf_release)(struct dma_buf *dma_buf);
|
||||
@@ -138,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile)
|
||||
return tfile;
|
||||
}
|
||||
|
||||
static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile,
|
||||
uint64_t key,
|
||||
struct vmwgfx_hash_item **p_hash)
|
||||
{
|
||||
struct vmwgfx_hash_item *hash;
|
||||
|
||||
hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) {
|
||||
if (hash->key == key) {
|
||||
*p_hash = hash;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ttm_tfile_find_ref(struct ttm_object_file *tfile,
|
||||
uint64_t key,
|
||||
struct vmwgfx_hash_item **p_hash)
|
||||
{
|
||||
struct vmwgfx_hash_item *hash;
|
||||
|
||||
hash_for_each_possible(tfile->ref_hash, hash, head, key) {
|
||||
if (hash->key == key) {
|
||||
*p_hash = hash;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ttm_object_file_destroy(struct kref *kref)
|
||||
{
|
||||
struct ttm_object_file *tfile =
|
||||
@@ -223,64 +254,29 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
|
||||
kref_put(&base->refcount, ttm_release_base);
|
||||
}
|
||||
|
||||
/**
|
||||
* ttm_base_object_noref_lookup - look up a base object without reference
|
||||
* @tfile: The struct ttm_object_file the object is registered with.
|
||||
* @key: The object handle.
|
||||
*
|
||||
* This function looks up a ttm base object and returns a pointer to it
|
||||
* without refcounting the pointer. The returned pointer is only valid
|
||||
* until ttm_base_object_noref_release() is called, and the object
|
||||
* pointed to by the returned pointer may be doomed. Any persistent usage
|
||||
* of the object requires a refcount to be taken using kref_get_unless_zero().
|
||||
* Iff this function returns successfully it needs to be paired with
|
||||
* ttm_base_object_noref_release() and no sleeping- or scheduling functions
|
||||
* may be called inbetween these function callse.
|
||||
*
|
||||
* Return: A pointer to the object if successful or NULL otherwise.
|
||||
*/
|
||||
struct ttm_base_object *
|
||||
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
|
||||
{
|
||||
struct vmwgfx_hash_item *hash;
|
||||
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
|
||||
if (ret) {
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__release(RCU);
|
||||
return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
|
||||
}
|
||||
EXPORT_SYMBOL(ttm_base_object_noref_lookup);
|
||||
|
||||
struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
|
||||
uint32_t key)
|
||||
uint64_t key)
|
||||
{
|
||||
struct ttm_base_object *base = NULL;
|
||||
struct vmwgfx_hash_item *hash;
|
||||
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
ret = vmwgfx_ht_find_item_rcu(ht, key, &hash);
|
||||
spin_lock(&tfile->lock);
|
||||
ret = ttm_tfile_find_ref(tfile, key, &hash);
|
||||
|
||||
if (likely(ret == 0)) {
|
||||
base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
|
||||
base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
|
||||
if (!kref_get_unless_zero(&base->refcount))
|
||||
base = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
spin_unlock(&tfile->lock);
|
||||
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
struct ttm_base_object *
|
||||
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
|
||||
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key)
|
||||
{
|
||||
struct ttm_base_object *base;
|
||||
|
||||
@@ -299,7 +295,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
|
||||
bool *existed,
|
||||
bool require_existed)
|
||||
{
|
||||
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
|
||||
struct ttm_ref_object *ref;
|
||||
struct vmwgfx_hash_item *hash;
|
||||
int ret = -EINVAL;
|
||||
@@ -312,10 +307,10 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
|
||||
|
||||
while (ret == -EINVAL) {
|
||||
rcu_read_lock();
|
||||
ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash);
|
||||
ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash);
|
||||
|
||||
if (ret == 0) {
|
||||
ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
|
||||
ref = hlist_entry(hash, struct ttm_ref_object, hash);
|
||||
if (kref_get_unless_zero(&ref->kref)) {
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
@@ -337,21 +332,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
|
||||
kref_init(&ref->kref);
|
||||
|
||||
spin_lock(&tfile->lock);
|
||||
ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash);
|
||||
|
||||
if (likely(ret == 0)) {
|
||||
list_add_tail(&ref->head, &tfile->ref_list);
|
||||
kref_get(&base->refcount);
|
||||
spin_unlock(&tfile->lock);
|
||||
if (existed != NULL)
|
||||
*existed = false;
|
||||
break;
|
||||
}
|
||||
hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key);
|
||||
ret = 0;
|
||||
|
||||
list_add_tail(&ref->head, &tfile->ref_list);
|
||||
kref_get(&base->refcount);
|
||||
spin_unlock(&tfile->lock);
|
||||
BUG_ON(ret != -EINVAL);
|
||||
|
||||
kfree(ref);
|
||||
if (existed != NULL)
|
||||
*existed = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -363,10 +351,8 @@ ttm_ref_object_release(struct kref *kref)
|
||||
struct ttm_ref_object *ref =
|
||||
container_of(kref, struct ttm_ref_object, kref);
|
||||
struct ttm_object_file *tfile = ref->tfile;
|
||||
struct vmwgfx_open_hash *ht;
|
||||
|
||||
ht = &tfile->ref_hash;
|
||||
(void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
|
||||
hash_del_rcu(&ref->hash.head);
|
||||
list_del(&ref->head);
|
||||
spin_unlock(&tfile->lock);
|
||||
|
||||
@@ -378,18 +364,17 @@ ttm_ref_object_release(struct kref *kref)
|
||||
int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
|
||||
unsigned long key)
|
||||
{
|
||||
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
|
||||
struct ttm_ref_object *ref;
|
||||
struct vmwgfx_hash_item *hash;
|
||||
int ret;
|
||||
|
||||
spin_lock(&tfile->lock);
|
||||
ret = vmwgfx_ht_find_item(ht, key, &hash);
|
||||
ret = ttm_tfile_find_ref(tfile, key, &hash);
|
||||
if (unlikely(ret != 0)) {
|
||||
spin_unlock(&tfile->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
|
||||
ref = hlist_entry(hash, struct ttm_ref_object, hash);
|
||||
kref_put(&ref->kref, ttm_ref_object_release);
|
||||
spin_unlock(&tfile->lock);
|
||||
return 0;
|
||||
@@ -416,16 +401,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
|
||||
}
|
||||
|
||||
spin_unlock(&tfile->lock);
|
||||
vmwgfx_ht_remove(&tfile->ref_hash);
|
||||
|
||||
ttm_object_file_unref(&tfile);
|
||||
}
|
||||
|
||||
struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
|
||||
unsigned int hash_order)
|
||||
struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev)
|
||||
{
|
||||
struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (unlikely(tfile == NULL))
|
||||
return NULL;
|
||||
@@ -435,34 +417,21 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
|
||||
kref_init(&tfile->refcount);
|
||||
INIT_LIST_HEAD(&tfile->ref_list);
|
||||
|
||||
ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
hash_init(tfile->ref_hash);
|
||||
|
||||
return tfile;
|
||||
out_err:
|
||||
vmwgfx_ht_remove(&tfile->ref_hash);
|
||||
|
||||
kfree(tfile);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ttm_object_device *
|
||||
ttm_object_device_init(unsigned int hash_order,
|
||||
const struct dma_buf_ops *ops)
|
||||
ttm_object_device_init(const struct dma_buf_ops *ops)
|
||||
{
|
||||
struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (unlikely(tdev == NULL))
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&tdev->object_lock);
|
||||
atomic_set(&tdev->object_count, 0);
|
||||
ret = vmwgfx_ht_create(&tdev->object_hash, hash_order);
|
||||
if (ret != 0)
|
||||
goto out_no_object_hash;
|
||||
|
||||
/*
|
||||
* Our base is at VMWGFX_NUM_MOB + 1 because we want to create
|
||||
@@ -477,10 +446,6 @@ ttm_object_device_init(unsigned int hash_order,
|
||||
tdev->dmabuf_release = tdev->ops.release;
|
||||
tdev->ops.release = ttm_prime_dmabuf_release;
|
||||
return tdev;
|
||||
|
||||
out_no_object_hash:
|
||||
kfree(tdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ttm_object_device_release(struct ttm_object_device **p_tdev)
|
||||
@@ -491,7 +456,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev)
|
||||
|
||||
WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
|
||||
idr_destroy(&tdev->idr);
|
||||
vmwgfx_ht_remove(&tdev->object_hash);
|
||||
|
||||
kfree(tdev);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -42,8 +42,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include "vmwgfx_hashtab.h"
|
||||
|
||||
/**
|
||||
* enum ttm_object_type
|
||||
*
|
||||
@@ -104,7 +102,7 @@ struct ttm_base_object {
|
||||
struct ttm_object_file *tfile;
|
||||
struct kref refcount;
|
||||
void (*refcount_release) (struct ttm_base_object **base);
|
||||
u32 handle;
|
||||
u64 handle;
|
||||
enum ttm_object_type object_type;
|
||||
u32 shareable;
|
||||
};
|
||||
@@ -164,7 +162,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
|
||||
*/
|
||||
|
||||
extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
|
||||
*tfile, uint32_t key);
|
||||
*tfile, uint64_t key);
|
||||
|
||||
/**
|
||||
* ttm_base_object_lookup_for_ref
|
||||
@@ -178,7 +176,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
|
||||
*/
|
||||
|
||||
extern struct ttm_base_object *
|
||||
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key);
|
||||
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key);
|
||||
|
||||
/**
|
||||
* ttm_base_object_unref
|
||||
@@ -237,14 +235,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
|
||||
* ttm_object_file_init - initialize a struct ttm_object file
|
||||
*
|
||||
* @tdev: A struct ttm_object device this file is initialized on.
|
||||
* @hash_order: Order of the hash table used to hold the reference objects.
|
||||
*
|
||||
* This is typically called by the file_ops::open function.
|
||||
*/
|
||||
|
||||
extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device
|
||||
*tdev,
|
||||
unsigned int hash_order);
|
||||
*tdev);
|
||||
|
||||
/**
|
||||
* ttm_object_file_release - release data held by a ttm_object_file
|
||||
@@ -262,7 +258,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
|
||||
/**
|
||||
* ttm_object device init - initialize a struct ttm_object_device
|
||||
*
|
||||
* @hash_order: Order of hash table used to hash the base objects.
|
||||
* @ops: DMA buf ops for prime objects of this device.
|
||||
*
|
||||
* This function is typically called on device initialization to prepare
|
||||
@@ -270,8 +265,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
|
||||
*/
|
||||
|
||||
extern struct ttm_object_device *
|
||||
ttm_object_device_init(unsigned int hash_order,
|
||||
const struct dma_buf_ops *ops);
|
||||
ttm_object_device_init(const struct dma_buf_ops *ops);
|
||||
|
||||
/**
|
||||
* ttm_object_device_release - release data held by a ttm_object_device
|
||||
@@ -313,18 +307,4 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
|
||||
#define ttm_prime_object_kfree(__obj, __prime) \
|
||||
kfree_rcu(__obj, __prime.base.rhead)
|
||||
|
||||
struct ttm_base_object *
|
||||
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key);
|
||||
|
||||
/**
|
||||
* ttm_base_object_noref_release - release a base object pointer looked up
|
||||
* without reference
|
||||
*
|
||||
* Releases a base object pointer looked up with ttm_base_object_noref_lookup().
|
||||
*/
|
||||
static inline void ttm_base_object_noref_release(void)
|
||||
{
|
||||
__acquire(RCU);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -715,44 +715,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference
|
||||
* @filp: The TTM object file the handle is registered with.
|
||||
* @handle: The user buffer object handle.
|
||||
*
|
||||
* This function looks up a struct vmw_bo and returns a pointer to the
|
||||
* struct vmw_buffer_object it derives from without refcounting the pointer.
|
||||
* The returned pointer is only valid until vmw_user_bo_noref_release() is
|
||||
* called, and the object pointed to by the returned pointer may be doomed.
|
||||
* Any persistent usage of the object requires a refcount to be taken using
|
||||
* ttm_bo_reference_unless_doomed(). Iff this function returns successfully it
|
||||
* needs to be paired with vmw_user_bo_noref_release() and no sleeping-
|
||||
* or scheduling functions may be called in between these function calls.
|
||||
*
|
||||
* Return: A struct vmw_buffer_object pointer if successful or negative
|
||||
* error pointer on failure.
|
||||
*/
|
||||
struct vmw_buffer_object *
|
||||
vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle)
|
||||
{
|
||||
struct vmw_buffer_object *vmw_bo;
|
||||
struct ttm_buffer_object *bo;
|
||||
struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle);
|
||||
|
||||
if (!gobj) {
|
||||
DRM_ERROR("Invalid buffer object handle 0x%08lx.\n",
|
||||
(unsigned long)handle);
|
||||
return ERR_PTR(-ESRCH);
|
||||
}
|
||||
vmw_bo = gem_to_vmw_bo(gobj);
|
||||
bo = ttm_bo_get_unless_zero(&vmw_bo->base);
|
||||
vmw_bo = vmw_buffer_object(bo);
|
||||
drm_gem_object_put(gobj);
|
||||
|
||||
return vmw_bo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_bo_fence_single - Utility function to fence a single TTM buffer
|
||||
* object without unreserving it.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "vmwgfx_drv.h"
|
||||
#include "vmwgfx_resource_priv.h"
|
||||
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#define VMW_CMDBUF_RES_MAN_HT_ORDER 12
|
||||
|
||||
/**
|
||||
@@ -59,7 +61,7 @@ struct vmw_cmdbuf_res {
|
||||
* @resources and @list are protected by the cmdbuf mutex for now.
|
||||
*/
|
||||
struct vmw_cmdbuf_res_manager {
|
||||
struct vmwgfx_open_hash resources;
|
||||
DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
|
||||
struct list_head list;
|
||||
struct vmw_private *dev_priv;
|
||||
};
|
||||
@@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
|
||||
u32 user_key)
|
||||
{
|
||||
struct vmwgfx_hash_item *hash;
|
||||
int ret;
|
||||
unsigned long key = user_key | (res_type << 24);
|
||||
|
||||
ret = vmwgfx_ht_find_item(&man->resources, key, &hash);
|
||||
if (unlikely(ret != 0))
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res;
|
||||
hash_for_each_possible_rcu(man->resources, hash, head, key) {
|
||||
if (hash->key == key)
|
||||
return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res;
|
||||
}
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
|
||||
struct vmw_cmdbuf_res *entry)
|
||||
{
|
||||
list_del(&entry->head);
|
||||
WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash));
|
||||
hash_del_rcu(&entry->hash.head);
|
||||
vmw_resource_unreference(&entry->res);
|
||||
kfree(entry);
|
||||
}
|
||||
@@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list)
|
||||
void vmw_cmdbuf_res_revert(struct list_head *list)
|
||||
{
|
||||
struct vmw_cmdbuf_res *entry, *next;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry_safe(entry, next, list, head) {
|
||||
switch (entry->state) {
|
||||
@@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list)
|
||||
vmw_cmdbuf_res_free(entry->man, entry);
|
||||
break;
|
||||
case VMW_CMDBUF_RES_DEL:
|
||||
ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash);
|
||||
BUG_ON(ret);
|
||||
hash_add_rcu(entry->man->resources, &entry->hash.head,
|
||||
entry->hash.key);
|
||||
list_move_tail(&entry->head, &entry->man->list);
|
||||
entry->state = VMW_CMDBUF_RES_COMMITTED;
|
||||
break;
|
||||
@@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
|
||||
struct list_head *list)
|
||||
{
|
||||
struct vmw_cmdbuf_res *cres;
|
||||
int ret;
|
||||
|
||||
cres = kzalloc(sizeof(*cres), GFP_KERNEL);
|
||||
if (unlikely(!cres))
|
||||
return -ENOMEM;
|
||||
|
||||
cres->hash.key = user_key | (res_type << 24);
|
||||
ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash);
|
||||
if (unlikely(ret != 0)) {
|
||||
kfree(cres);
|
||||
goto out_invalid_key;
|
||||
}
|
||||
hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key);
|
||||
|
||||
cres->state = VMW_CMDBUF_RES_ADD;
|
||||
cres->res = vmw_resource_reference(res);
|
||||
cres->man = man;
|
||||
list_add_tail(&cres->head, list);
|
||||
|
||||
out_invalid_key:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
|
||||
struct list_head *list,
|
||||
struct vmw_resource **res_p)
|
||||
{
|
||||
struct vmw_cmdbuf_res *entry;
|
||||
struct vmw_cmdbuf_res *entry = NULL;
|
||||
struct vmwgfx_hash_item *hash;
|
||||
int ret;
|
||||
unsigned long key = user_key | (res_type << 24);
|
||||
|
||||
ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24),
|
||||
&hash);
|
||||
if (likely(ret != 0))
|
||||
hash_for_each_possible_rcu(man->resources, hash, head, key) {
|
||||
if (hash->key == key) {
|
||||
entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unlikely(!entry))
|
||||
return -EINVAL;
|
||||
|
||||
entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
|
||||
|
||||
switch (entry->state) {
|
||||
case VMW_CMDBUF_RES_ADD:
|
||||
vmw_cmdbuf_res_free(man, entry);
|
||||
*res_p = NULL;
|
||||
break;
|
||||
case VMW_CMDBUF_RES_COMMITTED:
|
||||
(void) vmwgfx_ht_remove_item(&man->resources, &entry->hash);
|
||||
hash_del_rcu(&entry->hash.head);
|
||||
list_del(&entry->head);
|
||||
entry->state = VMW_CMDBUF_RES_DEL;
|
||||
list_add_tail(&entry->head, list);
|
||||
@@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager *
|
||||
vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
|
||||
{
|
||||
struct vmw_cmdbuf_res_manager *man;
|
||||
int ret;
|
||||
|
||||
man = kzalloc(sizeof(*man), GFP_KERNEL);
|
||||
if (!man)
|
||||
@@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
|
||||
|
||||
man->dev_priv = dev_priv;
|
||||
INIT_LIST_HEAD(&man->list);
|
||||
ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
|
||||
if (ret == 0)
|
||||
return man;
|
||||
|
||||
kfree(man);
|
||||
return ERR_PTR(ret);
|
||||
hash_init(man->resources);
|
||||
return man;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
|
||||
list_for_each_entry_safe(entry, next, &man->list, head)
|
||||
vmw_cmdbuf_res_free(man, entry);
|
||||
|
||||
vmwgfx_ht_remove(&man->resources);
|
||||
kfree(man);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,13 @@
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/cc_platform.h>
|
||||
|
||||
#include "vmwgfx_drv.h"
|
||||
|
||||
#include "vmwgfx_devcaps.h"
|
||||
#include "vmwgfx_mksstat.h"
|
||||
#include "vmwgfx_binding.h"
|
||||
#include "ttm_object.h"
|
||||
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_drv.h>
|
||||
@@ -41,11 +44,11 @@
|
||||
#include <drm/ttm/ttm_placement.h>
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
#include "ttm_object.h"
|
||||
#include "vmwgfx_binding.h"
|
||||
#include "vmwgfx_devcaps.h"
|
||||
#include "vmwgfx_drv.h"
|
||||
#include "vmwgfx_mksstat.h"
|
||||
#include <linux/cc_platform.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
|
||||
|
||||
@@ -806,6 +809,43 @@ static int vmw_detect_version(struct vmw_private *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmw_write_driver_id(struct vmw_private *dev)
|
||||
{
|
||||
if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) {
|
||||
vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
|
||||
SVGA_REG_GUEST_DRIVER_ID_LINUX);
|
||||
|
||||
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1,
|
||||
LINUX_VERSION_MAJOR << 24 |
|
||||
LINUX_VERSION_PATCHLEVEL << 16 |
|
||||
LINUX_VERSION_SUBLEVEL);
|
||||
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2,
|
||||
VMWGFX_DRIVER_MAJOR << 24 |
|
||||
VMWGFX_DRIVER_MINOR << 16 |
|
||||
VMWGFX_DRIVER_PATCHLEVEL);
|
||||
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0);
|
||||
|
||||
vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
|
||||
SVGA_REG_GUEST_DRIVER_ID_SUBMIT);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmw_sw_context_init(struct vmw_private *dev_priv)
|
||||
{
|
||||
struct vmw_sw_context *sw_context = &dev_priv->ctx;
|
||||
|
||||
hash_init(sw_context->res_ht);
|
||||
}
|
||||
|
||||
static void vmw_sw_context_fini(struct vmw_private *dev_priv)
|
||||
{
|
||||
struct vmw_sw_context *sw_context = &dev_priv->ctx;
|
||||
|
||||
vfree(sw_context->cmd_bounce);
|
||||
if (sw_context->staged_bindings)
|
||||
vmw_binding_state_free(sw_context->staged_bindings);
|
||||
}
|
||||
|
||||
static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
|
||||
{
|
||||
int ret;
|
||||
@@ -815,6 +855,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
|
||||
|
||||
dev_priv->drm.dev_private = dev_priv;
|
||||
|
||||
vmw_sw_context_init(dev_priv);
|
||||
|
||||
mutex_init(&dev_priv->cmdbuf_mutex);
|
||||
mutex_init(&dev_priv->binding_mutex);
|
||||
spin_lock_init(&dev_priv->resource_lock);
|
||||
@@ -970,7 +1012,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
|
||||
goto out_err0;
|
||||
}
|
||||
|
||||
dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops);
|
||||
dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops);
|
||||
|
||||
if (unlikely(dev_priv->tdev == NULL)) {
|
||||
drm_err(&dev_priv->drm,
|
||||
@@ -1091,6 +1133,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
|
||||
vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)",
|
||||
VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
|
||||
VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE);
|
||||
vmw_write_driver_id(dev_priv);
|
||||
|
||||
if (dev_priv->enable_fb) {
|
||||
vmw_fifo_resource_inc(dev_priv);
|
||||
@@ -1143,9 +1186,7 @@ static void vmw_driver_unload(struct drm_device *dev)
|
||||
|
||||
unregister_pm_notifier(&dev_priv->pm_nb);
|
||||
|
||||
if (dev_priv->ctx.res_ht_initialized)
|
||||
vmwgfx_ht_remove(&dev_priv->ctx.res_ht);
|
||||
vfree(dev_priv->ctx.cmd_bounce);
|
||||
vmw_sw_context_fini(dev_priv);
|
||||
if (dev_priv->enable_fb) {
|
||||
vmw_fb_off(dev_priv);
|
||||
vmw_fb_close(dev_priv);
|
||||
@@ -1173,8 +1214,6 @@ static void vmw_driver_unload(struct drm_device *dev)
|
||||
vmw_irq_uninstall(&dev_priv->drm);
|
||||
|
||||
ttm_object_device_release(&dev_priv->tdev);
|
||||
if (dev_priv->ctx.staged_bindings)
|
||||
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
|
||||
|
||||
for (i = vmw_res_context; i < vmw_res_max; ++i)
|
||||
idr_destroy(&dev_priv->res_idr[i]);
|
||||
@@ -1203,7 +1242,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
|
||||
if (unlikely(!vmw_fp))
|
||||
return ret;
|
||||
|
||||
vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10);
|
||||
vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev);
|
||||
if (unlikely(vmw_fp->tfile == NULL))
|
||||
goto out_no_tfile;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#include <drm/drm_auth.h>
|
||||
#include <drm/drm_device.h>
|
||||
@@ -42,7 +43,6 @@
|
||||
#include "ttm_object.h"
|
||||
|
||||
#include "vmwgfx_fence.h"
|
||||
#include "vmwgfx_hashtab.h"
|
||||
#include "vmwgfx_reg.h"
|
||||
#include "vmwgfx_validation.h"
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
#define VMW_RES_STREAM ttm_driver_type2
|
||||
#define VMW_RES_FENCE ttm_driver_type3
|
||||
#define VMW_RES_SHADER ttm_driver_type4
|
||||
#define VMW_RES_HT_ORDER 12
|
||||
|
||||
#define MKSSTAT_CAPACITY_LOG2 5U
|
||||
#define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)
|
||||
@@ -102,6 +103,11 @@ struct vmw_fpriv {
|
||||
bool gb_aware; /* user-space is guest-backed aware */
|
||||
};
|
||||
|
||||
struct vmwgfx_hash_item {
|
||||
struct hlist_node head;
|
||||
unsigned long key;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vmw_buffer_object - TTM buffer object with vmwgfx additions
|
||||
* @base: The TTM buffer object
|
||||
@@ -425,8 +431,7 @@ struct vmw_ctx_validation_info;
|
||||
* @ctx: The validation context
|
||||
*/
|
||||
struct vmw_sw_context{
|
||||
struct vmwgfx_open_hash res_ht;
|
||||
bool res_ht_initialized;
|
||||
DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER);
|
||||
bool kernel;
|
||||
struct vmw_fpriv *fp;
|
||||
struct drm_file *filp;
|
||||
@@ -821,12 +826,7 @@ extern int vmw_user_resource_lookup_handle(
|
||||
uint32_t handle,
|
||||
const struct vmw_user_resource_conv *converter,
|
||||
struct vmw_resource **p_res);
|
||||
extern struct vmw_resource *
|
||||
vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
|
||||
struct ttm_object_file *tfile,
|
||||
uint32_t handle,
|
||||
const struct vmw_user_resource_conv *
|
||||
converter);
|
||||
|
||||
extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
|
||||
@@ -865,15 +865,6 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
|
||||
return !RB_EMPTY_NODE(&res->mob_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_user_resource_noref_release - release a user resource pointer looked up
|
||||
* without reference
|
||||
*/
|
||||
static inline void vmw_user_resource_noref_release(void)
|
||||
{
|
||||
ttm_base_object_noref_release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer object helper functions - vmwgfx_bo.c
|
||||
*/
|
||||
@@ -925,8 +916,6 @@ extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
|
||||
extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
|
||||
struct ttm_resource *mem);
|
||||
extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
|
||||
extern struct vmw_buffer_object *
|
||||
vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle);
|
||||
|
||||
/**
|
||||
* vmw_bo_adjust_prio - Adjust the buffer object eviction priority
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
@@ -25,6 +25,7 @@
|
||||
*
|
||||
**************************************************************************/
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/hashtable.h>
|
||||
|
||||
#include "vmwgfx_drv.h"
|
||||
#include "vmwgfx_reg.h"
|
||||
@@ -34,7 +35,6 @@
|
||||
#include "vmwgfx_binding.h"
|
||||
#include "vmwgfx_mksstat.h"
|
||||
|
||||
#define VMW_RES_HT_ORDER 12
|
||||
|
||||
/*
|
||||
* Helper macro to get dx_ctx_node if available otherwise print an error
|
||||
@@ -290,20 +290,26 @@ static void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache,
|
||||
rcache->valid_handle = 0;
|
||||
}
|
||||
|
||||
enum vmw_val_add_flags {
|
||||
vmw_val_add_flag_none = 0,
|
||||
vmw_val_add_flag_noctx = 1 << 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* vmw_execbuf_res_noref_val_add - Add a resource described by an unreferenced
|
||||
* rcu-protected pointer to the validation list.
|
||||
* vmw_execbuf_res_val_add - Add a resource to the validation list.
|
||||
*
|
||||
* @sw_context: Pointer to the software context.
|
||||
* @res: Unreferenced rcu-protected pointer to the resource.
|
||||
* @dirty: Whether to change dirty status.
|
||||
* @flags: specifies whether to use the context or not
|
||||
*
|
||||
* Returns: 0 on success. Negative error code on failure. Typical error codes
|
||||
* are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed.
|
||||
*/
|
||||
static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
|
||||
struct vmw_resource *res,
|
||||
u32 dirty)
|
||||
static int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context,
|
||||
struct vmw_resource *res,
|
||||
u32 dirty,
|
||||
u32 flags)
|
||||
{
|
||||
struct vmw_private *dev_priv = res->dev_priv;
|
||||
int ret;
|
||||
@@ -318,24 +324,30 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
|
||||
if (dirty)
|
||||
vmw_validation_res_set_dirty(sw_context->ctx,
|
||||
rcache->private, dirty);
|
||||
vmw_user_resource_noref_release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv_size = vmw_execbuf_res_size(dev_priv, res_type);
|
||||
ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
|
||||
dirty, (void **)&ctx_info,
|
||||
&first_usage);
|
||||
vmw_user_resource_noref_release();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv_size && first_usage) {
|
||||
ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
|
||||
ctx_info);
|
||||
if (ret) {
|
||||
VMW_DEBUG_USER("Failed first usage context setup.\n");
|
||||
if ((flags & vmw_val_add_flag_noctx) != 0) {
|
||||
ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
|
||||
(void **)&ctx_info, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
priv_size = vmw_execbuf_res_size(dev_priv, res_type);
|
||||
ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
|
||||
dirty, (void **)&ctx_info,
|
||||
&first_usage);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv_size && first_usage) {
|
||||
ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
|
||||
ctx_info);
|
||||
if (ret) {
|
||||
VMW_DEBUG_USER("Failed first usage context setup.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,43 +355,6 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_execbuf_res_noctx_val_add - Add a non-context resource to the resource
|
||||
* validation list if it's not already on it
|
||||
*
|
||||
* @sw_context: Pointer to the software context.
|
||||
* @res: Pointer to the resource.
|
||||
* @dirty: Whether to change dirty status.
|
||||
*
|
||||
* Returns: Zero on success. Negative error code on failure.
|
||||
*/
|
||||
static int vmw_execbuf_res_noctx_val_add(struct vmw_sw_context *sw_context,
|
||||
struct vmw_resource *res,
|
||||
u32 dirty)
|
||||
{
|
||||
struct vmw_res_cache_entry *rcache;
|
||||
enum vmw_res_type res_type = vmw_res_type(res);
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
rcache = &sw_context->res_cache[res_type];
|
||||
if (likely(rcache->valid && rcache->res == res)) {
|
||||
if (dirty)
|
||||
vmw_validation_res_set_dirty(sw_context->ctx,
|
||||
rcache->private, dirty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
|
||||
&ptr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vmw_execbuf_rcache_update(rcache, res, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_view_res_val_add - Add a view and the surface it's pointing to to the
|
||||
* validation list
|
||||
@@ -398,13 +373,13 @@ static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
|
||||
* First add the resource the view is pointing to, otherwise it may be
|
||||
* swapped out when the view is validated.
|
||||
*/
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, vmw_view_srf(view),
|
||||
vmw_view_dirtying(view));
|
||||
ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view),
|
||||
vmw_view_dirtying(view), vmw_val_add_flag_noctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return vmw_execbuf_res_noctx_val_add(sw_context, view,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,8 +450,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
|
||||
if (IS_ERR(res))
|
||||
continue;
|
||||
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_SET);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_SET,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
}
|
||||
@@ -490,9 +466,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
|
||||
if (vmw_res_type(entry->res) == vmw_res_view)
|
||||
ret = vmw_view_res_val_add(sw_context, entry->res);
|
||||
else
|
||||
ret = vmw_execbuf_res_noctx_val_add
|
||||
(sw_context, entry->res,
|
||||
vmw_binding_dirtying(entry->bt));
|
||||
ret = vmw_execbuf_res_val_add(sw_context, entry->res,
|
||||
vmw_binding_dirtying(entry->bt),
|
||||
vmw_val_add_flag_noctx);
|
||||
if (unlikely(ret != 0))
|
||||
break;
|
||||
}
|
||||
@@ -658,7 +634,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
|
||||
{
|
||||
struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type];
|
||||
struct vmw_resource *res;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
bool needs_unref = false;
|
||||
|
||||
if (p_res)
|
||||
*p_res = NULL;
|
||||
@@ -683,17 +660,18 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = vmw_user_resource_noref_lookup_handle
|
||||
(dev_priv, sw_context->fp->tfile, *id_loc, converter);
|
||||
if (IS_ERR(res)) {
|
||||
ret = vmw_user_resource_lookup_handle
|
||||
(dev_priv, sw_context->fp->tfile, *id_loc, converter, &res);
|
||||
if (ret != 0) {
|
||||
VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n",
|
||||
(unsigned int) *id_loc);
|
||||
return PTR_ERR(res);
|
||||
}
|
||||
|
||||
ret = vmw_execbuf_res_noref_val_add(sw_context, res, dirty);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
}
|
||||
needs_unref = true;
|
||||
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none);
|
||||
if (unlikely(ret != 0))
|
||||
goto res_check_done;
|
||||
|
||||
if (rcache->valid && rcache->res == res) {
|
||||
rcache->valid_handle = true;
|
||||
@@ -708,7 +686,11 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
|
||||
if (p_res)
|
||||
*p_res = res;
|
||||
|
||||
return 0;
|
||||
res_check_done:
|
||||
if (needs_unref)
|
||||
vmw_resource_unreference(&res);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1171,9 +1153,9 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
|
||||
int ret;
|
||||
|
||||
vmw_validation_preload_bo(sw_context->ctx);
|
||||
vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
|
||||
if (IS_ERR(vmw_bo)) {
|
||||
VMW_DEBUG_USER("Could not find or use MOB buffer.\n");
|
||||
ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
|
||||
if (ret != 0) {
|
||||
drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
|
||||
return PTR_ERR(vmw_bo);
|
||||
}
|
||||
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false);
|
||||
@@ -1225,9 +1207,9 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
|
||||
int ret;
|
||||
|
||||
vmw_validation_preload_bo(sw_context->ctx);
|
||||
vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
|
||||
if (IS_ERR(vmw_bo)) {
|
||||
VMW_DEBUG_USER("Could not find or use GMR region.\n");
|
||||
ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
|
||||
if (ret != 0) {
|
||||
drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
|
||||
return PTR_ERR(vmw_bo);
|
||||
}
|
||||
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false);
|
||||
@@ -2025,8 +2007,9 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
|
||||
res = vmw_shader_lookup(vmw_context_res_man(ctx),
|
||||
cmd->body.shid, cmd->body.type);
|
||||
if (!IS_ERR(res)) {
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
|
||||
@@ -2273,8 +2256,9 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
|
||||
return PTR_ERR(res);
|
||||
}
|
||||
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -2777,8 +2761,8 @@ static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
|
||||
return PTR_ERR(res);
|
||||
}
|
||||
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (ret) {
|
||||
VMW_DEBUG_USER("Error creating resource validation node.\n");
|
||||
return ret;
|
||||
@@ -3098,8 +3082,8 @@ static int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv,
|
||||
|
||||
vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes);
|
||||
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (ret) {
|
||||
DRM_ERROR("Error creating resource validation node.\n");
|
||||
return ret;
|
||||
@@ -3148,8 +3132,8 @@ static int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
|
||||
VMW_RES_DIRTY_NONE);
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
|
||||
vmw_val_add_flag_noctx);
|
||||
if (ret) {
|
||||
DRM_ERROR("Error creating resource validation node.\n");
|
||||
return ret;
|
||||
@@ -4067,22 +4051,26 @@ static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = vmw_user_resource_noref_lookup_handle
|
||||
ret = vmw_user_resource_lookup_handle
|
||||
(dev_priv, sw_context->fp->tfile, handle,
|
||||
user_context_converter);
|
||||
if (IS_ERR(res)) {
|
||||
user_context_converter, &res);
|
||||
if (ret != 0) {
|
||||
VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n",
|
||||
(unsigned int) handle);
|
||||
return PTR_ERR(res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = vmw_execbuf_res_noref_val_add(sw_context, res, VMW_RES_DIRTY_SET);
|
||||
if (unlikely(ret != 0))
|
||||
ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET,
|
||||
vmw_val_add_flag_none);
|
||||
if (unlikely(ret != 0)) {
|
||||
vmw_resource_unreference(&res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res);
|
||||
sw_context->man = vmw_context_res_man(res);
|
||||
|
||||
vmw_resource_unreference(&res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4101,7 +4089,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
|
||||
int ret;
|
||||
int32_t out_fence_fd = -1;
|
||||
struct sync_file *sync_file = NULL;
|
||||
DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1);
|
||||
DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
|
||||
|
||||
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
|
||||
out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
@@ -4164,14 +4152,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
|
||||
if (sw_context->staged_bindings)
|
||||
vmw_binding_state_reset(sw_context->staged_bindings);
|
||||
|
||||
if (!sw_context->res_ht_initialized) {
|
||||
ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
|
||||
if (unlikely(ret != 0))
|
||||
goto out_unlock;
|
||||
|
||||
sw_context->res_ht_initialized = true;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&sw_context->staged_cmd_res);
|
||||
sw_context->ctx = &val_ctx;
|
||||
ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "vmwgfx_hashtab.h"
|
||||
|
||||
int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order)
|
||||
{
|
||||
unsigned int size = 1 << order;
|
||||
|
||||
ht->order = order;
|
||||
ht->table = NULL;
|
||||
if (size <= PAGE_SIZE / sizeof(*ht->table))
|
||||
ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
|
||||
else
|
||||
ht->table = vzalloc(array_size(size, sizeof(*ht->table)));
|
||||
if (!ht->table) {
|
||||
DRM_ERROR("Out of memory for hash table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct vmwgfx_hash_item *entry;
|
||||
struct hlist_head *h_list;
|
||||
unsigned int hashed_key;
|
||||
int count = 0;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each_entry(entry, h_list, head)
|
||||
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
|
||||
}
|
||||
|
||||
static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct vmwgfx_hash_item *entry;
|
||||
struct hlist_head *h_list;
|
||||
unsigned int hashed_key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each_entry(entry, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return &entry->head;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct vmwgfx_hash_item *entry;
|
||||
struct hlist_head *h_list;
|
||||
unsigned int hashed_key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each_entry_rcu(entry, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return &entry->head;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
|
||||
{
|
||||
struct vmwgfx_hash_item *entry;
|
||||
struct hlist_head *h_list;
|
||||
struct hlist_node *parent;
|
||||
unsigned int hashed_key;
|
||||
unsigned long key = item->key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
parent = NULL;
|
||||
hlist_for_each_entry(entry, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return -EINVAL;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
parent = &entry->head;
|
||||
}
|
||||
if (parent)
|
||||
hlist_add_behind_rcu(&item->head, parent);
|
||||
else
|
||||
hlist_add_head_rcu(&item->head, h_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just insert an item and return any "bits" bit key that hasn't been
|
||||
* used before.
|
||||
*/
|
||||
int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add)
|
||||
{
|
||||
int ret;
|
||||
unsigned long mask = (1UL << bits) - 1;
|
||||
unsigned long first, unshifted_key;
|
||||
|
||||
unshifted_key = hash_long(seed, bits);
|
||||
first = unshifted_key;
|
||||
do {
|
||||
item->key = (unshifted_key << shift) + add;
|
||||
ret = vmwgfx_ht_insert_item(ht, item);
|
||||
if (ret)
|
||||
unshifted_key = (unshifted_key + 1) & mask;
|
||||
} while (ret && (unshifted_key != first));
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("Available key bit space exhausted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
|
||||
struct vmwgfx_hash_item **item)
|
||||
{
|
||||
struct hlist_node *list;
|
||||
|
||||
list = vmwgfx_ht_find_key_rcu(ht, key);
|
||||
if (!list)
|
||||
return -EINVAL;
|
||||
|
||||
*item = hlist_entry(list, struct vmwgfx_hash_item, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct hlist_node *list;
|
||||
|
||||
list = vmwgfx_ht_find_key(ht, key);
|
||||
if (list) {
|
||||
hlist_del_init_rcu(list);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
|
||||
{
|
||||
hlist_del_init_rcu(&item->head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht)
|
||||
{
|
||||
if (ht->table) {
|
||||
kvfree(ht->table);
|
||||
ht->table = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: Replace this hashtable with Linux' generic implementation
|
||||
* from <linux/hashtable.h>.
|
||||
*/
|
||||
|
||||
#ifndef VMWGFX_HASHTAB_H
|
||||
#define VMWGFX_HASHTAB_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
struct vmwgfx_hash_item {
|
||||
struct hlist_node head;
|
||||
unsigned long key;
|
||||
};
|
||||
|
||||
struct vmwgfx_open_hash {
|
||||
struct hlist_head *table;
|
||||
u8 order;
|
||||
};
|
||||
|
||||
int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order);
|
||||
int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
|
||||
int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add);
|
||||
int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
|
||||
struct vmwgfx_hash_item **item);
|
||||
|
||||
void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key);
|
||||
int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key);
|
||||
int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
|
||||
void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht);
|
||||
|
||||
/*
|
||||
* RCU-safe interface
|
||||
*
|
||||
* The user of this API needs to make sure that two or more instances of the
|
||||
* hash table manipulation functions are never run simultaneously.
|
||||
* The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously
|
||||
* with any of the manipulation functions as long as it's called from within
|
||||
* an RCU read-locked section.
|
||||
*/
|
||||
#define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item
|
||||
#define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please
|
||||
#define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key
|
||||
#define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item
|
||||
#define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item
|
||||
|
||||
#endif
|
||||
@@ -281,39 +281,6 @@ out_bad_resource:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_user_resource_noref_lookup_handle - lookup a struct resource from a
|
||||
* TTM user-space handle and perform basic type checks
|
||||
*
|
||||
* @dev_priv: Pointer to a device private struct
|
||||
* @tfile: Pointer to a struct ttm_object_file identifying the caller
|
||||
* @handle: The TTM user-space handle
|
||||
* @converter: Pointer to an object describing the resource type
|
||||
*
|
||||
* If the handle can't be found or is associated with an incorrect resource
|
||||
* type, -EINVAL will be returned.
|
||||
*/
|
||||
struct vmw_resource *
|
||||
vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
|
||||
struct ttm_object_file *tfile,
|
||||
uint32_t handle,
|
||||
const struct vmw_user_resource_conv
|
||||
*converter)
|
||||
{
|
||||
struct ttm_base_object *base;
|
||||
|
||||
base = ttm_base_object_noref_lookup(tfile, handle);
|
||||
if (!base)
|
||||
return ERR_PTR(-ESRCH);
|
||||
|
||||
if (unlikely(ttm_base_object_type(base) != converter->object_type)) {
|
||||
ttm_base_object_noref_release();
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return converter->base_obj_to_res(base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function that looks either a surface or bo.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -180,11 +180,16 @@ vmw_validation_find_bo_dup(struct vmw_validation_context *ctx,
|
||||
if (!ctx->merge_dups)
|
||||
return NULL;
|
||||
|
||||
if (ctx->ht) {
|
||||
if (ctx->sw_context) {
|
||||
struct vmwgfx_hash_item *hash;
|
||||
unsigned long key = (unsigned long) vbo;
|
||||
|
||||
if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash))
|
||||
bo_node = container_of(hash, typeof(*bo_node), hash);
|
||||
hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
|
||||
if (hash->key == key) {
|
||||
bo_node = container_of(hash, typeof(*bo_node), hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct vmw_validation_bo_node *entry;
|
||||
|
||||
@@ -217,11 +222,16 @@ vmw_validation_find_res_dup(struct vmw_validation_context *ctx,
|
||||
if (!ctx->merge_dups)
|
||||
return NULL;
|
||||
|
||||
if (ctx->ht) {
|
||||
if (ctx->sw_context) {
|
||||
struct vmwgfx_hash_item *hash;
|
||||
unsigned long key = (unsigned long) res;
|
||||
|
||||
if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash))
|
||||
res_node = container_of(hash, typeof(*res_node), hash);
|
||||
hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) {
|
||||
if (hash->key == key) {
|
||||
res_node = container_of(hash, typeof(*res_node), hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct vmw_validation_res_node *entry;
|
||||
|
||||
@@ -269,20 +279,15 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx,
|
||||
}
|
||||
} else {
|
||||
struct ttm_validate_buffer *val_buf;
|
||||
int ret;
|
||||
|
||||
bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node));
|
||||
if (!bo_node)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ctx->ht) {
|
||||
if (ctx->sw_context) {
|
||||
bo_node->hash.key = (unsigned long) vbo;
|
||||
ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize a buffer "
|
||||
"validation entry.\n");
|
||||
return ret;
|
||||
}
|
||||
hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head,
|
||||
bo_node->hash.key);
|
||||
}
|
||||
val_buf = &bo_node->base;
|
||||
val_buf->bo = ttm_bo_get_unless_zero(&vbo->base);
|
||||
@@ -316,7 +321,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
|
||||
bool *first_usage)
|
||||
{
|
||||
struct vmw_validation_res_node *node;
|
||||
int ret;
|
||||
|
||||
node = vmw_validation_find_res_dup(ctx, res);
|
||||
if (node) {
|
||||
@@ -330,14 +334,9 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ctx->ht) {
|
||||
if (ctx->sw_context) {
|
||||
node->hash.key = (unsigned long) res;
|
||||
ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize a resource validation "
|
||||
"entry.\n");
|
||||
return ret;
|
||||
}
|
||||
hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key);
|
||||
}
|
||||
node->res = vmw_resource_reference_unless_doomed(res);
|
||||
if (!node->res)
|
||||
@@ -681,19 +680,19 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx)
|
||||
struct vmw_validation_bo_node *entry;
|
||||
struct vmw_validation_res_node *val;
|
||||
|
||||
if (!ctx->ht)
|
||||
if (!ctx->sw_context)
|
||||
return;
|
||||
|
||||
list_for_each_entry(entry, &ctx->bo_list, base.head)
|
||||
(void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash);
|
||||
hash_del_rcu(&entry->hash.head);
|
||||
|
||||
list_for_each_entry(val, &ctx->resource_list, head)
|
||||
(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
|
||||
hash_del_rcu(&val->hash.head);
|
||||
|
||||
list_for_each_entry(val, &ctx->resource_ctx_list, head)
|
||||
(void) vmwgfx_ht_remove_item(ctx->ht, &val->hash);
|
||||
hash_del_rcu(&entry->hash.head);
|
||||
|
||||
ctx->ht = NULL;
|
||||
ctx->sw_context = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright © 2018 VMware, Inc., Palo Alto, CA., USA
|
||||
* Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@@ -29,12 +29,11 @@
|
||||
#define _VMWGFX_VALIDATION_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/ww_mutex.h>
|
||||
|
||||
#include <drm/ttm/ttm_execbuf_util.h>
|
||||
|
||||
#include "vmwgfx_hashtab.h"
|
||||
|
||||
#define VMW_RES_DIRTY_NONE 0
|
||||
#define VMW_RES_DIRTY_SET BIT(0)
|
||||
#define VMW_RES_DIRTY_CLEAR BIT(1)
|
||||
@@ -59,7 +58,7 @@
|
||||
* @total_mem: Amount of reserved memory.
|
||||
*/
|
||||
struct vmw_validation_context {
|
||||
struct vmwgfx_open_hash *ht;
|
||||
struct vmw_sw_context *sw_context;
|
||||
struct list_head resource_list;
|
||||
struct list_head resource_ctx_list;
|
||||
struct list_head bo_list;
|
||||
@@ -82,16 +81,16 @@ struct vmw_fence_obj;
|
||||
/**
|
||||
* DECLARE_VAL_CONTEXT - Declare a validation context with initialization
|
||||
* @_name: The name of the variable
|
||||
* @_ht: The hash table used to find dups or NULL if none
|
||||
* @_sw_context: Contains the hash table used to find dups or NULL if none
|
||||
* @_merge_dups: Whether to merge duplicate buffer object- or resource
|
||||
* entries. If set to true, ideally a hash table pointer should be supplied
|
||||
* as well unless the number of resources and buffer objects per validation
|
||||
* is known to be very small
|
||||
*/
|
||||
#endif
|
||||
#define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups) \
|
||||
#define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups) \
|
||||
struct vmw_validation_context _name = \
|
||||
{ .ht = _ht, \
|
||||
{ .sw_context = _sw_context, \
|
||||
.resource_list = LIST_HEAD_INIT((_name).resource_list), \
|
||||
.resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \
|
||||
.bo_list = LIST_HEAD_INIT((_name).bo_list), \
|
||||
@@ -114,19 +113,6 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx)
|
||||
return !list_empty(&ctx->bo_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_validation_set_ht - Register a hash table for duplicate finding
|
||||
* @ctx: The validation context
|
||||
* @ht: Pointer to a hash table to use for duplicate finding
|
||||
* This function is intended to be used if the hash table wasn't
|
||||
* available at validation context declaration time
|
||||
*/
|
||||
static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx,
|
||||
struct vmwgfx_open_hash *ht)
|
||||
{
|
||||
ctx->ht = ht;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_validation_bo_reserve - Reserve buffer objects registered with a
|
||||
* validation context
|
||||
|
||||
@@ -3854,7 +3854,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
|
||||
|
||||
static void arm_smmu_device_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
arm_smmu_device_remove(pdev);
|
||||
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
|
||||
|
||||
arm_smmu_device_disable(smmu);
|
||||
}
|
||||
|
||||
static const struct of_device_id arm_smmu_of_match[] = {
|
||||
|
||||
@@ -1319,8 +1319,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
|
||||
|
||||
switch (cap) {
|
||||
case IOMMU_CAP_CACHE_COHERENCY:
|
||||
/* Assume that a coherent TCU implies coherent TBUs */
|
||||
return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
|
||||
/*
|
||||
* It's overwhelmingly the case in practice that when the pagetable
|
||||
* walk interface is connected to a coherent interconnect, all the
|
||||
* translation interfaces are too. Furthermore if the device is
|
||||
* natively coherent, then its translation interface must also be.
|
||||
*/
|
||||
return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK ||
|
||||
device_get_dma_attr(dev) == DEV_DMA_COHERENT;
|
||||
case IOMMU_CAP_NOEXEC:
|
||||
return true;
|
||||
default:
|
||||
@@ -2188,19 +2194,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_smmu_device_remove(struct platform_device *pdev)
|
||||
static void arm_smmu_device_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
|
||||
|
||||
if (!smmu)
|
||||
return -ENODEV;
|
||||
return;
|
||||
|
||||
if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
|
||||
dev_notice(&pdev->dev, "disabling translation\n");
|
||||
|
||||
iommu_device_unregister(&smmu->iommu);
|
||||
iommu_device_sysfs_remove(&smmu->iommu);
|
||||
|
||||
arm_smmu_rpm_get(smmu);
|
||||
/* Turn the thing off */
|
||||
arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD);
|
||||
@@ -2212,12 +2215,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
|
||||
clk_bulk_disable(smmu->num_clks, smmu->clks);
|
||||
|
||||
clk_bulk_unprepare(smmu->num_clks, smmu->clks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arm_smmu_device_shutdown(struct platform_device *pdev)
|
||||
static int arm_smmu_device_remove(struct platform_device *pdev)
|
||||
{
|
||||
arm_smmu_device_remove(pdev);
|
||||
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
|
||||
|
||||
if (!smmu)
|
||||
return -ENODEV;
|
||||
|
||||
iommu_device_unregister(&smmu->iommu);
|
||||
iommu_device_sysfs_remove(&smmu->iommu);
|
||||
|
||||
arm_smmu_device_shutdown(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
|
||||
|
||||
@@ -199,7 +199,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
|
||||
|
||||
curr = __get_cached_rbnode(iovad, limit_pfn);
|
||||
curr_iova = to_iova(curr);
|
||||
retry_pfn = curr_iova->pfn_hi + 1;
|
||||
retry_pfn = curr_iova->pfn_hi;
|
||||
|
||||
retry:
|
||||
do {
|
||||
@@ -213,7 +213,7 @@ retry:
|
||||
if (high_pfn < size || new_pfn < low_pfn) {
|
||||
if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) {
|
||||
high_pfn = limit_pfn;
|
||||
low_pfn = retry_pfn;
|
||||
low_pfn = retry_pfn + 1;
|
||||
curr = iova_find_limit(iovad, limit_pfn);
|
||||
curr_iova = to_iova(curr);
|
||||
goto retry;
|
||||
|
||||
@@ -685,7 +685,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
|
||||
ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
|
||||
dev_name(&pdev->dev));
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_clk_unprepare;
|
||||
|
||||
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
|
||||
if (ret)
|
||||
@@ -700,6 +700,8 @@ out_dev_unreg:
|
||||
iommu_device_unregister(&data->iommu);
|
||||
out_sysfs_remove:
|
||||
iommu_device_sysfs_remove(&data->iommu);
|
||||
out_clk_unprepare:
|
||||
clk_disable_unprepare(data->bclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1755,6 +1755,8 @@ static void dm_split_and_process_bio(struct mapped_device *md,
|
||||
* otherwise associated queue_limits won't be imposed.
|
||||
*/
|
||||
bio = bio_split_to_limits(bio);
|
||||
if (!bio)
|
||||
return;
|
||||
}
|
||||
|
||||
init_clone_info(&ci, md, map, bio, is_abnormal);
|
||||
|
||||
@@ -443,6 +443,8 @@ static void md_submit_bio(struct bio *bio)
|
||||
}
|
||||
|
||||
bio = bio_split_to_limits(bio);
|
||||
if (!bio)
|
||||
return;
|
||||
|
||||
if (mddev->ro == 1 && unlikely(rw == WRITE)) {
|
||||
if (bio_sectors(bio) != 0)
|
||||
|
||||
@@ -50,7 +50,7 @@ static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs,
|
||||
int cnt = 0;
|
||||
int res = 0;
|
||||
int res2;
|
||||
loff_t offs;
|
||||
uint32_t offs;
|
||||
size_t retlen;
|
||||
struct sc_part_desc *pdesc = NULL;
|
||||
struct sc_part_desc *tmpdesc;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
@@ -990,7 +990,7 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
|
||||
DMA_ATTR_WEAK_ORDERING);
|
||||
skb = build_skb(page_address(page), PAGE_SIZE);
|
||||
if (!skb) {
|
||||
__free_page(page);
|
||||
page_pool_recycle_direct(rxr->page_pool, page);
|
||||
return NULL;
|
||||
}
|
||||
skb_mark_for_recycle(skb);
|
||||
@@ -1028,7 +1028,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
|
||||
|
||||
skb = napi_alloc_skb(&rxr->bnapi->napi, payload);
|
||||
if (!skb) {
|
||||
__free_page(page);
|
||||
page_pool_recycle_direct(rxr->page_pool, page);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -3130,7 +3130,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num,
|
||||
|
||||
hclgevf_update_rss_size(handle, new_tqps_num);
|
||||
|
||||
hclge_comm_get_rss_tc_info(cur_rss_size, hdev->hw_tc_map,
|
||||
hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map,
|
||||
tc_offset, tc_valid, tc_size);
|
||||
ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset,
|
||||
tc_valid, tc_size);
|
||||
|
||||
@@ -3850,7 +3850,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
|
||||
field_flags |= IAVF_CLOUD_FIELD_IIP;
|
||||
} else {
|
||||
dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
|
||||
be32_to_cpu(match.mask->dst));
|
||||
be32_to_cpu(match.mask->src));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,6 +363,7 @@ ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
/* Send the data out to a hardware port */
|
||||
write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
|
||||
if (!write_buf) {
|
||||
kfree(cmd_buf);
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@@ -460,6 +461,9 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
|
||||
for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
|
||||
pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
|
||||
GFP_KERNEL);
|
||||
if (!pf->gnss_tty_port[i])
|
||||
goto err_out;
|
||||
|
||||
pf->gnss_serial[i] = NULL;
|
||||
|
||||
tty_port_init(pf->gnss_tty_port[i]);
|
||||
@@ -469,21 +473,23 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
|
||||
err = tty_register_driver(tty_driver);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to register TTY driver err=%d\n", err);
|
||||
|
||||
for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
|
||||
tty_port_destroy(pf->gnss_tty_port[i]);
|
||||
kfree(pf->gnss_tty_port[i]);
|
||||
}
|
||||
kfree(ttydrv_name);
|
||||
tty_driver_kref_put(pf->ice_gnss_tty_driver);
|
||||
|
||||
return NULL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
|
||||
dev_info(dev, "%s%d registered\n", ttydrv_name, i);
|
||||
|
||||
return tty_driver;
|
||||
|
||||
err_out:
|
||||
while (i--) {
|
||||
tty_port_destroy(pf->gnss_tty_port[i]);
|
||||
kfree(pf->gnss_tty_port[i]);
|
||||
}
|
||||
kfree(ttydrv_name);
|
||||
tty_driver_kref_put(pf->ice_gnss_tty_driver);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -466,7 +466,9 @@
|
||||
#define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */
|
||||
#define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */
|
||||
#define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */
|
||||
#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */
|
||||
#define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */
|
||||
#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */
|
||||
#define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */
|
||||
|
||||
@@ -322,7 +322,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
|
||||
ts = ns_to_timespec64(ns);
|
||||
if (rq->perout.index == 1) {
|
||||
if (use_freq) {
|
||||
tsauxc_mask = IGC_TSAUXC_EN_CLK1;
|
||||
tsauxc_mask = IGC_TSAUXC_EN_CLK1 | IGC_TSAUXC_ST1;
|
||||
tsim_mask = 0;
|
||||
} else {
|
||||
tsauxc_mask = IGC_TSAUXC_EN_TT1;
|
||||
@@ -333,7 +333,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
|
||||
freqout = IGC_FREQOUT1;
|
||||
} else {
|
||||
if (use_freq) {
|
||||
tsauxc_mask = IGC_TSAUXC_EN_CLK0;
|
||||
tsauxc_mask = IGC_TSAUXC_EN_CLK0 | IGC_TSAUXC_ST0;
|
||||
tsim_mask = 0;
|
||||
} else {
|
||||
tsauxc_mask = IGC_TSAUXC_EN_TT0;
|
||||
@@ -347,10 +347,12 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
|
||||
tsauxc = rd32(IGC_TSAUXC);
|
||||
tsim = rd32(IGC_TSIM);
|
||||
if (rq->perout.index == 1) {
|
||||
tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1);
|
||||
tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1 |
|
||||
IGC_TSAUXC_ST1);
|
||||
tsim &= ~IGC_TSICR_TT1;
|
||||
} else {
|
||||
tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0);
|
||||
tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0 |
|
||||
IGC_TSAUXC_ST0);
|
||||
tsim &= ~IGC_TSICR_TT0;
|
||||
}
|
||||
if (on) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user