diff options
Diffstat (limited to 'drivers/xen/grant-table.c')
| -rw-r--r-- | drivers/xen/grant-table.c | 157 | 
1 files changed, 78 insertions, 79 deletions
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index c4d2298893b..eeba7544f0c 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -49,6 +49,7 @@  #include <xen/grant_table.h>  #include <xen/interface/memory.h>  #include <xen/hvc-console.h> +#include <xen/swiotlb-xen.h>  #include <asm/xen/hypercall.h>  #include <asm/xen/interface.h> @@ -61,12 +62,10 @@  static grant_ref_t **gnttab_list;  static unsigned int nr_grant_frames; -static unsigned int boot_max_nr_grant_frames;  static int gnttab_free_count;  static grant_ref_t gnttab_free_head;  static DEFINE_SPINLOCK(gnttab_list_lock); -unsigned long xen_hvm_resume_frames; -EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); +struct grant_frames xen_auto_xlat_grant_frames;  static union {  	struct grant_entry_v1 *v1; @@ -826,6 +825,11 @@ static unsigned int __max_nr_grant_frames(void)  unsigned int gnttab_max_grant_frames(void)  {  	unsigned int xen_max = __max_nr_grant_frames(); +	static unsigned int boot_max_nr_grant_frames; + +	/* First time, initialize it properly. */ +	if (!boot_max_nr_grant_frames) +		boot_max_nr_grant_frames = __max_nr_grant_frames();  	if (xen_max > boot_max_nr_grant_frames)  		return boot_max_nr_grant_frames; @@ -833,6 +837,51 @@ unsigned int gnttab_max_grant_frames(void)  }  EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); +int gnttab_setup_auto_xlat_frames(phys_addr_t addr) +{ +	xen_pfn_t *pfn; +	unsigned int max_nr_gframes = __max_nr_grant_frames(); +	unsigned int i; +	void *vaddr; + +	if (xen_auto_xlat_grant_frames.count) +		return -EINVAL; + +	vaddr = xen_remap(addr, PAGE_SIZE * max_nr_gframes); +	if (vaddr == NULL) { +		pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n", +			&addr); +		return -ENOMEM; +	} +	pfn = kcalloc(max_nr_gframes, sizeof(pfn[0]), GFP_KERNEL); +	if (!pfn) { +		xen_unmap(vaddr); +		return -ENOMEM; +	} +	for (i = 0; i < max_nr_gframes; i++) +		pfn[i] = PFN_DOWN(addr) + i; + +	xen_auto_xlat_grant_frames.vaddr = vaddr; +	xen_auto_xlat_grant_frames.pfn = pfn; +	xen_auto_xlat_grant_frames.count = max_nr_gframes; + +	return 0; +} +EXPORT_SYMBOL_GPL(gnttab_setup_auto_xlat_frames); + +void gnttab_free_auto_xlat_frames(void) +{ +	if (!xen_auto_xlat_grant_frames.count) +		return; +	kfree(xen_auto_xlat_grant_frames.pfn); +	xen_unmap(xen_auto_xlat_grant_frames.vaddr); + +	xen_auto_xlat_grant_frames.pfn = NULL; +	xen_auto_xlat_grant_frames.count = 0; +	xen_auto_xlat_grant_frames.vaddr = NULL; +} +EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames); +  /* Handling of paged out grant targets (GNTST_eagain) */  #define MAX_DELAY 256  static inline void @@ -884,9 +933,6 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,  		    struct page **pages, unsigned int count)  {  	int i, ret; -	bool lazy = false; -	pte_t *pte; -	unsigned long mfn;  	ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);  	if (ret) @@ -898,36 +944,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,  			gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i,  						&map_ops[i].status, __func__); -	if (xen_feature(XENFEAT_auto_translated_physmap)) -		return ret; - -	if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { -		arch_enter_lazy_mmu_mode(); -		lazy = true; -	} - -	for (i = 0; i < count; i++) { -		/* Do not add to override if the map failed. */ -		if (map_ops[i].status) -			continue; - -		if (map_ops[i].flags & GNTMAP_contains_pte) { -			pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + -				(map_ops[i].host_addr & ~PAGE_MASK)); -			mfn = pte_mfn(*pte); -		} else { -			mfn = PFN_DOWN(map_ops[i].dev_bus_addr); -		} -		ret = m2p_add_override(mfn, pages[i], kmap_ops ? -				       &kmap_ops[i] : NULL); -		if (ret) -			return ret; -	} - -	if (lazy) -		arch_leave_lazy_mmu_mode(); - -	return ret; +	return set_foreign_p2m_mapping(map_ops, kmap_ops, pages, count);  }  EXPORT_SYMBOL_GPL(gnttab_map_refs); @@ -935,32 +952,13 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,  		      struct gnttab_map_grant_ref *kmap_ops,  		      struct page **pages, unsigned int count)  { -	int i, ret; -	bool lazy = false; +	int ret;  	ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);  	if (ret)  		return ret; -	if (xen_feature(XENFEAT_auto_translated_physmap)) -		return ret; - -	if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { -		arch_enter_lazy_mmu_mode(); -		lazy = true; -	} - -	for (i = 0; i < count; i++) { -		ret = m2p_remove_override(pages[i], kmap_ops ? -				       &kmap_ops[i] : NULL); -		if (ret) -			return ret; -	} - -	if (lazy) -		arch_leave_lazy_mmu_mode(); - -	return ret; +	return clear_foreign_p2m_mapping(unmap_ops, kmap_ops, pages, count);  }  EXPORT_SYMBOL_GPL(gnttab_unmap_refs); @@ -1043,10 +1041,11 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)  	unsigned int nr_gframes = end_idx + 1;  	int rc; -	if (xen_hvm_domain()) { +	if (xen_feature(XENFEAT_auto_translated_physmap)) {  		struct xen_add_to_physmap xatp;  		unsigned int i = end_idx;  		rc = 0; +		BUG_ON(xen_auto_xlat_grant_frames.count < nr_gframes);  		/*  		 * Loop backwards, so that the first hypercall has the largest  		 * index, ensuring that the table will grow only once. @@ -1055,7 +1054,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)  			xatp.domid = DOMID_SELF;  			xatp.idx = i;  			xatp.space = XENMAPSPACE_grant_table; -			xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i; +			xatp.gpfn = xen_auto_xlat_grant_frames.pfn[i];  			rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);  			if (rc != 0) {  				pr_warn("grant table add_to_physmap failed, err=%d\n", @@ -1118,10 +1117,8 @@ static void gnttab_request_version(void)  	int rc;  	struct gnttab_set_version gsv; -	if (xen_hvm_domain()) -		gsv.version = 1; -	else -		gsv.version = 2; +	gsv.version = 1; +  	rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);  	if (rc == 0 && gsv.version == 2) {  		grant_table_version = 2; @@ -1152,21 +1149,15 @@ static int gnttab_setup(void)  	if (max_nr_gframes < nr_grant_frames)  		return -ENOSYS; -	if (xen_pv_domain()) -		return gnttab_map(0, nr_grant_frames - 1); - -	if (gnttab_shared.addr == NULL) { -		gnttab_shared.addr = xen_remap(xen_hvm_resume_frames, -						PAGE_SIZE * max_nr_gframes); +	if (xen_feature(XENFEAT_auto_translated_physmap) && gnttab_shared.addr == NULL) { +		gnttab_shared.addr = xen_auto_xlat_grant_frames.vaddr;  		if (gnttab_shared.addr == NULL) { -			pr_warn("Failed to ioremap gnttab share frames!\n"); +			pr_warn("gnttab share frames (addr=0x%08lx) is not mapped!\n", +				(unsigned long)xen_auto_xlat_grant_frames.vaddr);  			return -ENOMEM;  		}  	} - -	gnttab_map(0, nr_grant_frames - 1); - -	return 0; +	return gnttab_map(0, nr_grant_frames - 1);  }  int gnttab_resume(void) @@ -1177,7 +1168,8 @@ int gnttab_resume(void)  int gnttab_suspend(void)  { -	gnttab_interface->unmap_frames(); +	if (!xen_feature(XENFEAT_auto_translated_physmap)) +		gnttab_interface->unmap_frames();  	return 0;  } @@ -1203,19 +1195,20 @@ static int gnttab_expand(unsigned int req_entries)  int gnttab_init(void)  {  	int i; +	unsigned long max_nr_grant_frames;  	unsigned int max_nr_glist_frames, nr_glist_frames;  	unsigned int nr_init_grefs;  	int ret;  	gnttab_request_version(); +	max_nr_grant_frames = gnttab_max_grant_frames();  	nr_grant_frames = 1; -	boot_max_nr_grant_frames = __max_nr_grant_frames();  	/* Determine the maximum number of frames required for the  	 * grant reference free list on the current hypervisor.  	 */  	BUG_ON(grefs_per_grant_frame == 0); -	max_nr_glist_frames = (boot_max_nr_grant_frames * +	max_nr_glist_frames = (max_nr_grant_frames *  			       grefs_per_grant_frame / RPP);  	gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), @@ -1232,6 +1225,11 @@ int gnttab_init(void)  		}  	} +	ret = arch_gnttab_init(max_nr_grant_frames, +			       nr_status_frames(max_nr_grant_frames)); +	if (ret < 0) +		goto ini_nomem; +  	if (gnttab_setup() < 0) {  		ret = -ENODEV;  		goto ini_nomem; @@ -1268,5 +1266,6 @@ static int __gnttab_init(void)  	return gnttab_init();  } - -core_initcall(__gnttab_init); +/* Starts after core_initcall so that xen_pvh_gnttab_setup can be called + * beforehand to initialize xen_auto_xlat_grant_frames. */ +core_initcall_sync(__gnttab_init);  | 
