diff options
Diffstat (limited to 'arch/arm/xen/p2m.c')
| -rw-r--r-- | arch/arm/xen/p2m.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c index e71eefa2e427..9da57a5b81c7 100644 --- a/arch/arm/xen/p2m.c +++ b/arch/arm/xen/p2m.c @@ -1,7 +1,8 @@ -#include <linux/bootmem.h> +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/memblock.h> #include <linux/gfp.h> #include <linux/export.h> -#include <linux/rwlock.h> +#include <linux/spinlock.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/dma-mapping.h> @@ -10,6 +11,7 @@ #include <xen/xen.h> #include <xen/interface/memory.h> +#include <xen/grant_table.h> #include <xen/page.h> #include <xen/swiotlb-xen.h> @@ -61,17 +63,19 @@ out: unsigned long __pfn_to_mfn(unsigned long pfn) { - struct rb_node *n = phys_to_mach.rb_node; + struct rb_node *n; struct xen_p2m_entry *entry; unsigned long irqflags; read_lock_irqsave(&p2m_lock, irqflags); + n = phys_to_mach.rb_node; while (n) { entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys); if (entry->pfn <= pfn && entry->pfn + entry->nr_pages > pfn) { + unsigned long mfn = entry->mfn + (pfn - entry->pfn); read_unlock_irqrestore(&p2m_lock, irqflags); - return entry->mfn + (pfn - entry->pfn); + return mfn; } if (pfn < entry->pfn) n = n->rb_left; @@ -91,15 +95,43 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, int i; for (i = 0; i < count; i++) { + struct gnttab_unmap_grant_ref unmap; + int rc; + if (map_ops[i].status) continue; - set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT, - map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT); + if (likely(set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT, + map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) + continue; + + /* + * Signal an error for this slot. This in turn requires + * immediate unmapping. + */ + map_ops[i].status = GNTST_general_error; + unmap.host_addr = map_ops[i].host_addr; + unmap.handle = map_ops[i].handle; + map_ops[i].handle = INVALID_GRANT_HANDLE; + if (map_ops[i].flags & GNTMAP_device_map) + unmap.dev_bus_addr = map_ops[i].dev_bus_addr; + else + unmap.dev_bus_addr = 0; + + /* + * Pre-populate the status field, to be recognizable in + * the log message below. + */ + unmap.status = 1; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + &unmap, 1); + if (rc || unmap.status != GNTST_okay) + pr_err_once("gnttab unmap failed: rc=%d st=%d\n", + rc, unmap.status); } return 0; } -EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping); int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, struct gnttab_unmap_grant_ref *kunmap_ops, @@ -114,7 +146,6 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, return 0; } -EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping); bool __set_phys_to_machine_multi(unsigned long pfn, unsigned long mfn, unsigned long nr_pages) @@ -122,10 +153,11 @@ bool __set_phys_to_machine_multi(unsigned long pfn, int rc; unsigned long irqflags; struct xen_p2m_entry *p2m_entry; - struct rb_node *n = phys_to_mach.rb_node; + struct rb_node *n; if (mfn == INVALID_P2M_ENTRY) { write_lock_irqsave(&p2m_lock, irqflags); + n = phys_to_mach.rb_node; while (n) { p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys); if (p2m_entry->pfn <= pfn && @@ -156,6 +188,7 @@ bool __set_phys_to_machine_multi(unsigned long pfn, rc = xen_add_phys_to_mach_entry(p2m_entry); if (rc < 0) { write_unlock_irqrestore(&p2m_lock, irqflags); + kfree(p2m_entry); return false; } write_unlock_irqrestore(&p2m_lock, irqflags); |
