Commit 750137ec authored by Michael Ellerman's avatar Michael Ellerman
Browse files

Merge branch 'fixes' into topic/ppc-kvm

Merge our fixes branch. In parciular this brings in the KVM TCE handling
fix, which is a prerequisite for a subsequent patch.
parents 1d1cd0f1 ee834849
Loading
Loading
Loading
Loading
+14 −15
Original line number Diff line number Diff line
@@ -615,8 +615,6 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
		return;
	}

	/* Conditionally hard-enable interrupts. */
	if (should_hard_irq_enable()) {
	/*
	 * Ensure a positive value is written to the decrementer, or
	 * else some CPUs will continue to take decrementer exceptions.
@@ -630,8 +628,9 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
	else
		set_dec(decrementer_max);

	/* Conditionally hard-enable interrupts. */
	if (should_hard_irq_enable())
		do_hard_irq_enable();
	}

#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC)
	if (atomic_read(&ppc_n_lost_interrupts) != 0)
+7 −2
Original line number Diff line number Diff line
@@ -22,12 +22,15 @@
.macro cvdso_call funct call_time=0
  .cfi_startproc
	PPC_STLU	r1, -PPC_MIN_STKFRM(r1)
  .cfi_adjust_cfa_offset PPC_MIN_STKFRM
	mflr		r0
  .cfi_register lr, r0
	PPC_STLU	r1, -PPC_MIN_STKFRM(r1)
  .cfi_adjust_cfa_offset PPC_MIN_STKFRM
	PPC_STL		r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
  .cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF
#ifdef __powerpc64__
	PPC_STL		r2, PPC_MIN_STKFRM + STK_GOT(r1)
  .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
#endif
	get_datapage	r5
	.ifeq	\call_time
@@ -39,13 +42,15 @@
	PPC_LL		r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
#ifdef __powerpc64__
	PPC_LL		r2, PPC_MIN_STKFRM + STK_GOT(r1)
  .cfi_restore r2
#endif
	.ifeq	\call_time
	cmpwi		r3, 0
	.endif
	mtlr		r0
  .cfi_restore lr
	addi		r1, r1, 2 * PPC_MIN_STKFRM
  .cfi_restore lr
  .cfi_def_cfa_offset 0
	crclr		so
	.ifeq	\call_time
	beqlr+
+21 −5
Original line number Diff line number Diff line
@@ -122,11 +122,27 @@

	/* 0x0 - 0xb */

	/* 'current->mm' needs to be in r4 */
	tophys(r4, r2)
	lwz	r4, MM(r4)
	tophys(r4, r4)
	/* This only clobbers r0, r3, r4 and r5 */
	/* switch_mmu_context() needs paging, let's enable it */
	mfmsr   r9
	ori     r11, r9, MSR_DR
	mtmsr   r11
	sync

	/* switch_mmu_context() clobbers r12, rescue it */
	SAVE_GPR(12, r1)

	/* Calling switch_mmu_context(<inv>, current->mm, <inv>); */
	lwz	r4, MM(r2)
	bl	switch_mmu_context

	/* restore r12 */
	REST_GPR(12, r1)

	/* Disable paging again */
	mfmsr   r9
	li      r6, MSR_DR
	andc    r9, r9, r6
	mtmsr	r9
	sync

.endm
+23 −22
Original line number Diff line number Diff line
@@ -420,13 +420,19 @@ static void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt,
	tbl[idx % TCES_PER_PAGE] = tce;
}

static void kvmppc_clear_tce(struct mm_struct *mm, struct iommu_table *tbl,
		unsigned long entry)
static void kvmppc_clear_tce(struct mm_struct *mm, struct kvmppc_spapr_tce_table *stt,
		struct iommu_table *tbl, unsigned long entry)
{
	unsigned long i;
	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
	unsigned long io_entry = entry << (stt->page_shift - tbl->it_page_shift);

	for (i = 0; i < subpages; ++i) {
		unsigned long hpa = 0;
		enum dma_data_direction dir = DMA_NONE;

	iommu_tce_xchg_no_kill(mm, tbl, entry, &hpa, &dir);
		iommu_tce_xchg_no_kill(mm, tbl, io_entry + i, &hpa, &dir);
	}
}

static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
@@ -485,6 +491,8 @@ static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
			break;
	}

	iommu_tce_kill(tbl, io_entry, subpages);

	return ret;
}

@@ -544,6 +552,8 @@ static long kvmppc_tce_iommu_map(struct kvm *kvm,
			break;
	}

	iommu_tce_kill(tbl, io_entry, subpages);

	return ret;
}

