Merge 4.14.29 into android-4.14
Changes in 4.14.29
x86/cpufeatures: Add Intel Total Memory Encryption cpufeature
x86/cpufeatures: Add Intel PCONFIG cpufeature
selftests/x86/entry_from_vm86: Exit with 1 if we fail
selftests/x86: Add tests for User-Mode Instruction Prevention
selftests/x86: Add tests for the STR and SLDT instructions
selftests/x86/entry_from_vm86: Add test cases for POPF
x86/vm86/32: Fix POPF emulation
x86/speculation, objtool: Annotate indirect calls/jumps for objtool on 32-bit kernels
x86/speculation: Remove Skylake C2 from Speculation Control microcode blacklist
KVM: x86: Fix device passthrough when SME is active
x86/mm: Fix vmalloc_fault to use pXd_large
parisc: Handle case where flush_cache_range is called with no context
ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats()
ALSA: hda - Revert power_save option default value
ALSA: seq: Fix possible UAF in snd_seq_check_queue()
ALSA: seq: Clear client entry before deleting else at closing
drm/nouveau/bl: Fix oops on driver unbind
drm/amdgpu: fix prime teardown order
drm/radeon: fix prime teardown order
drm/amdgpu/dce: Don't turn off DP sink when disconnected
fs: Teach path_connected to handle nfs filesystems with multiple roots.
KVM: arm/arm64: Reduce verbosity of KVM init log
kvm: arm/arm64: vgic-v3: Tighten synchronization for guests using v2 on v3
KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid
lock_parent() needs to recheck if dentry got __dentry_kill'ed under it
fs/aio: Add explicit RCU grace period when freeing kioctx
fs/aio: Use RCU accessors for kioctx_table->table[]
RDMAVT: Fix synchronization around percpu_ref
irqchip/gic-v3-its: Ensure nr_ites >= nr_lpis
btrfs: Fix NULL pointer exception in find_bio_stripe
btrfs: add missing initialization in btrfs_check_shared
btrfs: alloc_chunk: fix DUP stripe size handling
btrfs: Fix use-after-free when cleaning up fs_devs with a single stale device
btrfs: remove spurious WARN_ON(ref->count < 0) in find_parent_nodes
btrfs: Fix memory barriers usage with device stats counters
scsi: qla2xxx: Fix smatch warning in qla25xx_delete_{rsp|req}_que
scsi: qla2xxx: Fix NULL pointer access for fcport structure
scsi: qla2xxx: Fix logo flag for qlt_free_session_done()
scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure
USB: gadget: udc: Add missing platform_device_put() on error in bdc_pci_probe()
usb: dwc3: Fix GDBGFIFOSPACE_TYPE values
Linux 4.14.29
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 14
|
||||
SUBLEVEL = 28
|
||||
SUBLEVEL = 29
|
||||
EXTRAVERSION =
|
||||
NAME = Petit Gorille
|
||||
|
||||
|
||||
@@ -543,7 +543,8 @@ void flush_cache_mm(struct mm_struct *mm)
|
||||
rp3440, etc. So, avoid it if the mm isn't too big. */
|
||||
if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
|
||||
mm_total_size(mm) >= parisc_cache_flush_threshold) {
|
||||
flush_tlb_all();
|
||||
if (mm->context)
|
||||
flush_tlb_all();
|
||||
flush_cache_all();
|
||||
return;
|
||||
}
|
||||
@@ -571,6 +572,8 @@ void flush_cache_mm(struct mm_struct *mm)
|
||||
pfn = pte_pfn(*ptep);
|
||||
if (!pfn_valid(pfn))
|
||||
continue;
|
||||
if (unlikely(mm->context))
|
||||
flush_tlb_page(vma, addr);
|
||||
__flush_cache_page(vma, addr, PFN_PHYS(pfn));
|
||||
}
|
||||
}
|
||||
@@ -579,26 +582,46 @@ void flush_cache_mm(struct mm_struct *mm)
|
||||
void flush_cache_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
unsigned long addr;
|
||||
|
||||
if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
|
||||
end - start >= parisc_cache_flush_threshold) {
|
||||
flush_tlb_range(vma, start, end);
|
||||
if (vma->vm_mm->context)
|
||||
flush_tlb_range(vma, start, end);
|
||||
flush_cache_all();
|
||||
return;
|
||||
}
|
||||
|
||||
flush_user_dcache_range_asm(start, end);
|
||||
if (vma->vm_flags & VM_EXEC)
|
||||
flush_user_icache_range_asm(start, end);
|
||||
flush_tlb_range(vma, start, end);
|
||||
if (vma->vm_mm->context == mfsp(3)) {
|
||||
flush_user_dcache_range_asm(start, end);
|
||||
if (vma->vm_flags & VM_EXEC)
|
||||
flush_user_icache_range_asm(start, end);
|
||||
flush_tlb_range(vma, start, end);
|
||||
return;
|
||||
}
|
||||
|
||||
pgd = vma->vm_mm->pgd;
|
||||
for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
|
||||
unsigned long pfn;
|
||||
pte_t *ptep = get_ptep(pgd, addr);
|
||||
if (!ptep)
|
||||
continue;
|
||||
pfn = pte_pfn(*ptep);
|
||||
if (pfn_valid(pfn)) {
|
||||
if (unlikely(vma->vm_mm->context))
|
||||
flush_tlb_page(vma, addr);
|
||||
__flush_cache_page(vma, addr, PFN_PHYS(pfn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
|
||||
{
|
||||
BUG_ON(!vma->vm_mm->context);
|
||||
|
||||
if (pfn_valid(pfn)) {
|
||||
flush_tlb_page(vma, vmaddr);
|
||||
if (likely(vma->vm_mm->context))
|
||||
flush_tlb_page(vma, vmaddr);
|
||||
__flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,6 +314,7 @@
|
||||
#define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */
|
||||
#define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */
|
||||
#define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */
|
||||
#define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */
|
||||
#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
|
||||
#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */
|
||||
#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */
|
||||
@@ -326,6 +327,7 @@
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
|
||||
#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */
|
||||
#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
|
||||
#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */
|
||||
#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
|
||||
#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */
|
||||
#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
|
||||
|
||||
@@ -183,7 +183,10 @@
|
||||
* otherwise we'll run out of registers. We don't care about CET
|
||||
* here, anyway.
|
||||
*/
|
||||
# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \
|
||||
# define CALL_NOSPEC \
|
||||
ALTERNATIVE( \
|
||||
ANNOTATE_RETPOLINE_SAFE \
|
||||
"call *%[thunk_target]\n", \
|
||||
" jmp 904f;\n" \
|
||||
" .align 16\n" \
|
||||
"901: call 903f;\n" \
|
||||
|
||||
@@ -105,7 +105,7 @@ static void probe_xeon_phi_r3mwait(struct cpuinfo_x86 *c)
|
||||
/*
|
||||
* Early microcode releases for the Spectre v2 mitigation were broken.
|
||||
* Information taken from;
|
||||
* - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/microcode-update-guidance.pdf
|
||||
* - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/03/microcode-update-guidance.pdf
|
||||
* - https://kb.vmware.com/s/article/52345
|
||||
* - Microcode revisions observed in the wild
|
||||
* - Release note from 20180108 microcode release
|
||||
@@ -123,7 +123,6 @@ static const struct sku_microcode spectre_bad_microcodes[] = {
|
||||
{ INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 },
|
||||
{ INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e },
|
||||
{ INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c },
|
||||
{ INTEL_FAM6_SKYLAKE_DESKTOP, 0x03, 0xc2 },
|
||||
{ INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 },
|
||||
{ INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b },
|
||||
{ INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 },
|
||||
|
||||
@@ -727,7 +727,8 @@ void handle_vm86_fault(struct kernel_vm86_regs *regs, long error_code)
|
||||
return;
|
||||
|
||||
check_vip:
|
||||
if (VEFLAGS & X86_EFLAGS_VIP) {
|
||||
if ((VEFLAGS & (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) ==
|
||||
(X86_EFLAGS_VIP | X86_EFLAGS_VIF)) {
|
||||
save_v86_state(regs, VM86_STI);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2758,8 +2758,10 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
|
||||
else
|
||||
pte_access &= ~ACC_WRITE_MASK;
|
||||
|
||||
if (!kvm_is_mmio_pfn(pfn))
|
||||
spte |= shadow_me_mask;
|
||||
|
||||
spte |= (u64)pfn << PAGE_SHIFT;
|
||||
spte |= shadow_me_mask;
|
||||
|
||||
if (pte_access & ACC_WRITE_MASK) {
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ static noinline int vmalloc_fault(unsigned long address)
|
||||
if (!pmd_k)
|
||||
return -1;
|
||||
|
||||
if (pmd_huge(*pmd_k))
|
||||
if (pmd_large(*pmd_k))
|
||||
return 0;
|
||||
|
||||
pte_k = pte_offset_kernel(pmd_k, address);
|
||||
@@ -479,7 +479,7 @@ static noinline int vmalloc_fault(unsigned long address)
|
||||
if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
|
||||
BUG();
|
||||
|
||||
if (pud_huge(*pud))
|
||||
if (pud_large(*pud))
|
||||
return 0;
|
||||
|
||||
pmd = pmd_offset(pud, address);
|
||||
@@ -490,7 +490,7 @@ static noinline int vmalloc_fault(unsigned long address)
|
||||
if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
|
||||
BUG();
|
||||
|
||||
if (pmd_huge(*pmd))
|
||||
if (pmd_large(*pmd))
|
||||
return 0;
|
||||
|
||||
pte_ref = pte_offset_kernel(pmd_ref, address);
|
||||
|
||||
@@ -69,25 +69,18 @@ void amdgpu_connector_hotplug(struct drm_connector *connector)
|
||||
/* don't do anything if sink is not display port, i.e.,
|
||||
* passive dp->(dvi|hdmi) adaptor
|
||||
*/
|
||||
if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
|
||||
int saved_dpms = connector->dpms;
|
||||
/* Only turn off the display if it's physically disconnected */
|
||||
if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
} else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
|
||||
/* Don't try to start link training before we
|
||||
* have the dpcd */
|
||||
if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
|
||||
return;
|
||||
if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
|
||||
amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) &&
|
||||
amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
|
||||
/* Don't start link training before we have the DPCD */
|
||||
if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
|
||||
return;
|
||||
|
||||
/* set it to OFF so that drm_helper_connector_dpms()
|
||||
* won't return immediately since the current state
|
||||
* is ON at this point.
|
||||
*/
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
connector->dpms = saved_dpms;
|
||||
/* Turn the connector off and back on immediately, which
|
||||
* will trigger link training
|
||||
*/
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj)
|
||||
struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj);
|
||||
|
||||
if (robj) {
|
||||
if (robj->gem_base.import_attach)
|
||||
drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
|
||||
amdgpu_mn_unregister(robj);
|
||||
amdgpu_bo_unref(&robj);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
|
||||
|
||||
amdgpu_bo_kunmap(bo);
|
||||
|
||||
if (bo->gem_base.import_attach)
|
||||
drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg);
|
||||
drm_gem_object_release(&bo->gem_base);
|
||||
amdgpu_bo_unref(&bo->parent);
|
||||
if (!list_empty(&bo->shadow_list)) {
|
||||
|
||||
@@ -268,13 +268,13 @@ nouveau_backlight_init(struct drm_device *dev)
|
||||
struct nvif_device *device = &drm->client.device;
|
||||
struct drm_connector *connector;
|
||||
|
||||
INIT_LIST_HEAD(&drm->bl_connectors);
|
||||
|
||||
if (apple_gmux_present()) {
|
||||
NV_INFO(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&drm->bl_connectors);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
|
||||
connector->connector_type != DRM_MODE_CONNECTOR_eDP)
|
||||
|
||||
@@ -34,8 +34,6 @@ void radeon_gem_object_free(struct drm_gem_object *gobj)
|
||||
struct radeon_bo *robj = gem_to_radeon_bo(gobj);
|
||||
|
||||
if (robj) {
|
||||
if (robj->gem_base.import_attach)
|
||||
drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
|
||||
radeon_mn_unregister(robj);
|
||||
radeon_bo_unref(&robj);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
|
||||
mutex_unlock(&bo->rdev->gem.mutex);
|
||||
radeon_bo_clear_surface_reg(bo);
|
||||
WARN_ON_ONCE(!list_empty(&bo->va));
|
||||
if (bo->gem_base.import_attach)
|
||||
drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg);
|
||||
drm_gem_object_release(&bo->gem_base);
|
||||
kfree(bo);
|
||||
}
|
||||
|
||||
@@ -489,11 +489,13 @@ static int rvt_check_refs(struct rvt_mregion *mr, const char *t)
|
||||
unsigned long timeout;
|
||||
struct rvt_dev_info *rdi = ib_to_rvt(mr->pd->device);
|
||||
|
||||
if (percpu_ref_is_zero(&mr->refcount))
|
||||
return 0;
|
||||
/* avoid dma mr */
|
||||
if (mr->lkey)
|
||||
if (mr->lkey) {
|
||||
/* avoid dma mr */
|
||||
rvt_dereg_clean_qps(mr);
|
||||
/* @mr was indexed on rcu protected @lkey_table */
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&mr->comp, 5 * HZ);
|
||||
if (!timeout) {
|
||||
rvt_pr_err(rdi,
|
||||
|
||||
@@ -1310,7 +1310,7 @@ static struct irq_chip its_irq_chip = {
|
||||
* This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
|
||||
*/
|
||||
#define IRQS_PER_CHUNK_SHIFT 5
|
||||
#define IRQS_PER_CHUNK (1 << IRQS_PER_CHUNK_SHIFT)
|
||||
#define IRQS_PER_CHUNK (1UL << IRQS_PER_CHUNK_SHIFT)
|
||||
#define ITS_MAX_LPI_NRBITS 16 /* 64K LPIs */
|
||||
|
||||
static unsigned long *lpi_bitmap;
|
||||
@@ -2026,11 +2026,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
/*
|
||||
* At least one bit of EventID is being used, hence a minimum
|
||||
* of two entries. No, the architecture doesn't let you
|
||||
* express an ITT with a single entry.
|
||||
* We allocate at least one chunk worth of LPIs bet device,
|
||||
* and thus that many ITEs. The device may require less though.
|
||||
*/
|
||||
nr_ites = max(2UL, roundup_pow_of_two(nvecs));
|
||||
nr_ites = max(IRQS_PER_CHUNK, roundup_pow_of_two(nvecs));
|
||||
sz = nr_ites * its->ite_size;
|
||||
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
|
||||
itt = kzalloc(sz, GFP_KERNEL);
|
||||
|
||||
@@ -102,11 +102,16 @@ qla2x00_async_iocb_timeout(void *data)
|
||||
struct srb_iocb *lio = &sp->u.iocb_cmd;
|
||||
struct event_arg ea;
|
||||
|
||||
ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
|
||||
"Async-%s timeout - hdl=%x portid=%06x %8phC.\n",
|
||||
sp->name, sp->handle, fcport->d_id.b24, fcport->port_name);
|
||||
if (fcport) {
|
||||
ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
|
||||
"Async-%s timeout - hdl=%x portid=%06x %8phC.\n",
|
||||
sp->name, sp->handle, fcport->d_id.b24, fcport->port_name);
|
||||
|
||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
||||
} else {
|
||||
pr_info("Async-%s timeout - hdl=%x.\n",
|
||||
sp->name, sp->handle);
|
||||
}
|
||||
|
||||
switch (sp->type) {
|
||||
case SRB_LOGIN_CMD:
|
||||
|
||||
@@ -582,8 +582,9 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
ret = qla25xx_init_req_que(vha, req);
|
||||
if (ret != QLA_SUCCESS)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
qla25xx_free_req_que(vha, req);
|
||||
}
|
||||
qla25xx_free_req_que(vha, req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -598,8 +599,9 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
ret = qla25xx_init_rsp_que(vha, rsp);
|
||||
if (ret != QLA_SUCCESS)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
qla25xx_free_rsp_que(vha, rsp);
|
||||
}
|
||||
qla25xx_free_rsp_que(vha, rsp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
|
||||
ha->req_q_map[0] = req;
|
||||
set_bit(0, ha->rsp_qid_map);
|
||||
set_bit(0, ha->req_qid_map);
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
fail_qpair_map:
|
||||
kfree(ha->base_qpair);
|
||||
@@ -459,6 +459,9 @@ fail_req_map:
|
||||
|
||||
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||
{
|
||||
if (!ha->req_q_map)
|
||||
return;
|
||||
|
||||
if (IS_QLAFX00(ha)) {
|
||||
if (req && req->ring_fx00)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
@@ -469,14 +472,17 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||
(req->length + 1) * sizeof(request_t),
|
||||
req->ring, req->dma);
|
||||
|
||||
if (req)
|
||||
if (req) {
|
||||
kfree(req->outstanding_cmds);
|
||||
|
||||
kfree(req);
|
||||
kfree(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
{
|
||||
if (!ha->rsp_q_map)
|
||||
return;
|
||||
|
||||
if (IS_QLAFX00(ha)) {
|
||||
if (rsp && rsp->ring)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
@@ -487,7 +493,8 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
(rsp->length + 1) * sizeof(response_t),
|
||||
rsp->ring, rsp->dma);
|
||||
}
|
||||
kfree(rsp);
|
||||
if (rsp)
|
||||
kfree(rsp);
|
||||
}
|
||||
|
||||
static void qla2x00_free_queues(struct qla_hw_data *ha)
|
||||
@@ -1710,6 +1717,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
|
||||
struct qla_tgt_cmd *cmd;
|
||||
uint8_t trace = 0;
|
||||
|
||||
if (!ha->req_q_map)
|
||||
return;
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (que = 0; que < ha->max_req_queues; que++) {
|
||||
req = ha->req_q_map[que];
|
||||
@@ -3063,14 +3072,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
/* Set up the irqs */
|
||||
ret = qla2x00_request_irqs(ha, rsp);
|
||||
if (ret)
|
||||
goto probe_hw_failed;
|
||||
goto probe_failed;
|
||||
|
||||
/* Alloc arrays of request and response ring ptrs */
|
||||
if (!qla2x00_alloc_queues(ha, req, rsp)) {
|
||||
if (qla2x00_alloc_queues(ha, req, rsp)) {
|
||||
ql_log(ql_log_fatal, base_vha, 0x003d,
|
||||
"Failed to allocate memory for queue pointers..."
|
||||
"aborting.\n");
|
||||
goto probe_init_failed;
|
||||
goto probe_failed;
|
||||
}
|
||||
|
||||
if (ha->mqenable && shost_use_blk_mq(host)) {
|
||||
@@ -3347,15 +3356,6 @@ skip_dpc:
|
||||
|
||||
return 0;
|
||||
|
||||
probe_init_failed:
|
||||
qla2x00_free_req_que(ha, req);
|
||||
ha->req_q_map[0] = NULL;
|
||||
clear_bit(0, ha->req_qid_map);
|
||||
qla2x00_free_rsp_que(ha, rsp);
|
||||
ha->rsp_q_map[0] = NULL;
|
||||
clear_bit(0, ha->rsp_qid_map);
|
||||
ha->max_req_queues = ha->max_rsp_queues = 0;
|
||||
|
||||
probe_failed:
|
||||
if (base_vha->timer_active)
|
||||
qla2x00_stop_timer(base_vha);
|
||||
@@ -4435,11 +4435,17 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
||||
if (ha->init_cb)
|
||||
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
|
||||
ha->init_cb, ha->init_cb_dma);
|
||||
vfree(ha->optrom_buffer);
|
||||
kfree(ha->nvram);
|
||||
kfree(ha->npiv_info);
|
||||
kfree(ha->swl);
|
||||
kfree(ha->loop_id_map);
|
||||
|
||||
if (ha->optrom_buffer)
|
||||
vfree(ha->optrom_buffer);
|
||||
if (ha->nvram)
|
||||
kfree(ha->nvram);
|
||||
if (ha->npiv_info)
|
||||
kfree(ha->npiv_info);
|
||||
if (ha->swl)
|
||||
kfree(ha->swl);
|
||||
if (ha->loop_id_map)
|
||||
kfree(ha->loop_id_map);
|
||||
|
||||
ha->srb_mempool = NULL;
|
||||
ha->ctx_mempool = NULL;
|
||||
@@ -4455,6 +4461,15 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
||||
ha->ex_init_cb_dma = 0;
|
||||
ha->async_pd = NULL;
|
||||
ha->async_pd_dma = 0;
|
||||
ha->loop_id_map = NULL;
|
||||
ha->npiv_info = NULL;
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->swl = NULL;
|
||||
ha->nvram = NULL;
|
||||
ha->mctp_dump = NULL;
|
||||
ha->dcbx_tlv = NULL;
|
||||
ha->xgmac_data = NULL;
|
||||
ha->sfp_data = NULL;
|
||||
|
||||
ha->s_dma_pool = NULL;
|
||||
ha->dl_dma_pool = NULL;
|
||||
|
||||
@@ -971,6 +971,7 @@ static void qlt_free_session_done(struct work_struct *work)
|
||||
|
||||
logo.id = sess->d_id;
|
||||
logo.cmd_count = 0;
|
||||
sess->send_els_logo = 0;
|
||||
qlt_send_first_logo(vha, &logo);
|
||||
}
|
||||
|
||||
|
||||
@@ -166,13 +166,15 @@
|
||||
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
|
||||
#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
|
||||
|
||||
#define DWC3_TXFIFOQ 1
|
||||
#define DWC3_RXFIFOQ 3
|
||||
#define DWC3_TXREQQ 5
|
||||
#define DWC3_RXREQQ 7
|
||||
#define DWC3_RXINFOQ 9
|
||||
#define DWC3_DESCFETCHQ 13
|
||||
#define DWC3_EVENTQ 15
|
||||
#define DWC3_TXFIFOQ 0
|
||||
#define DWC3_RXFIFOQ 1
|
||||
#define DWC3_TXREQQ 2
|
||||
#define DWC3_RXREQQ 3
|
||||
#define DWC3_RXINFOQ 4
|
||||
#define DWC3_PSTATQ 5
|
||||
#define DWC3_DESCFETCHQ 6
|
||||
#define DWC3_EVENTQ 7
|
||||
#define DWC3_AUXEVENTQ 8
|
||||
|
||||
/* Global RX Threshold Configuration Register */
|
||||
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
|
||||
|
||||
@@ -82,6 +82,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
if (ret) {
|
||||
dev_err(&pci->dev,
|
||||
"couldn't add resources to bdc device\n");
|
||||
platform_device_put(bdc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
44
fs/aio.c
44
fs/aio.c
@@ -68,9 +68,9 @@ struct aio_ring {
|
||||
#define AIO_RING_PAGES 8
|
||||
|
||||
struct kioctx_table {
|
||||
struct rcu_head rcu;
|
||||
unsigned nr;
|
||||
struct kioctx *table[];
|
||||
struct rcu_head rcu;
|
||||
unsigned nr;
|
||||
struct kioctx __rcu *table[];
|
||||
};
|
||||
|
||||
struct kioctx_cpu {
|
||||
@@ -115,7 +115,8 @@ struct kioctx {
|
||||
struct page **ring_pages;
|
||||
long nr_pages;
|
||||
|
||||
struct work_struct free_work;
|
||||
struct rcu_head free_rcu;
|
||||
struct work_struct free_work; /* see free_ioctx() */
|
||||
|
||||
/*
|
||||
* signals when all in-flight requests are done
|
||||
@@ -329,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
|
||||
for (i = 0; i < table->nr; i++) {
|
||||
struct kioctx *ctx;
|
||||
|
||||
ctx = table->table[i];
|
||||
ctx = rcu_dereference(table->table[i]);
|
||||
if (ctx && ctx->aio_ring_file == file) {
|
||||
if (!atomic_read(&ctx->dead)) {
|
||||
ctx->user_id = ctx->mmap_base = vma->vm_start;
|
||||
@@ -588,6 +589,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
|
||||
return cancel(&kiocb->common);
|
||||
}
|
||||
|
||||
/*
|
||||
* free_ioctx() should be RCU delayed to synchronize against the RCU
|
||||
* protected lookup_ioctx() and also needs process context to call
|
||||
* aio_free_ring(), so the double bouncing through kioctx->free_rcu and
|
||||
* ->free_work.
|
||||
*/
|
||||
static void free_ioctx(struct work_struct *work)
|
||||
{
|
||||
struct kioctx *ctx = container_of(work, struct kioctx, free_work);
|
||||
@@ -601,6 +608,14 @@ static void free_ioctx(struct work_struct *work)
|
||||
kmem_cache_free(kioctx_cachep, ctx);
|
||||
}
|
||||
|
||||
static void free_ioctx_rcufn(struct rcu_head *head)
|
||||
{
|
||||
struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
|
||||
|
||||
INIT_WORK(&ctx->free_work, free_ioctx);
|
||||
schedule_work(&ctx->free_work);
|
||||
}
|
||||
|
||||
static void free_ioctx_reqs(struct percpu_ref *ref)
|
||||
{
|
||||
struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
|
||||
@@ -609,8 +624,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
|
||||
if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count))
|
||||
complete(&ctx->rq_wait->comp);
|
||||
|
||||
INIT_WORK(&ctx->free_work, free_ioctx);
|
||||
schedule_work(&ctx->free_work);
|
||||
/* Synchronize against RCU protected table->table[] dereferences */
|
||||
call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -651,9 +666,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
|
||||
while (1) {
|
||||
if (table)
|
||||
for (i = 0; i < table->nr; i++)
|
||||
if (!table->table[i]) {
|
||||
if (!rcu_access_pointer(table->table[i])) {
|
||||
ctx->id = i;
|
||||
table->table[i] = ctx;
|
||||
rcu_assign_pointer(table->table[i], ctx);
|
||||
spin_unlock(&mm->ioctx_lock);
|
||||
|
||||
/* While kioctx setup is in progress,
|
||||
@@ -834,11 +849,11 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
|
||||
}
|
||||
|
||||
table = rcu_dereference_raw(mm->ioctx_table);
|
||||
WARN_ON(ctx != table->table[ctx->id]);
|
||||
table->table[ctx->id] = NULL;
|
||||
WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
|
||||
RCU_INIT_POINTER(table->table[ctx->id], NULL);
|
||||
spin_unlock(&mm->ioctx_lock);
|
||||
|
||||
/* percpu_ref_kill() will do the necessary call_rcu() */
|
||||
/* free_ioctx_reqs() will do the necessary RCU synchronization */
|
||||
wake_up_all(&ctx->wait);
|
||||
|
||||
/*
|
||||
@@ -880,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
|
||||
|
||||
skipped = 0;
|
||||
for (i = 0; i < table->nr; ++i) {
|
||||
struct kioctx *ctx = table->table[i];
|
||||
struct kioctx *ctx =
|
||||
rcu_dereference_protected(table->table[i], true);
|
||||
|
||||
if (!ctx) {
|
||||
skipped++;
|
||||
@@ -1069,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
|
||||
if (!table || id >= table->nr)
|
||||
goto out;
|
||||
|
||||
ctx = table->table[id];
|
||||
ctx = rcu_dereference(table->table[id]);
|
||||
if (ctx && ctx->user_id == ctx_id) {
|
||||
percpu_ref_get(&ctx->users);
|
||||
ret = ctx;
|
||||
|
||||
@@ -1252,7 +1252,16 @@ again:
|
||||
while (node) {
|
||||
ref = rb_entry(node, struct prelim_ref, rbnode);
|
||||
node = rb_next(&ref->rbnode);
|
||||
WARN_ON(ref->count < 0);
|
||||
/*
|
||||
* ref->count < 0 can happen here if there are delayed
|
||||
* refs with a node->action of BTRFS_DROP_DELAYED_REF.
|
||||
* prelim_ref_insert() relies on this when merging
|
||||
* identical refs to keep the overall count correct.
|
||||
* prelim_ref_insert() will merge only those refs
|
||||
* which compare identically. Any refs having
|
||||
* e.g. different offsets would not be merged,
|
||||
* and would retain their original ref->count < 0.
|
||||
*/
|
||||
if (roots && ref->count && ref->root_id && ref->parent == 0) {
|
||||
if (sc && sc->root_objectid &&
|
||||
ref->root_id != sc->root_objectid) {
|
||||
@@ -1496,6 +1505,7 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
|
||||
if (!node)
|
||||
break;
|
||||
bytenr = node->val;
|
||||
shared.share_count = 0;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
|
||||
@@ -1348,6 +1348,7 @@ static int find_bio_stripe(struct btrfs_raid_bio *rbio,
|
||||
stripe_start = stripe->physical;
|
||||
if (physical >= stripe_start &&
|
||||
physical < stripe_start + rbio->stripe_len &&
|
||||
stripe->dev->bdev &&
|
||||
bio->bi_disk == stripe->dev->bdev->bd_disk &&
|
||||
bio->bi_partno == stripe->dev->bdev->bd_partno) {
|
||||
return i;
|
||||
|
||||
@@ -589,6 +589,7 @@ void btrfs_free_stale_device(struct btrfs_device *cur_dev)
|
||||
btrfs_sysfs_remove_fsid(fs_devs);
|
||||
list_del(&fs_devs->list);
|
||||
free_fs_devices(fs_devs);
|
||||
break;
|
||||
} else {
|
||||
fs_devs->num_devices--;
|
||||
list_del(&dev->dev_list);
|
||||
@@ -4733,10 +4734,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||
ndevs = min(ndevs, devs_max);
|
||||
|
||||
/*
|
||||
* the primary goal is to maximize the number of stripes, so use as many
|
||||
* devices as possible, even if the stripes are not maximum sized.
|
||||
* The primary goal is to maximize the number of stripes, so use as
|
||||
* many devices as possible, even if the stripes are not maximum sized.
|
||||
*
|
||||
* The DUP profile stores more than one stripe per device, the
|
||||
* max_avail is the total size so we have to adjust.
|
||||
*/
|
||||
stripe_size = devices_info[ndevs-1].max_avail;
|
||||
stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes);
|
||||
num_stripes = ndevs * dev_stripes;
|
||||
|
||||
/*
|
||||
@@ -4771,8 +4775,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||
stripe_size = devices_info[ndevs-1].max_avail;
|
||||
}
|
||||
|
||||
stripe_size = div_u64(stripe_size, dev_stripes);
|
||||
|
||||
/* align to BTRFS_STRIPE_LEN */
|
||||
stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
|
||||
|
||||
@@ -7080,10 +7082,24 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
|
||||
|
||||
mutex_lock(&fs_devices->device_list_mutex);
|
||||
list_for_each_entry(device, &fs_devices->devices, dev_list) {
|
||||
if (!device->dev_stats_valid || !btrfs_dev_stats_dirty(device))
|
||||
stats_cnt = atomic_read(&device->dev_stats_ccnt);
|
||||
if (!device->dev_stats_valid || stats_cnt == 0)
|
||||
continue;
|
||||
|
||||
stats_cnt = atomic_read(&device->dev_stats_ccnt);
|
||||
|
||||
/*
|
||||
* There is a LOAD-LOAD control dependency between the value of
|
||||
* dev_stats_ccnt and updating the on-disk values which requires
|
||||
* reading the in-memory counters. Such control dependencies
|
||||
* require explicit read memory barriers.
|
||||
*
|
||||
* This memory barriers pairs with smp_mb__before_atomic in
|
||||
* btrfs_dev_stat_inc/btrfs_dev_stat_set and with the full
|
||||
* barrier implied by atomic_xchg in
|
||||
* btrfs_dev_stats_read_and_reset
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
ret = update_dev_stat_item(trans, fs_info, device);
|
||||
if (!ret)
|
||||
atomic_sub(stats_cnt, &device->dev_stats_ccnt);
|
||||
|
||||
@@ -498,6 +498,12 @@ static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
|
||||
int index)
|
||||
{
|
||||
atomic_inc(dev->dev_stat_values + index);
|
||||
/*
|
||||
* This memory barrier orders stores updating statistics before stores
|
||||
* updating dev_stats_ccnt.
|
||||
*
|
||||
* It pairs with smp_rmb() in btrfs_run_dev_stats().
|
||||
*/
|
||||
smp_mb__before_atomic();
|
||||
atomic_inc(&dev->dev_stats_ccnt);
|
||||
}
|
||||
@@ -523,6 +529,12 @@ static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
|
||||
int index, unsigned long val)
|
||||
{
|
||||
atomic_set(dev->dev_stat_values + index, val);
|
||||
/*
|
||||
* This memory barrier orders stores updating statistics before stores
|
||||
* updating dev_stats_ccnt.
|
||||
*
|
||||
* It pairs with smp_rmb() in btrfs_run_dev_stats().
|
||||
*/
|
||||
smp_mb__before_atomic();
|
||||
atomic_inc(&dev->dev_stats_ccnt);
|
||||
}
|
||||
|
||||
11
fs/dcache.c
11
fs/dcache.c
@@ -644,11 +644,16 @@ again:
|
||||
spin_unlock(&parent->d_lock);
|
||||
goto again;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (parent != dentry)
|
||||
if (parent != dentry) {
|
||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
else
|
||||
if (unlikely(dentry->d_lockref.count < 0)) {
|
||||
spin_unlock(&parent->d_lock);
|
||||
parent = NULL;
|
||||
}
|
||||
} else {
|
||||
parent = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
@@ -593,9 +593,10 @@ static int __nd_alloc_stack(struct nameidata *nd)
|
||||
static bool path_connected(const struct path *path)
|
||||
{
|
||||
struct vfsmount *mnt = path->mnt;
|
||||
struct super_block *sb = mnt->mnt_sb;
|
||||
|
||||
/* Only bind mounts can have disconnected paths */
|
||||
if (mnt->mnt_root == mnt->mnt_sb->s_root)
|
||||
/* Bind mounts and multi-root filesystems can have disconnected paths */
|
||||
if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
|
||||
return true;
|
||||
|
||||
return is_subdir(path->dentry, mnt->mnt_root);
|
||||
|
||||
@@ -2623,6 +2623,8 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
|
||||
/* initial superblock/root creation */
|
||||
mount_info->fill_super(s, mount_info);
|
||||
nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
|
||||
if (!(server->flags & NFS_MOUNT_UNSHARED))
|
||||
s->s_iflags |= SB_I_MULTIROOT;
|
||||
}
|
||||
|
||||
mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
|
||||
|
||||
@@ -1312,6 +1312,7 @@ extern int send_sigurg(struct fown_struct *fown);
|
||||
#define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */
|
||||
#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */
|
||||
#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */
|
||||
#define SB_I_MULTIROOT 0x00000008 /* Multiple roots to the dentry tree */
|
||||
|
||||
/* sb->s_iflags to limit user namespace mounts */
|
||||
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
|
||||
|
||||
@@ -501,6 +501,7 @@
|
||||
|
||||
#define ICH_HCR_EN (1 << 0)
|
||||
#define ICH_HCR_UIE (1 << 1)
|
||||
#define ICH_HCR_NPIE (1 << 3)
|
||||
#define ICH_HCR_TC (1 << 10)
|
||||
#define ICH_HCR_TALL0 (1 << 11)
|
||||
#define ICH_HCR_TALL1 (1 << 12)
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
|
||||
#define GICH_HCR_EN (1 << 0)
|
||||
#define GICH_HCR_UIE (1 << 1)
|
||||
#define GICH_HCR_NPIE (1 << 3)
|
||||
|
||||
#define GICH_LR_VIRTUALID (0x3ff << 0)
|
||||
#define GICH_LR_PHYSID_CPUID_SHIFT (10)
|
||||
|
||||
@@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
return -ENOMEM;
|
||||
_snd_pcm_hw_params_any(params);
|
||||
err = snd_pcm_hw_refine(substream, params);
|
||||
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
kfree(params);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto error;
|
||||
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
for (fmt = 0; fmt < 32; ++fmt) {
|
||||
if (snd_mask_test(format_mask, fmt)) {
|
||||
int f = snd_pcm_oss_format_to(fmt);
|
||||
@@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
formats |= f;
|
||||
}
|
||||
}
|
||||
return formats;
|
||||
|
||||
error:
|
||||
kfree(params);
|
||||
return err < 0 ? err : formats;
|
||||
}
|
||||
|
||||
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
|
||||
|
||||
@@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client)
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
snd_seq_delete_all_ports(client);
|
||||
snd_seq_queue_client_leave(client->number);
|
||||
spin_lock_irqsave(&clients_lock, flags);
|
||||
clienttablock[client->number] = 1;
|
||||
clienttab[client->number] = NULL;
|
||||
spin_unlock_irqrestore(&clients_lock, flags);
|
||||
snd_seq_delete_all_ports(client);
|
||||
snd_seq_queue_client_leave(client->number);
|
||||
snd_use_lock_sync(&client->use_lock);
|
||||
snd_seq_queue_client_termination(client->number);
|
||||
if (client->pool)
|
||||
|
||||
@@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
|
||||
if (f->cells > 0) {
|
||||
/* drain prioQ */
|
||||
while (f->cells > 0)
|
||||
snd_seq_cell_free(snd_seq_prioq_cell_out(f));
|
||||
snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));
|
||||
}
|
||||
|
||||
kfree(f);
|
||||
@@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return 1 if the current time >= event timestamp */
|
||||
static int event_is_ready(struct snd_seq_event *ev, void *current_time)
|
||||
{
|
||||
if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK)
|
||||
return snd_seq_compare_tick_time(current_time, &ev->time.tick);
|
||||
else
|
||||
return snd_seq_compare_real_time(current_time, &ev->time.time);
|
||||
}
|
||||
|
||||
/* dequeue cell from prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||
void *current_time)
|
||||
{
|
||||
struct snd_seq_event_cell *cell;
|
||||
unsigned long flags;
|
||||
@@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
|
||||
spin_lock_irqsave(&f->lock, flags);
|
||||
|
||||
cell = f->head;
|
||||
if (cell && current_time && !event_is_ready(&cell->event, current_time))
|
||||
cell = NULL;
|
||||
if (cell) {
|
||||
f->head = cell->next;
|
||||
|
||||
@@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
|
||||
return f->cells;
|
||||
}
|
||||
|
||||
|
||||
/* peek at cell at the head of the prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
|
||||
{
|
||||
if (f == NULL) {
|
||||
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
|
||||
return NULL;
|
||||
}
|
||||
return f->head;
|
||||
}
|
||||
|
||||
|
||||
static inline int prioq_match(struct snd_seq_event_cell *cell,
|
||||
int client, int timestamp)
|
||||
{
|
||||
|
||||
@@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);
|
||||
int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
|
||||
|
||||
/* dequeue cell from prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f);
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||
void *current_time);
|
||||
|
||||
/* return number of events available in prioq */
|
||||
int snd_seq_prioq_avail(struct snd_seq_prioq *f);
|
||||
|
||||
/* peek at cell at the head of the prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f);
|
||||
|
||||
/* client left queue */
|
||||
void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);
|
||||
|
||||
|
||||
@@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
||||
|
||||
__again:
|
||||
/* Process tick queue... */
|
||||
while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
|
||||
if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick,
|
||||
&cell->event.time.tick)) {
|
||||
cell = snd_seq_prioq_cell_out(q->tickq);
|
||||
if (cell)
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
} else {
|
||||
/* event remains in the queue */
|
||||
for (;;) {
|
||||
cell = snd_seq_prioq_cell_out(q->tickq,
|
||||
&q->timer->tick.cur_tick);
|
||||
if (!cell)
|
||||
break;
|
||||
}
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
}
|
||||
|
||||
|
||||
/* Process time queue... */
|
||||
while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
|
||||
if (snd_seq_compare_real_time(&q->timer->cur_time,
|
||||
&cell->event.time.time)) {
|
||||
cell = snd_seq_prioq_cell_out(q->timeq);
|
||||
if (cell)
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
} else {
|
||||
/* event remains in the queue */
|
||||
for (;;) {
|
||||
cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
|
||||
if (!cell)
|
||||
break;
|
||||
}
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
}
|
||||
|
||||
/* free lock */
|
||||
|
||||
@@ -181,11 +181,15 @@ static const struct kernel_param_ops param_ops_xint = {
|
||||
};
|
||||
#define param_check_xint param_check_int
|
||||
|
||||
static int power_save = -1;
|
||||
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
module_param(power_save, xint, 0644);
|
||||
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
|
||||
"(in second, 0 = disable).");
|
||||
|
||||
static bool pm_blacklist = true;
|
||||
module_param(pm_blacklist, bool, 0644);
|
||||
MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist");
|
||||
|
||||
/* reset the HD-audio controller in power save mode.
|
||||
* this may give more power-saving, but will take longer time to
|
||||
* wake up.
|
||||
@@ -2300,10 +2304,9 @@ static int azx_probe_continue(struct azx *chip)
|
||||
|
||||
val = power_save;
|
||||
#ifdef CONFIG_PM
|
||||
if (val == -1) {
|
||||
if (pm_blacklist) {
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
|
||||
if (q && val) {
|
||||
dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
|
||||
|
||||
@@ -95,6 +95,31 @@ asm (
|
||||
"int3\n\t"
|
||||
"vmcode_int80:\n\t"
|
||||
"int $0x80\n\t"
|
||||
"vmcode_popf_hlt:\n\t"
|
||||
"push %ax\n\t"
|
||||
"popf\n\t"
|
||||
"hlt\n\t"
|
||||
"vmcode_umip:\n\t"
|
||||
/* addressing via displacements */
|
||||
"smsw (2052)\n\t"
|
||||
"sidt (2054)\n\t"
|
||||
"sgdt (2060)\n\t"
|
||||
/* addressing via registers */
|
||||
"mov $2066, %bx\n\t"
|
||||
"smsw (%bx)\n\t"
|
||||
"mov $2068, %bx\n\t"
|
||||
"sidt (%bx)\n\t"
|
||||
"mov $2074, %bx\n\t"
|
||||
"sgdt (%bx)\n\t"
|
||||
/* register operands, only for smsw */
|
||||
"smsw %ax\n\t"
|
||||
"mov %ax, (2080)\n\t"
|
||||
"int3\n\t"
|
||||
"vmcode_umip_str:\n\t"
|
||||
"str %eax\n\t"
|
||||
"vmcode_umip_sldt:\n\t"
|
||||
"sldt %eax\n\t"
|
||||
"int3\n\t"
|
||||
".size vmcode, . - vmcode\n\t"
|
||||
"end_vmcode:\n\t"
|
||||
".code32\n\t"
|
||||
@@ -103,7 +128,8 @@ asm (
|
||||
|
||||
extern unsigned char vmcode[], end_vmcode[];
|
||||
extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[],
|
||||
vmcode_sti[], vmcode_int3[], vmcode_int80[];
|
||||
vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[],
|
||||
vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[];
|
||||
|
||||
/* Returns false if the test was skipped. */
|
||||
static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
|
||||
@@ -153,13 +179,75 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
|
||||
(VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) {
|
||||
printf("[OK]\tReturned correctly\n");
|
||||
} else {
|
||||
printf("[FAIL]\tIncorrect return reason\n");
|
||||
printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip);
|
||||
nerrs++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem)
|
||||
{
|
||||
struct table_desc {
|
||||
unsigned short limit;
|
||||
unsigned long base;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Initialize variables with arbitrary values */
|
||||
struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 };
|
||||
struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae };
|
||||
struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 };
|
||||
struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 };
|
||||
unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737;
|
||||
|
||||
/* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */
|
||||
do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests");
|
||||
|
||||
/* Results from displacement-only addressing */
|
||||
msw1 = *(unsigned short *)(test_mem + 2052);
|
||||
memcpy(&idt1, test_mem + 2054, sizeof(idt1));
|
||||
memcpy(&gdt1, test_mem + 2060, sizeof(gdt1));
|
||||
|
||||
/* Results from register-indirect addressing */
|
||||
msw2 = *(unsigned short *)(test_mem + 2066);
|
||||
memcpy(&idt2, test_mem + 2068, sizeof(idt2));
|
||||
memcpy(&gdt2, test_mem + 2074, sizeof(gdt2));
|
||||
|
||||
/* Results when using register operands */
|
||||
msw3 = *(unsigned short *)(test_mem + 2080);
|
||||
|
||||
printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
|
||||
printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
|
||||
idt1.limit, idt1.base);
|
||||
printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
|
||||
gdt1.limit, gdt1.base);
|
||||
|
||||
if (msw1 != msw2 || msw1 != msw3)
|
||||
printf("[FAIL]\tAll the results of SMSW should be the same.\n");
|
||||
else
|
||||
printf("[PASS]\tAll the results from SMSW are identical.\n");
|
||||
|
||||
if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
|
||||
printf("[FAIL]\tAll the results of SGDT should be the same.\n");
|
||||
else
|
||||
printf("[PASS]\tAll the results from SGDT are identical.\n");
|
||||
|
||||
if (memcmp(&idt1, &idt2, sizeof(idt1)))
|
||||
printf("[FAIL]\tAll the results of SIDT should be the same.\n");
|
||||
else
|
||||
printf("[PASS]\tAll the results from SIDT are identical.\n");
|
||||
|
||||
sethandler(SIGILL, sighandler, 0);
|
||||
do_test(vm86, vmcode_umip_str - vmcode, VM86_SIGNAL, 0,
|
||||
"STR instruction");
|
||||
clearhandler(SIGILL);
|
||||
|
||||
sethandler(SIGILL, sighandler, 0);
|
||||
do_test(vm86, vmcode_umip_sldt - vmcode, VM86_SIGNAL, 0,
|
||||
"SLDT instruction");
|
||||
clearhandler(SIGILL);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct vm86plus_struct v86;
|
||||
@@ -180,6 +268,9 @@ int main(void)
|
||||
v86.regs.ds = load_addr / 16;
|
||||
v86.regs.es = load_addr / 16;
|
||||
|
||||
/* Use the end of the page as our stack. */
|
||||
v86.regs.esp = 4096;
|
||||
|
||||
assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */
|
||||
|
||||
/* #BR -- should deliver SIG??? */
|
||||
@@ -211,6 +302,23 @@ int main(void)
|
||||
v86.regs.eflags &= ~X86_EFLAGS_IF;
|
||||
do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set");
|
||||
|
||||
/* POPF with VIP set but IF clear: should not trap */
|
||||
v86.regs.eflags = X86_EFLAGS_VIP;
|
||||
v86.regs.eax = 0;
|
||||
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear");
|
||||
|
||||
/* POPF with VIP set and IF set: should trap */
|
||||
v86.regs.eflags = X86_EFLAGS_VIP;
|
||||
v86.regs.eax = X86_EFLAGS_IF;
|
||||
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set");
|
||||
|
||||
/* POPF with VIP clear and IF set: should not trap */
|
||||
v86.regs.eflags = 0;
|
||||
v86.regs.eax = X86_EFLAGS_IF;
|
||||
do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set");
|
||||
|
||||
v86.regs.eflags = 0;
|
||||
|
||||
/* INT3 -- should cause #BP */
|
||||
do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3");
|
||||
|
||||
@@ -218,6 +326,9 @@ int main(void)
|
||||
v86.regs.eax = (unsigned int)-1;
|
||||
do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");
|
||||
|
||||
/* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
|
||||
do_umip_tests(&v86, addr);
|
||||
|
||||
/* Execute a null pointer */
|
||||
v86.regs.cs = 0;
|
||||
v86.regs.ss = 0;
|
||||
@@ -231,7 +342,7 @@ int main(void)
|
||||
clearhandler(SIGSEGV);
|
||||
|
||||
/* Make sure nothing explodes if we fork. */
|
||||
if (fork() > 0)
|
||||
if (fork() == 0)
|
||||
return 0;
|
||||
|
||||
return (nerrs == 0 ? 0 : 1);
|
||||
|
||||
@@ -602,7 +602,7 @@ int kvm_timer_hyp_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
kvm_info("virtual timer IRQ%d\n", host_vtimer_irq);
|
||||
kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
|
||||
"kvm/arm/timer:starting", kvm_timer_starting_cpu,
|
||||
|
||||
@@ -215,7 +215,8 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
||||
* are now visible to the system register interface.
|
||||
*/
|
||||
if (!cpu_if->vgic_sre) {
|
||||
dsb(st);
|
||||
dsb(sy);
|
||||
isb();
|
||||
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
|
||||
@@ -1760,9 +1760,9 @@ int kvm_mmu_init(void)
|
||||
*/
|
||||
BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
|
||||
|
||||
kvm_info("IDMAP page: %lx\n", hyp_idmap_start);
|
||||
kvm_info("HYP VA range: %lx:%lx\n",
|
||||
kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
|
||||
kvm_debug("IDMAP page: %lx\n", hyp_idmap_start);
|
||||
kvm_debug("HYP VA range: %lx:%lx\n",
|
||||
kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
|
||||
|
||||
if (hyp_idmap_start >= kern_hyp_va(PAGE_OFFSET) &&
|
||||
hyp_idmap_start < kern_hyp_va(~0UL) &&
|
||||
|
||||
@@ -37,6 +37,13 @@ void vgic_v2_init_lrs(void)
|
||||
vgic_v2_write_lr(i, 0);
|
||||
}
|
||||
|
||||
void vgic_v2_set_npie(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
|
||||
cpuif->vgic_hcr |= GICH_HCR_NPIE;
|
||||
}
|
||||
|
||||
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
@@ -63,7 +70,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;
|
||||
int lr;
|
||||
|
||||
cpuif->vgic_hcr &= ~GICH_HCR_UIE;
|
||||
cpuif->vgic_hcr &= ~(GICH_HCR_UIE | GICH_HCR_NPIE);
|
||||
|
||||
for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
|
||||
u32 val = cpuif->vgic_lr[lr];
|
||||
@@ -380,7 +387,7 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
|
||||
kvm_vgic_global_state.type = VGIC_V2;
|
||||
kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
|
||||
|
||||
kvm_info("vgic-v2@%llx\n", info->vctrl.start);
|
||||
kvm_debug("vgic-v2@%llx\n", info->vctrl.start);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
|
||||
@@ -25,6 +25,13 @@ static bool group0_trap;
|
||||
static bool group1_trap;
|
||||
static bool common_trap;
|
||||
|
||||
void vgic_v3_set_npie(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
||||
cpuif->vgic_hcr |= ICH_HCR_NPIE;
|
||||
}
|
||||
|
||||
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
@@ -45,7 +52,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
u32 model = vcpu->kvm->arch.vgic.vgic_model;
|
||||
int lr;
|
||||
|
||||
cpuif->vgic_hcr &= ~ICH_HCR_UIE;
|
||||
cpuif->vgic_hcr &= ~(ICH_HCR_UIE | ICH_HCR_NPIE);
|
||||
|
||||
for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
|
||||
u64 val = cpuif->vgic_lr[lr];
|
||||
|
||||
@@ -610,22 +610,37 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
|
||||
vgic_v3_set_underflow(vcpu);
|
||||
}
|
||||
|
||||
static inline void vgic_set_npie(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_set_npie(vcpu);
|
||||
else
|
||||
vgic_v3_set_npie(vcpu);
|
||||
}
|
||||
|
||||
/* Requires the ap_list_lock to be held. */
|
||||
static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
|
||||
static int compute_ap_list_depth(struct kvm_vcpu *vcpu,
|
||||
bool *multi_sgi)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_irq *irq;
|
||||
int count = 0;
|
||||
|
||||
*multi_sgi = false;
|
||||
|
||||
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
|
||||
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
spin_lock(&irq->irq_lock);
|
||||
/* GICv2 SGIs can count for more than one... */
|
||||
if (vgic_irq_is_sgi(irq->intid) && irq->source)
|
||||
count += hweight8(irq->source);
|
||||
else
|
||||
if (vgic_irq_is_sgi(irq->intid) && irq->source) {
|
||||
int w = hweight8(irq->source);
|
||||
|
||||
count += w;
|
||||
*multi_sgi |= (w > 1);
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
spin_unlock(&irq->irq_lock);
|
||||
}
|
||||
return count;
|
||||
@@ -636,28 +651,43 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_irq *irq;
|
||||
int count = 0;
|
||||
int count;
|
||||
bool npie = false;
|
||||
bool multi_sgi;
|
||||
u8 prio = 0xff;
|
||||
|
||||
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
|
||||
|
||||
if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
|
||||
count = compute_ap_list_depth(vcpu, &multi_sgi);
|
||||
if (count > kvm_vgic_global_state.nr_lr || multi_sgi)
|
||||
vgic_sort_ap_list(vcpu);
|
||||
|
||||
count = 0;
|
||||
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
spin_lock(&irq->irq_lock);
|
||||
|
||||
if (unlikely(vgic_target_oracle(irq) != vcpu))
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* If we get an SGI with multiple sources, try to get
|
||||
* them in all at once.
|
||||
* If we have multi-SGIs in the pipeline, we need to
|
||||
* guarantee that they are all seen before any IRQ of
|
||||
* lower priority. In that case, we need to filter out
|
||||
* these interrupts by exiting early. This is easy as
|
||||
* the AP list has been sorted already.
|
||||
*/
|
||||
do {
|
||||
vgic_populate_lr(vcpu, irq, count++);
|
||||
} while (irq->source && count < kvm_vgic_global_state.nr_lr);
|
||||
if (multi_sgi && irq->priority > prio) {
|
||||
spin_unlock(&irq->irq_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (likely(vgic_target_oracle(irq) == vcpu)) {
|
||||
vgic_populate_lr(vcpu, irq, count++);
|
||||
|
||||
if (irq->source) {
|
||||
npie = true;
|
||||
prio = irq->priority;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
spin_unlock(&irq->irq_lock);
|
||||
|
||||
if (count == kvm_vgic_global_state.nr_lr) {
|
||||
@@ -668,6 +698,9 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
if (npie)
|
||||
vgic_set_npie(vcpu);
|
||||
|
||||
vcpu->arch.vgic_cpu.used_lrs = count;
|
||||
|
||||
/* Nuke remaining LRs */
|
||||
|
||||
@@ -150,6 +150,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
|
||||
void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
|
||||
void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
|
||||
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
|
||||
void vgic_v2_set_npie(struct kvm_vcpu *vcpu);
|
||||
int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
|
||||
int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
|
||||
int offset, u32 *val);
|
||||
@@ -179,6 +180,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
|
||||
void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
|
||||
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_set_npie(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
|
||||
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
|
||||
void vgic_v3_enable(struct kvm_vcpu *vcpu);
|
||||
|
||||
Reference in New Issue
Block a user