arch/powerpc/kvm/book3s_64_vio.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kvm/book3s_64_vio.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kvm/book3s_64_vio.c
Extension
.c
Size
18946 bytes
Lines
797
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations kvm_spapr_tce_fops = {
	.mmap           = kvm_spapr_tce_mmap,
	.release	= kvm_spapr_tce_release,
};

int kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
				  struct kvm_create_spapr_tce_64 *args)
{
	struct kvmppc_spapr_tce_table *stt = NULL;
	struct kvmppc_spapr_tce_table *siter;
	struct mm_struct *mm = kvm->mm;
	unsigned long npages;
	int ret;

	if (!args->size || args->page_shift < 12 || args->page_shift > 34 ||
		(args->offset + args->size > (ULLONG_MAX >> args->page_shift)))
		return -EINVAL;

	npages = kvmppc_tce_pages(args->size);
	ret = account_locked_vm(mm, kvmppc_stt_pages(npages), true);
	if (ret)
		return ret;

	ret = -ENOMEM;
	stt = kzalloc_flex(*stt, pages, npages, GFP_KERNEL | __GFP_NOWARN);
	if (!stt)
		goto fail_acct;

	stt->liobn = args->liobn;
	stt->page_shift = args->page_shift;
	stt->offset = args->offset;
	stt->size = args->size;
	stt->kvm = kvm;
	mutex_init(&stt->alloc_lock);
	INIT_LIST_HEAD_RCU(&stt->iommu_tables);

	mutex_lock(&kvm->lock);

	/* Check this LIOBN hasn't been previously allocated */
	ret = 0;
	list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
		if (siter->liobn == args->liobn) {
			ret = -EBUSY;
			break;
		}
	}

	kvm_get_kvm(kvm);
	if (!ret)
		ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
				       stt, O_RDWR | O_CLOEXEC);

	if (ret >= 0)
		list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
	else
		kvm_put_kvm_no_destroy(kvm);

	mutex_unlock(&kvm->lock);

	if (ret >= 0)
		return ret;

	kfree(stt);
 fail_acct:
	account_locked_vm(mm, kvmppc_stt_pages(npages), false);
	return ret;
}

static long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce,
		unsigned long *ua)
{
	unsigned long gfn = tce >> PAGE_SHIFT;
	struct kvm_memory_slot *memslot;

	memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
	if (!memslot)
		return -EINVAL;

	*ua = __gfn_to_hva_memslot(memslot, gfn) |
		(tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE));

	return 0;
}

static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
		unsigned long tce)
{
	unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
	enum dma_data_direction dir = iommu_tce_direction(tce);
	struct kvmppc_spapr_tce_iommu_table *stit;

Annotation

Implementation Notes