@@ -590,10 +600,9 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
			ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl,
					entry, ua, dir);

		iommu_tce_kill(stit->tbl, entry, 1);

		if (ret != H_SUCCESS) {
			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
			kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl, entry);
			goto unlock_exit;
		}
	}
@@ -669,13 +678,13 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
		 */
		if (get_user(tce, tces + i)) {
			ret = H_TOO_HARD;
			goto invalidate_exit;
			goto unlock_exit;
		}
		tce = be64_to_cpu(tce);

		if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua)) {
			ret = H_PARAMETER;
			goto invalidate_exit;
			goto unlock_exit;
		}

		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -684,19 +693,15 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
					iommu_tce_direction(tce));

			if (ret != H_SUCCESS) {
				kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl,
						entry);
				goto invalidate_exit;
				kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl,
						 entry + i);
				goto unlock_exit;
			}
		}

		kvmppc_tce_put(stt, entry + i, tce);
	}

invalidate_exit:
	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
		iommu_tce_kill(stit->tbl, entry, npages);

unlock_exit:
	srcu_read_unlock(&vcpu->kvm->srcu, idx);

@@ -735,20 +740,16 @@ long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
				continue;

			if (ret == H_TOO_HARD)
				goto invalidate_exit;
				return ret;

			WARN_ON_ONCE(1);
			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
			kvmppc_clear_tce(vcpu->kvm->mm, stt, stit->tbl, entry + i);
		}
	}

	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
		kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);

invalidate_exit:
	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
		iommu_tce_kill(stit->tbl, ioba >> stt->page_shift, npages);

	return ret;
}
EXPORT_SYMBOL_GPL(kvmppc_h_stuff_tce);
+22 −22
Original line number Diff line number Diff line
@@ -247,13 +247,19 @@ static void iommu_tce_kill_rm(struct iommu_table *tbl,
		tbl->it_ops->tce_kill(tbl, entry, pages, true);
}

static void kvmppc_rm_clear_tce(struct kvm *kvm, struct iommu_table *tbl,
		unsigned long entry)
static void kvmppc_rm_clear_tce(struct kvm *kvm, struct kvmppc_spapr_tce_table *stt,
		struct iommu_table *tbl, unsigned long entry)
{
	unsigned long i;
	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
	unsigned long io_entry = entry << (stt->page_shift - tbl->it_page_shift);

	for (i = 0; i < subpages; ++i) {
		unsigned long hpa = 0;
		enum dma_data_direction dir = DMA_NONE;

	iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, entry, &hpa, &dir);
		iommu_tce_xchg_no_kill_rm(kvm->mm, tbl, io_entry + i, &hpa, &dir);
	}
}

static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm,
@@ -316,6 +322,8 @@ static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
			break;
	}

	iommu_tce_kill_rm(tbl, io_entry, subpages);

	return ret;
}

@@ -379,6 +387,8 @@ static long kvmppc_rm_tce_iommu_map(struct kvm *kvm,
			break;
	}

	iommu_tce_kill_rm(tbl, io_entry, subpages);

	return ret;
}

@@ -420,10 +430,8 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
			ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
					stit->tbl, entry, ua, dir);

		iommu_tce_kill_rm(stit->tbl, entry, 1);

		if (ret != H_SUCCESS) {
			kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry);
			kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry);
			return ret;
		}
	}
@@ -561,7 +569,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
		ua = 0;
		if (kvmppc_rm_tce_to_ua(vcpu->kvm, tce, &ua)) {
			ret = H_PARAMETER;
			goto invalidate_exit;
			goto unlock_exit;
		}

		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
@@ -570,19 +578,15 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
					iommu_tce_direction(tce));

			if (ret != H_SUCCESS) {
				kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl,
						entry);
				goto invalidate_exit;
				kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl,
						entry + i);
				goto unlock_exit;
			}
		}

		kvmppc_rm_tce_put(stt, entry + i, tce);
	}

invalidate_exit:
	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
		iommu_tce_kill_rm(stit->tbl, entry, npages);

unlock_exit:
	if (!prereg)
		arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock);
@@ -620,20 +624,16 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
				continue;

			if (ret == H_TOO_HARD)
				goto invalidate_exit;
				return ret;

			WARN_ON_ONCE_RM(1);
			kvmppc_rm_clear_tce(vcpu->kvm, stit->tbl, entry);
			kvmppc_rm_clear_tce(vcpu->kvm, stt, stit->tbl, entry + i);
		}
	}

	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
		kvmppc_rm_tce_put(stt, ioba >> stt->page_shift, tce_value);

invalidate_exit:
	list_for_each_entry_lockless(stit, &stt->iommu_tables, next)
		iommu_tce_kill_rm(stit->tbl, ioba >> stt->page_shift, npages);

	return ret;
}

Loading