Commit 41ecf140 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-4.4-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from David Vrabel:

 - Improve balloon driver memory hotplug placement.

 - Use unpopulated hotplugged memory for foreign pages (if
   supported/enabled).

 - Support 64 KiB guest pages on arm64.

 - CPU hotplug support on arm/arm64.

* tag 'for-linus-4.4-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (44 commits)
  xen: fix the check of e_pfn in xen_find_pfn_range
  x86/xen: add reschedule point when mapping foreign GFNs
  xen/arm: don't try to re-register vcpu_info on cpu_hotplug.
  xen, cpu_hotplug: call device_offline instead of cpu_down
  xen/arm: Enable cpu_hotplug.c
  xenbus: Support multiple grants ring with 64KB
  xen/grant-table: Add an helper to iterate over a specific number of grants
  xen/xenbus: Rename *RING_PAGE* to *RING_GRANT*
  xen/arm: correct comment in enlighten.c
  xen/gntdev: use types from linux/types.h in userspace headers
  xen/gntalloc: use types from linux/types.h in userspace headers
  xen/balloon: Use the correct sizeof when declaring frame_list
  xen/swiotlb: Add support for 64KB page granularity
  xen/swiotlb: Pass addresses rather than frame numbers to xen_arch_need_swiotlb
  arm/xen: Add support for 64KB page granularity
  xen/privcmd: Add support for Linux 64KB page granularity
  net/xen-netback: Make it running on 64KB page granularity
  net/xen-netfront: Make it running on 64KB page granularity
  block/xen-blkback: Make it running on 64KB page granularity
  block/xen-blkfront: Make it running on 64KB page granularity
  ...
parents 2dc10ad8 abed7d07
...@@ -26,4 +26,14 @@ void __init xen_early_init(void); ...@@ -26,4 +26,14 @@ void __init xen_early_init(void);
static inline void xen_early_init(void) { return; } static inline void xen_early_init(void) { return; }
#endif #endif
#ifdef CONFIG_HOTPLUG_CPU
static inline void xen_arch_register_cpu(int num)
{
}
static inline void xen_arch_unregister_cpu(int num)
{
}
#endif
#endif /* _ASM_ARM_XEN_HYPERVISOR_H */ #endif /* _ASM_ARM_XEN_HYPERVISOR_H */
...@@ -35,11 +35,15 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page, ...@@ -35,11 +35,15 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
dma_addr_t dev_addr, unsigned long offset, size_t size, dma_addr_t dev_addr, unsigned long offset, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs) enum dma_data_direction dir, struct dma_attrs *attrs)
{ {
bool local = PFN_DOWN(dev_addr) == page_to_pfn(page); bool local = XEN_PFN_DOWN(dev_addr) == page_to_xen_pfn(page);
/* Dom0 is mapped 1:1, so if pfn == mfn the page is local otherwise /*
* is a foreign page grant-mapped in dom0. If the page is local we * Dom0 is mapped 1:1, while the Linux page can be spanned accross
* can safely call the native dma_ops function, otherwise we call * multiple Xen page, it's not possible to have a mix of local and
* the xen specific function. */ * foreign Xen page. So if the first xen_pfn == mfn the page is local
* otherwise it's a foreign page grant-mapped in dom0. If the page is
* local we can safely call the native dma_ops function, otherwise we
* call the xen specific function.
*/
if (local) if (local)
__generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs); __generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
else else
...@@ -51,10 +55,14 @@ static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, ...@@ -51,10 +55,14 @@ static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
struct dma_attrs *attrs) struct dma_attrs *attrs)
{ {
unsigned long pfn = PFN_DOWN(handle); unsigned long pfn = PFN_DOWN(handle);
/* Dom0 is mapped 1:1, so calling pfn_valid on a foreign mfn will /*
* always return false. If the page is local we can safely call the * Dom0 is mapped 1:1, while the Linux page can be spanned accross
* native dma_ops function, otherwise we call the xen specific * multiple Xen page, it's not possible to have a mix of local and
* function. */ * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a
* foreign mfn will always return false. If the page is local we can
* safely call the native dma_ops function, otherwise we call the xen
* specific function.
*/
if (pfn_valid(pfn)) { if (pfn_valid(pfn)) {
if (__generic_dma_ops(hwdev)->unmap_page) if (__generic_dma_ops(hwdev)->unmap_page)
__generic_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs); __generic_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs);
......
...@@ -13,9 +13,6 @@ ...@@ -13,9 +13,6 @@
#define phys_to_machine_mapping_valid(pfn) (1) #define phys_to_machine_mapping_valid(pfn) (1)
#define pte_mfn pte_pfn
#define mfn_pte pfn_pte
/* Xen machine address */ /* Xen machine address */
typedef struct xmaddr { typedef struct xmaddr {
phys_addr_t maddr; phys_addr_t maddr;
...@@ -31,6 +28,17 @@ typedef struct xpaddr { ...@@ -31,6 +28,17 @@ typedef struct xpaddr {
#define INVALID_P2M_ENTRY (~0UL) #define INVALID_P2M_ENTRY (~0UL)
/*
* The pseudo-physical frame (pfn) used in all the helpers is always based
* on Xen page granularity (i.e 4KB).
*
* A Linux page may be split across multiple non-contiguous Xen page so we
* have to keep track with frame based on 4KB page granularity.
*
* PV drivers should never make a direct usage of those helpers (particularly
* pfn_to_gfn and gfn_to_pfn).
*/
unsigned long __pfn_to_mfn(unsigned long pfn); unsigned long __pfn_to_mfn(unsigned long pfn);
extern struct rb_root phys_to_mach; extern struct rb_root phys_to_mach;
...@@ -67,8 +75,8 @@ static inline unsigned long bfn_to_pfn(unsigned long bfn) ...@@ -67,8 +75,8 @@ static inline unsigned long bfn_to_pfn(unsigned long bfn)
#define bfn_to_local_pfn(bfn) bfn_to_pfn(bfn) #define bfn_to_local_pfn(bfn) bfn_to_pfn(bfn)
/* VIRT <-> GUEST conversion */ /* VIRT <-> GUEST conversion */
#define virt_to_gfn(v) (pfn_to_gfn(virt_to_pfn(v))) #define virt_to_gfn(v) (pfn_to_gfn(virt_to_phys(v) >> XEN_PAGE_SHIFT))
#define gfn_to_virt(m) (__va(gfn_to_pfn(m) << PAGE_SHIFT)) #define gfn_to_virt(m) (__va(gfn_to_pfn(m) << XEN_PAGE_SHIFT))
/* Only used in PV code. But ARM guests are always HVM. */ /* Only used in PV code. But ARM guests are always HVM. */
static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr) static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
...@@ -107,8 +115,8 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) ...@@ -107,8 +115,8 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
#define xen_unmap(cookie) iounmap((cookie)) #define xen_unmap(cookie) iounmap((cookie))
bool xen_arch_need_swiotlb(struct device *dev, bool xen_arch_need_swiotlb(struct device *dev,
unsigned long pfn, phys_addr_t phys,
unsigned long bfn); dma_addr_t dev_addr);
unsigned long xen_get_swiotlb_free_pages(unsigned int order); unsigned long xen_get_swiotlb_free_pages(unsigned int order);
#endif /* _ASM_ARM_XEN_PAGE_H */ #endif /* _ASM_ARM_XEN_PAGE_H */
...@@ -86,16 +86,25 @@ static void xen_percpu_init(void) ...@@ -86,16 +86,25 @@ static void xen_percpu_init(void)
int err; int err;
int cpu = get_cpu(); int cpu = get_cpu();
/*
* VCPUOP_register_vcpu_info cannot be called twice for the same
* vcpu, so if vcpu_info is already registered, just get out. This
* can happen with cpu-hotplug.
*/
if (per_cpu(xen_vcpu, cpu) != NULL)
goto after_register_vcpu_info;
pr_info("Xen: initializing cpu%d\n", cpu); pr_info("Xen: initializing cpu%d\n", cpu);
vcpup = per_cpu_ptr(xen_vcpu_info, cpu); vcpup = per_cpu_ptr(xen_vcpu_info, cpu);
info.mfn = __pa(vcpup) >> PAGE_SHIFT; info.mfn = virt_to_gfn(vcpup);
info.offset = offset_in_page(vcpup); info.offset = xen_offset_in_page(vcpup);
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info); err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
BUG_ON(err); BUG_ON(err);
per_cpu(xen_vcpu, cpu) = vcpup; per_cpu(xen_vcpu, cpu) = vcpup;
after_register_vcpu_info:
enable_percpu_irq(xen_events_irq, 0); enable_percpu_irq(xen_events_irq, 0);
put_cpu(); put_cpu();
} }
...@@ -124,6 +133,9 @@ static int xen_cpu_notification(struct notifier_block *self, ...@@ -124,6 +133,9 @@ static int xen_cpu_notification(struct notifier_block *self,
case CPU_STARTING: case CPU_STARTING:
xen_percpu_init(); xen_percpu_init();
break; break;
case CPU_DYING:
disable_percpu_irq(xen_events_irq);
break;
default: default:
break; break;
} }
...@@ -213,7 +225,7 @@ static int __init xen_guest_init(void) ...@@ -213,7 +225,7 @@ static int __init xen_guest_init(void)
xatp.domid = DOMID_SELF; xatp.domid = DOMID_SELF;
xatp.idx = 0; xatp.idx = 0;
xatp.space = XENMAPSPACE_shared_info; xatp.space = XENMAPSPACE_shared_info;
xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; xatp.gpfn = virt_to_gfn(shared_info_page);
if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
BUG(); BUG();
...@@ -284,7 +296,7 @@ void xen_arch_resume(void) { } ...@@ -284,7 +296,7 @@ void xen_arch_resume(void) { }
void xen_arch_suspend(void) { } void xen_arch_suspend(void) { }
/* In the hypervisor.S file. */ /* In the hypercall.S file. */
EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op); EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op); EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_xen_version); EXPORT_SYMBOL_GPL(HYPERVISOR_xen_version);
......
...@@ -48,22 +48,22 @@ static void dma_cache_maint(dma_addr_t handle, unsigned long offset, ...@@ -48,22 +48,22 @@ static void dma_cache_maint(dma_addr_t handle, unsigned long offset,
size_t size, enum dma_data_direction dir, enum dma_cache_op op) size_t size, enum dma_data_direction dir, enum dma_cache_op op)
{ {
struct gnttab_cache_flush cflush; struct gnttab_cache_flush cflush;
unsigned long pfn; unsigned long xen_pfn;
size_t left = size; size_t left = size;
pfn = (handle >> PAGE_SHIFT) + offset / PAGE_SIZE; xen_pfn = (handle >> XEN_PAGE_SHIFT) + offset / XEN_PAGE_SIZE;
offset %= PAGE_SIZE; offset %= XEN_PAGE_SIZE;
do { do {
size_t len = left; size_t len = left;
/* buffers in highmem or foreign pages cannot cross page /* buffers in highmem or foreign pages cannot cross page
* boundaries */ * boundaries */
if (len + offset > PAGE_SIZE) if (len + offset > XEN_PAGE_SIZE)
len = PAGE_SIZE - offset; len = XEN_PAGE_SIZE - offset;
cflush.op = 0; cflush.op = 0;
cflush.a.dev_bus_addr = pfn << PAGE_SHIFT; cflush.a.dev_bus_addr = xen_pfn << XEN_PAGE_SHIFT;
cflush.offset = offset; cflush.offset = offset;
cflush.length = len; cflush.length = len;
...@@ -79,7 +79,7 @@ static void dma_cache_maint(dma_addr_t handle, unsigned long offset, ...@@ -79,7 +79,7 @@ static void dma_cache_maint(dma_addr_t handle, unsigned long offset,
HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1); HYPERVISOR_grant_table_op(GNTTABOP_cache_flush, &cflush, 1);
offset = 0; offset = 0;
pfn++; xen_pfn++;
left -= len; left -= len;
} while (left); } while (left);
} }
...@@ -138,10 +138,29 @@ void __xen_dma_sync_single_for_device(struct device *hwdev, ...@@ -138,10 +138,29 @@ void __xen_dma_sync_single_for_device(struct device *hwdev,
} }
bool xen_arch_need_swiotlb(struct device *dev, bool xen_arch_need_swiotlb(struct device *dev,
unsigned long pfn, phys_addr_t phys,
unsigned long bfn) dma_addr_t dev_addr)
{ {
return (!hypercall_cflush && (pfn != bfn) && !is_device_dma_coherent(dev)); unsigned int xen_pfn = XEN_PFN_DOWN(phys);
unsigned int bfn = XEN_PFN_DOWN(dev_addr);
/*
* The swiotlb buffer should be used if
* - Xen doesn't have the cache flush hypercall
* - The Linux page refers to foreign memory
* - The device doesn't support coherent DMA request
*
* The Linux page may be spanned acrros multiple Xen page, although
* it's not possible to have a mix of local and foreign Xen page.
* Furthermore, range_straddles_page_boundary is already checking
* if buffer is physically contiguous in the host RAM.
*
* Therefore we only need to check the first Xen page to know if we
* require a bounce buffer because the device doesn't support coherent
* memory and we are not able to flush the cache.
*/
return (!hypercall_cflush && (xen_pfn != bfn) &&
!is_device_dma_coherent(dev));
} }
int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
......
...@@ -93,8 +93,8 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, ...@@ -93,8 +93,8 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (map_ops[i].status) if (map_ops[i].status)
continue; continue;
set_phys_to_machine(map_ops[i].host_addr >> PAGE_SHIFT, set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
map_ops[i].dev_bus_addr >> PAGE_SHIFT); map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT);
} }
return 0; return 0;
...@@ -108,7 +108,7 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, ...@@ -108,7 +108,7 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
int i; int i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
set_phys_to_machine(unmap_ops[i].host_addr >> PAGE_SHIFT, set_phys_to_machine(unmap_ops[i].host_addr >> XEN_PAGE_SHIFT,
INVALID_P2M_ENTRY); INVALID_P2M_ENTRY);
} }
......
...@@ -57,4 +57,9 @@ static inline bool xen_x2apic_para_available(void) ...@@ -57,4 +57,9 @@ static inline bool xen_x2apic_para_available(void)
} }
#endif #endif
#ifdef CONFIG_HOTPLUG_CPU
void xen_arch_register_cpu(int num);
void xen_arch_unregister_cpu(int num);
#endif
#endif /* _ASM_X86_XEN_HYPERVISOR_H */ #endif /* _ASM_X86_XEN_HYPERVISOR_H */
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/grant_table.h> #include <xen/interface/grant_table.h>
#include <xen/features.h> #include <xen/features.h>
/* Xen machine address */ /* Xen machine address */
...@@ -43,6 +43,8 @@ extern unsigned long *xen_p2m_addr; ...@@ -43,6 +43,8 @@ extern unsigned long *xen_p2m_addr;
extern unsigned long xen_p2m_size; extern unsigned long xen_p2m_size;
extern unsigned long xen_max_p2m_pfn; extern unsigned long xen_max_p2m_pfn;
extern int xen_alloc_p2m_entry(unsigned long pfn);
extern unsigned long get_phys_to_machine(unsigned long pfn); extern unsigned long get_phys_to_machine(unsigned long pfn);
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
...@@ -296,8 +298,8 @@ void make_lowmem_page_readwrite(void *vaddr); ...@@ -296,8 +298,8 @@ void make_lowmem_page_readwrite(void *vaddr);
#define xen_unmap(cookie) iounmap((cookie)) #define xen_unmap(cookie) iounmap((cookie))
static inline bool xen_arch_need_swiotlb(struct device *dev, static inline bool xen_arch_need_swiotlb(struct device *dev,
unsigned long pfn, phys_addr_t phys,
unsigned long bfn) dma_addr_t dev_addr)
{ {
return false; return false;
} }
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#include <asm/mwait.h> #include <asm/mwait.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/cpu.h>
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -1899,3 +1900,17 @@ const struct hypervisor_x86 x86_hyper_xen = { ...@@ -1899,3 +1900,17 @@ const struct hypervisor_x86 x86_hyper_xen = {
.set_cpu_features = xen_set_cpu_features, .set_cpu_features = xen_set_cpu_features,
}; };
EXPORT_SYMBOL(x86_hyper_xen); EXPORT_SYMBOL(x86_hyper_xen);
#ifdef CONFIG_HOTPLUG_CPU
void xen_arch_register_cpu(int num)
{
arch_register_cpu(num);
}
EXPORT_SYMBOL(xen_arch_register_cpu);
void xen_arch_unregister_cpu(int num)
{
arch_unregister_cpu(num);
}
EXPORT_SYMBOL(xen_arch_unregister_cpu);
#endif
...@@ -133,7 +133,7 @@ static int __init xlated_setup_gnttab_pages(void) ...@@ -133,7 +133,7 @@ static int __init xlated_setup_gnttab_pages(void)
kfree(pages); kfree(pages);
return -ENOMEM; return -ENOMEM;
} }
rc = alloc_xenballooned_pages(nr_grant_frames, pages, 0 /* lowmem */); rc = alloc_xenballooned_pages(nr_grant_frames, pages);
if (rc) { if (rc) {
pr_warn("%s Couldn't balloon alloc %ld pfns rc:%d\n", __func__, pr_warn("%s Couldn't balloon alloc %ld pfns rc:%d\n", __func__,
nr_grant_frames, rc); nr_grant_frames, rc);
......
...@@ -2888,6 +2888,7 @@ static int do_remap_gfn(struct vm_area_struct *vma, ...@@ -2888,6 +2888,7 @@ static int do_remap_gfn(struct vm_area_struct *vma,
addr += range; addr += range;
if (err_ptr) if (err_ptr)
err_ptr += batch; err_ptr += batch;
cond_resched();
} }
out: out:
......
...@@ -530,7 +530,7 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *pte_pg) ...@@ -530,7 +530,7 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *pte_pg)
* the new pages are installed with cmpxchg; if we lose the race then * the new pages are installed with cmpxchg; if we lose the race then
* simply free the page we allocated and use the one that's there. * simply free the page we allocated and use the one that's there.
*/ */
static bool alloc_p2m(unsigned long pfn) int xen_alloc_p2m_entry(unsigned long pfn)
{ {
unsigned topidx; unsigned topidx;
unsigned long *top_mfn_p, *mid_mfn; unsigned long *top_mfn_p, *mid_mfn;
...@@ -540,6 +540,9 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -540,6 +540,9 @@ static bool alloc_p2m(unsigned long pfn)
unsigned long addr = (unsigned long)(xen_p2m_addr + pfn); unsigned long addr = (unsigned long)(xen_p2m_addr + pfn);
unsigned long p2m_pfn; unsigned long p2m_pfn;
if (xen_feature(XENFEAT_auto_translated_physmap))
return 0;
ptep = lookup_address(addr, &level); ptep = lookup_address(addr, &level);
BUG_ON(!ptep || level != PG_LEVEL_4K); BUG_ON(!ptep || level != PG_LEVEL_4K);
pte_pg = (pte_t *)((unsigned long)ptep & ~(PAGE_SIZE - 1)); pte_pg = (pte_t *)((unsigned long)ptep & ~(PAGE_SIZE - 1));
...@@ -548,7 +551,7 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -548,7 +551,7 @@ static bool alloc_p2m(unsigned long pfn)
/* PMD level is missing, allocate a new one */ /* PMD level is missing, allocate a new one */
ptep = alloc_p2m_pmd(addr, pte_pg); ptep = alloc_p2m_pmd(addr, pte_pg);
if (!ptep) if (!ptep)
return false; return -ENOMEM;
} }
if (p2m_top_mfn && pfn < MAX_P2M_PFN) { if (p2m_top_mfn && pfn < MAX_P2M_PFN) {
...@@ -566,7 +569,7 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -566,7 +569,7 @@ static bool alloc_p2m(unsigned long pfn)
mid_mfn = alloc_p2m_page(); mid_mfn = alloc_p2m_page();
if (!mid_mfn) if (!mid_mfn)
return false; return -ENOMEM;
p2m_mid_mfn_init(mid_mfn, p2m_missing); p2m_mid_mfn_init(mid_mfn, p2m_missing);
...@@ -592,7 +595,7 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -592,7 +595,7 @@ static bool alloc_p2m(unsigned long pfn)
p2m = alloc_p2m_page(); p2m = alloc_p2m_page();
if (!p2m) if (!p2m)
return false; return -ENOMEM;
if (p2m_pfn == PFN_DOWN(__pa(p2m_missing))) if (p2m_pfn == PFN_DOWN(__pa(p2m_missing)))
p2m_init(p2m); p2m_init(p2m);
...@@ -625,8 +628,9 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -625,8 +628,9 @@ static bool alloc_p2m(unsigned long pfn)
HYPERVISOR_shared_info->arch.max_pfn = xen_p2m_last_pfn; HYPERVISOR_shared_info->arch.max_pfn = xen_p2m_last_pfn;
} }
return true; return 0;
} }
EXPORT_SYMBOL(xen_alloc_p2m_entry);
unsigned long __init set_phys_range_identity(unsigned long pfn_s, unsigned long __init set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e) unsigned long pfn_e)
...@@ -688,7 +692,10 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn) ...@@ -688,7 +692,10 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{ {
if (unlikely(!__set_phys_to_machine(pfn, mfn))) { if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
if (!alloc_p2m(pfn)) int ret;
ret = xen_alloc_p2m_entry(pfn);
if (ret < 0)
return false; return false;
return __set_phys_to_machine(pfn, mfn); return __set_phys_to_machine(pfn, mfn);
......
...@@ -212,7 +212,7 @@ static unsigned long __init xen_find_pfn_range(unsigned long *min_pfn) ...@@ -212,7 +212,7 @@ static unsigned long __init xen_find_pfn_range(unsigned long *min_pfn)
e_pfn = PFN_DOWN(entry->addr + entry->size); e_pfn = PFN_DOWN(entry->addr + entry->size);
/* We only care about E820 after this */ /* We only care about E820 after this */
if (e_pfn < *min_pfn) if (e_pfn <= *min_pfn)
continue; continue;
s_pfn = PFN_UP(entry->addr); s_pfn = PFN_UP(entry->addr);
...@@ -829,6 +829,8 @@ char * __init xen_memory_setup(void) ...@@ -829,6 +829,8 @@ char * __init xen_memory_setup(void)
addr = xen_e820_map[0].addr; addr = xen_e820_map[0].addr;
size = xen_e820_map[0].size; size = xen_e820_map[0].size;
while (i < xen_e820_map_entries) { while (i < xen_e820_map_entries) {
bool discard = false;
chunk_size = size; chunk_size = size;
type = xen_e820_map[i].type; type = xen_e820_map[i].type;
...@@ -843,10 +845,11 @@ char * __init xen_memory_setup(void) ...@@ -843,10 +845,11 @@ char * __init xen_memory_setup(void)
xen_add_extra_mem(pfn_s, n_pfns); xen_add_extra_mem(pfn_s, n_pfns);
xen_max_p2m_pfn = pfn_s + n_pfns; xen_max_p2m_pfn = pfn_s + n_pfns;
} else } else
type = E820_UNUSABLE; discard = true;
} }
xen_align_and_add_e820_region(addr, chunk_size, type); if (!discard)
xen_align_and_add_e820_region(addr, chunk_size, type);
addr += chunk_size; addr += chunk_size;
size -= chunk_size; size -= chunk_size;
......
...@@ -87,7 +87,7 @@ MODULE_PARM_DESC(max_persistent_grants, ...@@ -87,7 +87,7 @@ MODULE_PARM_DESC(max_persistent_grants,
* Maximum order of pages to be used for the shared ring between front and * Maximum order of pages to be used for the shared ring between front and
* backend, 4KB page granularity is used. * backend, 4KB page granularity is used.
*/ */
unsigned int xen_blkif_max_ring_order = XENBUS_MAX_RING_PAGE_ORDER; unsigned int xen_blkif_max_ring_order = XENBUS_MAX_RING_GRANT_ORDER;
module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, S_IRUGO); module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, S_IRUGO);
MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring"); MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring");
/* /*
...@@ -961,7 +961,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req, ...@@ -961,7 +961,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
seg[n].nsec = segments[i].last_sect - seg[n].nsec = segments[i].last_sect -
segments[i].first_sect + 1; segments[i].first_sect + 1;
seg[n].offset = (segments[i].first_sect << 9); seg[n].offset = (segments[i].first_sect << 9);
if ((segments[i].last_sect >= (PAGE_SIZE >> 9)) || if ((segments[i].last_sect >= (XEN_PAGE_SIZE >> 9)) ||
(segments[i].last_sect < segments[i].first_sect)) { (segments[i].last_sect < segments[i].first_sect)) {
rc = -EINVAL; rc = -EINVAL;
goto unmap; goto unmap;
...@@ -1210,6 +1210,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, ...@@ -1210,6 +1210,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
req_operation = req->operation == BLKIF_OP_INDIRECT ? req_operation = req->operation == BLKIF_OP_INDIRECT ?
req->u.indirect.indirect_op : req->operation; req->u.indirect.indirect_op : req->operation;
if ((req->operation == BLKIF_OP_INDIRECT) && if ((req->operation == BLKIF_OP_INDIRECT) &&
(req_operation != BLKIF_OP_READ) && (req_operation != BLKIF_OP_READ) &&
(req_operation != BLKIF_OP_WRITE)) { (req_operation != BLKIF_OP_WRITE)) {
...@@ -1268,7 +1269,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, ...@@ -1268,7 +1269,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
seg[i].nsec = req->u.rw.seg[i].last_sect - seg[i].nsec = req->u.rw.seg[i].last_sect -
req->u.rw.seg[i].first_sect + 1; req->u.rw.seg[i].first_sect + 1;
seg[i].offset = (req->u.rw.seg[i].first_sect << 9); seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) || if ((req->u.rw.seg[i].last_sect >= (XEN_PAGE_SIZE >> 9)) ||
(req->u.rw.seg[i].last_sect < (req->u.rw.seg[i].last_sect <
req->u.rw.seg[i].first_sect)) req->u.rw.seg[i].first_sect))
goto fail_response; goto fail_response;
...@@ -1445,10 +1446,10 @@ static int __init xen_blkif_init(void) ...@@ -1445,10 +1446,10 @@ static int __init xen_blkif_init(void)
if (!xen_domain()) if (!xen_domain())
return -ENODEV; return -ENODEV;
if (xen_blkif_max_ring_order > XENBUS_MAX_RING_PAGE_ORDER) { if (xen_blkif_max_ring_order > XENBUS_MAX_RING_GRANT_ORDER) {
pr_info("Invalid max_ring_order (%d), will use default max: %d.\n", pr_info("Invalid max_ring_order (%d), will use default max: %d.\n",
xen_blkif_max_ring_order, XENBUS_MAX_RING_PAGE_ORDER); xen_blkif_max_ring_order, XENBUS_MAX_RING_GRANT_ORDER);
xen_blkif_max_ring_order = XENBUS_MAX_RING_PAGE_ORDER; xen_blkif_max_ring_order = XENBUS_MAX_RING_GRANT_ORDER;
} }
rc = xen_blkif_interface_init(); rc = xen_blkif_interface_init();
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/hypervisor.h> #include <asm/hypervisor.h>
#include <xen/grant_table.h> #include <xen/grant_table.h>
#include <xen/page.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/interface/io/ring.h> #include <xen/interface/io/ring.h>
#include <xen/interface/io/blkif.h> #include <xen/interface/io/blkif.h>
...@@ -51,12 +52,20 @@ extern unsigned int xen_blkif_max_ring_order; ...@@ -51,12 +52,20 @@ extern unsigned int xen_blkif_max_ring_order;
*/ */
#define MAX_INDIRECT_SEGMENTS 256 #define MAX_INDIRECT_SEGMENTS 256
#define SEGS_PER_INDIRECT_FRAME \ /*
(PAGE_SIZE/sizeof(struct blkif_request_segment)) * Xen use 4K pages. The guest may use different page size (4K or 64K)
* Number of Xen pages per segment
*/
#define XEN_PAGES_PER_SEGMENT (PAGE_SIZE / XEN_PAGE_SIZE)
#define XEN_PAGES_PER_INDIRECT_FRAME \
(XEN_PAGE_SIZE/sizeof(struct blkif_request_segment))
#define SEGS_PER_INDIRECT_FRAME \
(XEN_PAGES_PER_INDIRECT_FRAME / XEN_PAGES_PER_SEGMENT)
#define MAX_INDIRECT_PAGES \ #define MAX_INDIRECT_PAGES \
((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
#define INDIRECT_PAGES(_segs) \ #define INDIRECT_PAGES(_segs) DIV_ROUND_UP(_segs, XEN_PAGES_PER_INDIRECT_FRAME)
((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
/* Not a real protocol. Used to generate ring structs which contain /* Not a real protocol. Used to generate ring structs which contain
* the elements common to all protocols only. This way we get a * the elements common to all protocols only. This way we get a
......
...@@ -176,21 +176,24 @@ static int xen_blkif_map(struct xen_blkif *blkif, grant_ref_t *gref, ...@@ -176,21 +176,24 @@ static int xen_blkif_map(struct xen_blkif *blkif, grant_ref_t *gref,
{ {
struct blkif_sring *sring; struct blkif_sring *sring;
sring = (struct blkif_sring *)blkif->blk_ring; sring = (struct blkif_sring *)blkif->blk_ring;
BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE * nr_grefs); BACK_RING_INIT(&blkif->blk_rings.native, sring,
XEN_PAGE_SIZE * nr_grefs);
break; break;
} }
case BLKIF_PROTOCOL_X86_32: case BLKIF_PROTOCOL_X86_32:
{ {
struct blkif_x86_32_sring *sring_x86_32; struct blkif_x86_32_sring *sring_x86_32;
sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring; sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring;
BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE * nr_grefs); BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32,
XEN_PAGE_SIZE * nr_grefs);
break; break;
} }
case BLKIF_PROTOCOL_X86_64: case BLKIF_PROTOCOL_X86_64:
{ {
struct blkif_x86_64_sring *sring_x86_64; struct blkif_x86_64_sring *sring_x86_64;
sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring; sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring;
BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE * nr_grefs); BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64,
XEN_PAGE_SIZE * nr_grefs);
break; break;
} }
default: default:
...@@ -826,7 +829,7 @@ static void connect(struct backend_info *be) ...@@ -826,7 +829,7 @@ static void connect(struct backend_info *be)
static int connect_ring(struct backend_info *be) static int connect_ring(struct backend_info *be)
{ {
struct xenbus_device *dev = be->dev; struct xenbus_device *dev = be->dev;
unsigned int ring_ref[XENBUS_MAX_RING_PAGES]; unsigned int ring_ref[XENBUS_MAX_RING_GRANTS];
unsigned int evtchn, nr_grefs, ring_page_order; unsigned int evtchn, nr_grefs, ring_page_order;
unsigned int pers_grants; unsigned int pers_grants;
char protocol[64] = ""; char protocol[64] = "";
......
This diff is collapsed.
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <xen/interface/grant_table.h> #include <xen/interface/grant_table.h>
#include <xen/grant_table.h> #include <xen/grant_table.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/page.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
typedef unsigned int pending_ring_idx_t; typedef unsigned int pending_ring_idx_t;
...@@ -64,8 +65,8 @@ struct pending_tx_info { ...@@ -64,8 +65,8 @@ struct pending_tx_info {
struct ubuf_info callback_struct; struct ubuf_info callback_struct;
}; };
#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE)
#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) #define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE)
struct xenvif_rx_meta { struct xenvif_rx_meta {
int id; int id;
...@@ -80,16 +81,21 @@ struct xenvif_rx_meta { ...@@ -80,16 +81,21 @@ struct xenvif_rx_meta {
/* Discriminate from any valid pending_idx value. */ /* Discriminate from any valid pending_idx value. */
#define INVALID_PENDING_IDX 0xFFFF #define INVALID_PENDING_IDX 0xFFFF
#define MAX_BUFFER_OFFSET PAGE_SIZE #define MAX_BUFFER_OFFSET XEN_PAGE_SIZE
#define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE #define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE
/* The maximum number of frags is derived from the size of a grant (same
* as a Xen page size for now).
*/
#define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
/* It's possible for an skb to have a maximal number of frags /* It's possible for an skb to have a maximal number of frags
* but still be less than MAX_BUFFER_OFFSET in size. Thus the * but still be less than MAX_BUFFER_OFFSET in size. Thus the
* worst-case number of copy operations is MAX_SKB_FRAGS per * worst-case number of copy operations is MAX_XEN_SKB_FRAGS per
* ring slot. * ring slot.
*/ */
#define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) #define MAX_GRANT_COPY_OPS (MAX_XEN_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
#define NETBACK_INVALID_HANDLE -1 #define NETBACK_INVALID_HANDLE -1
......
...@@ -152,9 +152,9 @@ static inline pending_ring_idx_t pending_index(unsigned i) ...@@ -152,9 +152,9 @@ static inline pending_ring_idx_t pending_index(unsigned i)
static int xenvif_rx_ring_slots_needed(struct xenvif *vif) static int xenvif_rx_ring_slots_needed(struct xenvif *vif)
{ {
if (vif->gso_mask) if (vif->gso_mask)
return DIV_ROUND_UP(vif->dev->gso_max_size, PAGE_SIZE) + 1; return DIV_ROUND_UP(vif->dev->gso_max_size, XEN_PAGE_SIZE) + 1;
else else
return DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); return DIV_ROUND_UP(vif->dev->mtu, XEN_PAGE_SIZE);
} }
static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue) static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue)
...@@ -274,6 +274,80 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue, ...@@ -274,6 +274,80 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
return meta; return meta;
} }
struct gop_frag_copy {
struct xenvif_queue *queue;
struct netrx_pending_operations *npo;
struct xenvif_rx_meta *meta;
int head;
int gso_type;
struct page *page;
};
static void xenvif_setup_copy_gop(unsigned long gfn,
unsigned int offset,
unsigned int *len,
struct gop_frag_copy *info)
{
struct gnttab_copy *copy_gop;
struct xen_page_foreign *foreign;
/* Convenient aliases */
struct xenvif_queue *queue = info->queue;
struct netrx_pending_operations *npo = info->npo;
struct page *page = info->page;
BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
if (npo->copy_off == MAX_BUFFER_OFFSET)
info->meta = get_next_rx_buffer(queue, npo);
if (npo->copy_off + *len > MAX_BUFFER_OFFSET)
*len = MAX_BUFFER_OFFSET - npo->copy_off;
copy_gop = npo->copy + npo->copy_prod++;
copy_gop->flags = GNTCOPY_dest_gref;
copy_gop->len = *len;
foreign = xen_page_foreign(page);
if (foreign) {
copy_gop->source.domid = foreign->domid;
copy_gop->source.u.ref = foreign->gref;
copy_gop->flags |= GNTCOPY_source_gref;
} else {
copy_gop->source.domid = DOMID_SELF;
copy_gop->source.u.gmfn = gfn;
}
copy_gop->source.offset = offset;
copy_gop->dest.domid = queue->vif->domid;
copy_gop->dest.offset = npo->copy_off;
copy_gop->dest.u.ref = npo->copy_gref;
npo->copy_off += *len;
info->meta->size += *len;
/* Leave a gap for the GSO descriptor. */
if (info->head && ((1 << info->gso_type) & queue->vif->gso_mask))
queue->rx.req_cons++;
info->head = 0; /* There must be something in this buffer now */
}
static void xenvif_gop_frag_copy_grant(unsigned long gfn,
unsigned offset,
unsigned int len,
void *data)
{
unsigned int bytes;
while (len) {
bytes = len;
xenvif_setup_copy_gop(gfn, offset, &bytes, data);
offset += bytes;
len -= bytes;
}
}
/* /*
* Set up the grant operations for this fragment. If it's a flipping * Set up the grant operations for this fragment. If it's a flipping
* interface, we also set up the unmap request from here. * interface, we also set up the unmap request from here.
...@@ -283,83 +357,52 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb ...@@ -283,83 +357,52 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
struct page *page, unsigned long size, struct page *page, unsigned long size,
unsigned long offset, int *head) unsigned long offset, int *head)
{ {
struct gnttab_copy *copy_gop; struct gop_frag_copy info = {
struct xenvif_rx_meta *meta; .queue = queue,
.npo = npo,
.head = *head,
.gso_type = XEN_NETIF_GSO_TYPE_NONE,
};
unsigned long bytes; unsigned long bytes;
int gso_type = XEN_NETIF_GSO_TYPE_NONE;
if (skb_is_gso(skb)) {
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
info.gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
info.gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
}
/* Data must not cross a page boundary. */ /* Data must not cross a page boundary. */
BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
meta = npo->meta + npo->meta_prod - 1; info.meta = npo->meta + npo->meta_prod - 1;
/* Skip unused frames from start of page */ /* Skip unused frames from start of page */
page += offset >> PAGE_SHIFT; page += offset >> PAGE_SHIFT;
offset &= ~PAGE_MASK; offset &= ~PAGE_MASK;
while (size > 0) { while (size > 0) {
struct xen_page_foreign *foreign;
BUG_ON(offset >= PAGE_SIZE); BUG_ON(offset >= PAGE_SIZE);
BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
if (npo->copy_off == MAX_BUFFER_OFFSET)
meta = get_next_rx_buffer(queue, npo);
bytes = PAGE_SIZE - offset; bytes = PAGE_SIZE - offset;
if (bytes > size) if (bytes > size)
bytes = size; bytes = size;
if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) info.page = page;
bytes = MAX_BUFFER_OFFSET - npo->copy_off; gnttab_foreach_grant_in_range(page, offset, bytes,
xenvif_gop_frag_copy_grant,
copy_gop = npo->copy + npo->copy_prod++; &info);
copy_gop->flags = GNTCOPY_dest_gref;
copy_gop->len = bytes;
foreign = xen_page_foreign(page);
if (foreign) {
copy_gop->source.domid = foreign->domid;
copy_gop->source.u.ref = foreign->gref;
copy_gop->flags |= GNTCOPY_source_gref;
} else {
copy_gop->source.domid = DOMID_SELF;
copy_gop->source.u.gmfn =
virt_to_gfn(page_address(page));
}
copy_gop->source.offset = offset;
copy_gop->dest.domid = queue->vif->domid;
copy_gop->dest.offset = npo->copy_off;
copy_gop->dest.u.ref = npo->copy_gref;
npo->copy_off += bytes;
meta->size += bytes;
offset += bytes;
size -= bytes; size -= bytes;
offset = 0;
/* Next frame */ /* Next page */
if (offset == PAGE_SIZE && size) { if (size) {
BUG_ON(!PageCompound(page)); BUG_ON(!PageCompound(page));
page++; page++;
offset = 0;
} }
/* Leave a gap for the GSO descriptor. */
if (skb_is_gso(skb)) {
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
}
if (*head && ((1 << gso_type) & queue->vif->gso_mask))
queue->rx.req_cons++;
*head = 0; /* There must be something in this buffer now. */
} }
*head = info.head;
} }
/* /*
...@@ -758,7 +801,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue, ...@@ -758,7 +801,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
first->size -= txp->size; first->size -= txp->size;
slots++; slots++;
if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { if (unlikely((txp->offset + txp->size) > XEN_PAGE_SIZE)) {
netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n", netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n",
txp->offset, txp->size); txp->offset, txp->size);
xenvif_fatal_tx_err(queue->vif); xenvif_fatal_tx_err(queue->vif);
...@@ -1339,11 +1382,11 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, ...@@ -1339,11 +1382,11 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
} }
/* No crossing a page as the payload mustn't fragment. */ /* No crossing a page as the payload mustn't fragment. */
if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) {
netdev_err(queue->vif->dev, netdev_err(queue->vif->dev,
"txreq.offset: %u, size: %u, end: %lu\n", "txreq.offset: %u, size: %u, end: %lu\n",
txreq.offset, txreq.size, txreq.offset, txreq.size,
(unsigned long)(txreq.offset&~PAGE_MASK) + txreq.size); (unsigned long)(txreq.offset&~XEN_PAGE_MASK) + txreq.size);
xenvif_fatal_tx_err(queue->vif); xenvif_fatal_tx_err(queue->vif);
break; break;
} }
...@@ -1409,7 +1452,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, ...@@ -1409,7 +1452,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
virt_to_gfn(skb->data); virt_to_gfn(skb->data);
queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF; queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF;
queue->tx_copy_ops[*copy_ops].dest.offset = queue->tx_copy_ops[*copy_ops].dest.offset =
offset_in_page(skb->data); offset_in_page(skb->data) & ~XEN_PAGE_MASK;
queue->tx_copy_ops[*copy_ops].len = data_len; queue->tx_copy_ops[*copy_ops].len = data_len;
queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref; queue->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref;
...@@ -1894,7 +1937,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, ...@@ -1894,7 +1937,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
goto err; goto err;
txs = (struct xen_netif_tx_sring *)addr; txs = (struct xen_netif_tx_sring *)addr;
BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); BACK_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
&rx_ring_ref, 1, &addr); &rx_ring_ref, 1, &addr);
...@@ -1902,7 +1945,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, ...@@ -1902,7 +1945,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
goto err; goto err;
rxs = (struct xen_netif_rx_sring *)addr; rxs = (struct xen_netif_rx_sring *)addr;
BACK_RING_INIT(&queue->rx, rxs, PAGE_SIZE); BACK_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
return 0; return 0;
......
...@@ -74,8 +74,8 @@ struct netfront_cb { ...@@ -74,8 +74,8 @@ struct netfront_cb {
#define GRANT_INVALID_REF 0 #define GRANT_INVALID_REF 0
#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) #define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE)
#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) #define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE)
/* Minimum number of Rx slots (includes slot for GSO metadata). */ /* Minimum number of Rx slots (includes slot for GSO metadata). */
#define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1) #define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1)
...@@ -291,7 +291,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) ...@@ -291,7 +291,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
struct sk_buff *skb; struct sk_buff *skb;
unsigned short id; unsigned short id;
grant_ref_t ref; grant_ref_t ref;
unsigned long gfn; struct page *page;
struct xen_netif_rx_request *req; struct xen_netif_rx_request *req;
skb = xennet_alloc_one_rx_buffer(queue); skb = xennet_alloc_one_rx_buffer(queue);
...@@ -307,14 +307,13 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) ...@@ -307,14 +307,13 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
BUG_ON((signed short)ref < 0); BUG_ON((signed short)ref < 0);
queue->grant_rx_ref[id] = ref; queue->grant_rx_ref[id] = ref;
gfn = xen_page_to_gfn(skb_frag_page(&skb_shinfo(skb)->frags[0])); page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
req = RING_GET_REQUEST(&queue->rx, req_prod); req = RING_GET_REQUEST(&queue->rx, req_prod);
gnttab_grant_foreign_access_ref(ref, gnttab_page_grant_foreign_access_ref_one(ref,
queue->info->xbdev->otherend_id, queue->info->xbdev->otherend_id,
gfn, page,
0); 0);
req->id = id; req->id = id;
req->gref = ref; req->gref = ref;
} }
...@@ -415,25 +414,33 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) ...@@ -415,25 +414,33 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
xennet_maybe_wake_tx(queue); xennet_maybe_wake_tx(queue);
} }
static struct xen_netif_tx_request *xennet_make_one_txreq( struct xennet_gnttab_make_txreq {
struct netfront_queue *queue, struct sk_buff *skb, struct netfront_queue *queue;
struct page *page, unsigned int offset, unsigned int len) struct sk_buff *skb;
struct page *page;
struct xen_netif_tx_request *tx; /* Last request */
unsigned int size;
};
static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset,
unsigned int len, void *data)
{ {
struct xennet_gnttab_make_txreq *info = data;
unsigned int id; unsigned int id;
struct xen_netif_tx_request *tx; struct xen_netif_tx_request *tx;
grant_ref_t ref; grant_ref_t ref;
/* convenient aliases */
len = min_t(unsigned int, PAGE_SIZE - offset, len); struct page *page = info->page;
struct netfront_queue *queue = info->queue;
struct sk_buff *skb = info->skb;
id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
ref = gnttab_claim_grant_reference(&queue->gref_tx_head); ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
BUG_ON((signed short)ref < 0); BUG_ON((signed short)ref < 0);
gnttab_grant_foreign_access_ref(ref, gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
queue->info->xbdev->otherend_id, gfn, GNTMAP_readonly);
xen_page_to_gfn(page),
GNTMAP_readonly);
queue->tx_skbs[id].skb = skb; queue->tx_skbs[id].skb = skb;
queue->grant_tx_page[id] = page; queue->grant_tx_page[id] = page;
...@@ -445,7 +452,34 @@ static struct xen_netif_tx_request *xennet_make_one_txreq( ...@@ -445,7 +452,34 @@ static struct xen_netif_tx_request *xennet_make_one_txreq(
tx->size = len; tx->size = len;
tx->flags = 0; tx->flags = 0;
return tx; info->tx = tx;
info->size += tx->size;
}
static struct xen_netif_tx_request *xennet_make_first_txreq(
struct netfront_queue *queue, struct sk_buff *skb,
struct page *page, unsigned int offset, unsigned int len)
{
struct xennet_gnttab_make_txreq info = {
.queue = queue,
.skb = skb,
.page = page,
.size = 0,
};
gnttab_for_one_grant(page, offset, len, xennet_tx_setup_grant, &info);
return info.tx;
}
static void xennet_make_one_txreq(unsigned long gfn, unsigned int offset,
unsigned int len, void *data)
{
struct xennet_gnttab_make_txreq *info = data;
info->tx->flags |= XEN_NETTXF_more_data;
skb_get(info->skb);
xennet_tx_setup_grant(gfn, offset, len, data);
} }
static struct xen_netif_tx_request *xennet_make_txreqs( static struct xen_netif_tx_request *xennet_make_txreqs(
...@@ -453,20 +487,30 @@ static struct xen_netif_tx_request *xennet_make_txreqs( ...@@ -453,20 +487,30 @@ static struct xen_netif_tx_request *xennet_make_txreqs(
struct sk_buff *skb, struct page *page, struct sk_buff *skb, struct page *page,
unsigned int offset, unsigned int len) unsigned int offset, unsigned int len)
{ {
struct xennet_gnttab_make_txreq info = {
.queue = queue,
.skb = skb,
.tx = tx,
};
/* Skip unused frames from start of page */ /* Skip unused frames from start of page */
page += offset >> PAGE_SHIFT; page += offset >> PAGE_SHIFT;
offset &= ~PAGE_MASK; offset &= ~PAGE_MASK;
while (len) { while (len) {
tx->flags |= XEN_NETTXF_more_data; info.page = page;
tx = xennet_make_one_txreq(queue, skb_get(skb), info.size = 0;
page, offset, len);
gnttab_foreach_grant_in_range(page, offset, len,
xennet_make_one_txreq,
&info);
page++; page++;
offset = 0; offset = 0;
len -= tx->size; len -= info.size;
} }
return tx; return info.tx;
} }
/* /*
...@@ -476,9 +520,10 @@ static struct xen_netif_tx_request *xennet_make_txreqs( ...@@ -476,9 +520,10 @@ static struct xen_netif_tx_request *xennet_make_txreqs(
static int xennet_count_skb_slots(struct sk_buff *skb) static int xennet_count_skb_slots(struct sk_buff *skb)
{ {
int i, frags = skb_shinfo(skb)->nr_frags; int i, frags = skb_shinfo(skb)->nr_frags;
int pages; int slots;
pages = PFN_UP(offset_in_page(skb->data) + skb_headlen(skb)); slots = gnttab_count_grant(offset_in_page(skb->data),
skb_headlen(skb));
for (i = 0; i < frags; i++) { for (i = 0; i < frags; i++) {
skb_frag_t *frag = skb_shinfo(skb)->frags + i; skb_frag_t *frag = skb_shinfo(skb)->frags + i;
...@@ -488,10 +533,10 @@ static int xennet_count_skb_slots(struct sk_buff *skb) ...@@ -488,10 +533,10 @@ static int xennet_count_skb_slots(struct sk_buff *skb)
/* Skip unused frames from start of page */ /* Skip unused frames from start of page */
offset &= ~PAGE_MASK; offset &= ~PAGE_MASK;
pages += PFN_UP(offset + size); slots += gnttab_count_grant(offset, size);
} }
return pages; return slots;
} }
static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb, static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb,
...@@ -512,6 +557,8 @@ static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb, ...@@ -512,6 +557,8 @@ static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb,
return queue_idx; return queue_idx;
} }
#define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct netfront_info *np = netdev_priv(dev); struct netfront_info *np = netdev_priv(dev);
...@@ -546,7 +593,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -546,7 +593,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
slots = xennet_count_skb_slots(skb); slots = xennet_count_skb_slots(skb);
if (unlikely(slots > MAX_SKB_FRAGS + 1)) { if (unlikely(slots > MAX_XEN_SKB_FRAGS + 1)) {
net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n", net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n",
slots, skb->len); slots, skb->len);
if (skb_linearize(skb)) if (skb_linearize(skb))
...@@ -567,10 +614,13 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -567,10 +614,13 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
/* First request for the linear area. */ /* First request for the linear area. */
first_tx = tx = xennet_make_one_txreq(queue, skb, first_tx = tx = xennet_make_first_txreq(queue, skb,
page, offset, len); page, offset, len);
page++; offset += tx->size;
offset = 0; if (offset == PAGE_SIZE) {
page++;
offset = 0;
}
len -= tx->size; len -= tx->size;
if (skb->ip_summed == CHECKSUM_PARTIAL) if (skb->ip_summed == CHECKSUM_PARTIAL)
...@@ -732,7 +782,7 @@ static int xennet_get_responses(struct netfront_queue *queue, ...@@ -732,7 +782,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
for (;;) { for (;;) {
if (unlikely(rx->status < 0 || if (unlikely(rx->status < 0 ||
rx->offset + rx->status > PAGE_SIZE)) { rx->offset + rx->status > XEN_PAGE_SIZE)) {
if (net_ratelimit()) if (net_ratelimit())
dev_warn(dev, "rx->offset: %u, size: %d\n", dev_warn(dev, "rx->offset: %u, size: %d\n",
rx->offset, rx->status); rx->offset, rx->status);
...@@ -1496,7 +1546,7 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1496,7 +1546,7 @@ static int setup_netfront(struct xenbus_device *dev,
goto fail; goto fail;
} }
SHARED_RING_INIT(txs); SHARED_RING_INIT(txs);
FRONT_RING_INIT(&queue->tx, txs, PAGE_SIZE); FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, txs, 1, &gref); err = xenbus_grant_ring(dev, txs, 1, &gref);
if (err < 0) if (err < 0)
...@@ -1510,7 +1560,7 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1510,7 +1560,7 @@ static int setup_netfront(struct xenbus_device *dev,
goto alloc_rx_ring_fail; goto alloc_rx_ring_fail;
} }
SHARED_RING_INIT(rxs); SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&queue->rx, rxs, PAGE_SIZE); FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, rxs, 1, &gref); err = xenbus_grant_ring(dev, rxs, 1, &gref);
if (err < 0) if (err < 0)
......
...@@ -230,7 +230,7 @@ static int xen_hvm_console_init(void) ...@@ -230,7 +230,7 @@ static int xen_hvm_console_init(void)
if (r < 0 || v == 0) if (r < 0 || v == 0)
goto err; goto err;
gfn = v; gfn = v;
info->intf = xen_remap(gfn << PAGE_SHIFT, PAGE_SIZE); info->intf = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE);
if (info->intf == NULL) if (info->intf == NULL)
goto err; goto err;
info->vtermno = HVC_COOKIE; info->vtermno = HVC_COOKIE;
...@@ -472,7 +472,7 @@ static int xencons_resume(struct xenbus_device *dev) ...@@ -472,7 +472,7 @@ static int xencons_resume(struct xenbus_device *dev)
struct xencons_info *info = dev_get_drvdata(&dev->dev); struct xencons_info *info = dev_get_drvdata(&dev->dev);
xencons_disconnect_backend(info); xencons_disconnect_backend(info);
memset(info->intf, 0, PAGE_SIZE); memset(info->intf, 0, XEN_PAGE_SIZE);
return xencons_connect_backend(dev, info); return xencons_connect_backend(dev, info);
} }
......
ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
endif
obj-$(CONFIG_X86) += fallback.o obj-$(CONFIG_X86) += fallback.o
obj-y += grant-table.o features.o balloon.o manage.o preempt.o obj-y += grant-table.o features.o balloon.o manage.o preempt.o
obj-y += events/ obj-y += events/
......
This diff is collapsed.
...@@ -6,10 +6,18 @@ ...@@ -6,10 +6,18 @@
bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
const struct bio_vec *vec2) const struct bio_vec *vec2)
{ {
#if XEN_PAGE_SIZE == PAGE_SIZE
unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page)); unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page));
unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page)); unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page));
return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) && return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&
((bfn1 == bfn2) || ((bfn1+1) == bfn2)); ((bfn1 == bfn2) || ((bfn1+1) == bfn2));
#else
/*
* XXX: Add support for merging bio_vec when using different page
* size in Xen and Linux.
*/
return 0;
#endif
} }
EXPORT_SYMBOL(xen_biovec_phys_mergeable); EXPORT_SYMBOL(xen_biovec_phys_mergeable);
...@@ -11,15 +11,20 @@ ...@@ -11,15 +11,20 @@
static void enable_hotplug_cpu(int cpu) static void enable_hotplug_cpu(int cpu)
{ {
if (!cpu_present(cpu)) if (!cpu_present(cpu))
arch_register_cpu(cpu); xen_arch_register_cpu(cpu);
set_cpu_present(cpu, true); set_cpu_present(cpu, true);
} }
static void disable_hotplug_cpu(int cpu) static void disable_hotplug_cpu(int cpu)
{ {
if (cpu_online(cpu)) {
lock_device_hotplug();
device_offline(get_cpu_device(cpu));
unlock_device_hotplug();
}
if (cpu_present(cpu)) if (cpu_present(cpu))
arch_unregister_cpu(cpu); xen_arch_unregister_cpu(cpu);
set_cpu_present(cpu, false); set_cpu_present(cpu, false);
} }
...@@ -55,7 +60,6 @@ static void vcpu_hotplug(unsigned int cpu) ...@@ -55,7 +60,6 @@ static void vcpu_hotplug(unsigned int cpu)
enable_hotplug_cpu(cpu); enable_hotplug_cpu(cpu);
break; break;
case 0: case 0:
(void)cpu_down(cpu);
disable_hotplug_cpu(cpu); disable_hotplug_cpu(cpu);
break; break;
default: default:
...@@ -102,7 +106,11 @@ static int __init setup_vcpu_hotplug_event(void) ...@@ -102,7 +106,11 @@ static int __init setup_vcpu_hotplug_event(void)
static struct notifier_block xsn_cpu = { static struct notifier_block xsn_cpu = {
.notifier_call = setup_cpu_watcher }; .notifier_call = setup_cpu_watcher };
#ifdef CONFIG_X86
if (!xen_pv_domain()) if (!xen_pv_domain())
#else
if (!xen_domain())
#endif
return -ENODEV; return -ENODEV;
register_xenstore_notifier(&xsn_cpu); register_xenstore_notifier(&xsn_cpu);
......
...@@ -40,11 +40,11 @@ ...@@ -40,11 +40,11 @@
#include <asm/idle.h> #include <asm/idle.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
#include <asm/xen/pci.h> #include <asm/xen/pci.h>
#include <xen/page.h>
#endif #endif
#include <asm/sync_bitops.h> #include <asm/sync_bitops.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/page.h>
#include <xen/xen.h> #include <xen/xen.h>
#include <xen/hvm.h> #include <xen/hvm.h>
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
#include "events_internal.h" #include "events_internal.h"
#define EVENT_WORDS_PER_PAGE (PAGE_SIZE / sizeof(event_word_t)) #define EVENT_WORDS_PER_PAGE (XEN_PAGE_SIZE / sizeof(event_word_t))
#define MAX_EVENT_ARRAY_PAGES (EVTCHN_FIFO_NR_CHANNELS / EVENT_WORDS_PER_PAGE) #define MAX_EVENT_ARRAY_PAGES (EVTCHN_FIFO_NR_CHANNELS / EVENT_WORDS_PER_PAGE)
struct evtchn_fifo_queue { struct evtchn_fifo_queue {
......
...@@ -642,7 +642,7 @@ int gnttab_setup_auto_xlat_frames(phys_addr_t addr) ...@@ -642,7 +642,7 @@ int gnttab_setup_auto_xlat_frames(phys_addr_t addr)
if (xen_auto_xlat_grant_frames.count) if (xen_auto_xlat_grant_frames.count)
return -EINVAL; return -EINVAL;
vaddr = xen_remap(addr, PAGE_SIZE * max_nr_gframes); vaddr = xen_remap(addr, XEN_PAGE_SIZE * max_nr_gframes);
if (vaddr == NULL) { if (vaddr == NULL) {
pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n", pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n",
&addr); &addr);
...@@ -654,7 +654,7 @@ int gnttab_setup_auto_xlat_frames(phys_addr_t addr) ...@@ -654,7 +654,7 @@ int gnttab_setup_auto_xlat_frames(phys_addr_t addr)
return -ENOMEM; return -ENOMEM;
} }
for (i = 0; i < max_nr_gframes; i++) for (i = 0; i < max_nr_gframes; i++)
pfn[i] = PFN_DOWN(addr) + i; pfn[i] = XEN_PFN_DOWN(addr) + i;
xen_auto_xlat_grant_frames.vaddr = vaddr; xen_auto_xlat_grant_frames.vaddr = vaddr;
xen_auto_xlat_grant_frames.pfn = pfn; xen_auto_xlat_grant_frames.pfn = pfn;
...@@ -687,7 +687,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages) ...@@ -687,7 +687,7 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages)
int i; int i;
int ret; int ret;
ret = alloc_xenballooned_pages(nr_pages, pages, false); ret = alloc_xenballooned_pages(nr_pages, pages);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -776,6 +776,54 @@ void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count) ...@@ -776,6 +776,54 @@ void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count)
} }
EXPORT_SYMBOL_GPL(gnttab_batch_copy); EXPORT_SYMBOL_GPL(gnttab_batch_copy);
void gnttab_foreach_grant_in_range(struct page *page,
unsigned int offset,
unsigned int len,
xen_grant_fn_t fn,
void *data)
{
unsigned int goffset;
unsigned int glen;
unsigned long xen_pfn;
len = min_t(unsigned int, PAGE_SIZE - offset, len);
goffset = xen_offset_in_page(offset);
xen_pfn = page_to_xen_pfn(page) + XEN_PFN_DOWN(offset);
while (len) {
glen = min_t(unsigned int, XEN_PAGE_SIZE - goffset, len);
fn(pfn_to_gfn(xen_pfn), goffset, glen, data);
goffset = 0;
xen_pfn++;
len -= glen;
}
}
EXPORT_SYMBOL_GPL(gnttab_foreach_grant_in_range);
void gnttab_foreach_grant(struct page **pages,
unsigned int nr_grefs,
xen_grant_fn_t fn,
void *data)
{
unsigned int goffset = 0;
unsigned long xen_pfn = 0;
unsigned int i;
for (i = 0; i < nr_grefs; i++) {
if ((i % XEN_PFN_PER_PAGE) == 0) {
xen_pfn = page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
goffset = 0;
}
fn(pfn_to_gfn(xen_pfn), goffset, XEN_PAGE_SIZE, data);
goffset += XEN_PAGE_SIZE;
xen_pfn++;
}
}
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
struct gnttab_map_grant_ref *kmap_ops, struct gnttab_map_grant_ref *kmap_ops,
struct page **pages, unsigned int count) struct page **pages, unsigned int count)
...@@ -978,7 +1026,7 @@ static void gnttab_request_version(void) ...@@ -978,7 +1026,7 @@ static void gnttab_request_version(void)
{ {
/* Only version 1 is used, which will always be available. */ /* Only version 1 is used, which will always be available. */
grant_table_version = 1; grant_table_version = 1;
grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1); grefs_per_grant_frame = XEN_PAGE_SIZE / sizeof(struct grant_entry_v1);
gnttab_interface = &gnttab_v1_ops; gnttab_interface = &gnttab_v1_ops;
pr_info("Grant tables using version %d layout\n", grant_table_version); pr_info("Grant tables using version %d layout\n", grant_table_version);
......
...@@ -401,7 +401,7 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs) ...@@ -401,7 +401,7 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
if (pages == NULL) if (pages == NULL)
return -ENOMEM; return -ENOMEM;
rc = alloc_xenballooned_pages(numpgs, pages, 0); rc = alloc_xenballooned_pages(numpgs, pages);
if (rc != 0) { if (rc != 0) {
pr_warn("%s Could not alloc %d pfns rc:%d\n", __func__, pr_warn("%s Could not alloc %d pfns rc:%d\n", __func__,
numpgs, rc); numpgs, rc);
...@@ -446,7 +446,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) ...@@ -446,7 +446,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
return -EINVAL; return -EINVAL;
} }
nr_pages = m.num; nr_pages = DIV_ROUND_UP(m.num, XEN_PFN_PER_PAGE);
if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT))) if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
return -EINVAL; return -EINVAL;
...@@ -494,7 +494,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) ...@@ -494,7 +494,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
goto out_unlock; goto out_unlock;
} }
if (xen_feature(XENFEAT_auto_translated_physmap)) { if (xen_feature(XENFEAT_auto_translated_physmap)) {
ret = alloc_empty_pages(vma, m.num); ret = alloc_empty_pages(vma, nr_pages);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out_unlock;
} else } else
...@@ -518,6 +518,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) ...@@ -518,6 +518,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
state.global_error = 0; state.global_error = 0;
state.version = version; state.version = version;
BUILD_BUG_ON(((PAGE_SIZE / sizeof(xen_pfn_t)) % XEN_PFN_PER_PAGE) != 0);
/* mmap_batch_fn guarantees ret == 0 */ /* mmap_batch_fn guarantees ret == 0 */
BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t), BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t),
&pagelist, mmap_batch_fn, &state)); &pagelist, mmap_batch_fn, &state));
...@@ -582,12 +583,13 @@ static void privcmd_close(struct vm_area_struct *vma) ...@@ -582,12 +583,13 @@ static void privcmd_close(struct vm_area_struct *vma)
{ {
struct page **pages = vma->vm_private_data; struct page **pages = vma->vm_private_data;
int numpgs = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; int numpgs = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
int numgfns = (vma->vm_end - vma->vm_start) >> XEN_PAGE_SHIFT;
int rc; int rc;
if (!xen_feature(XENFEAT_auto_translated_physmap) || !numpgs || !pages) if (!xen_feature(XENFEAT_auto_translated_physmap) || !numpgs || !pages)
return; return;
rc = xen_unmap_domain_gfn_range(vma, numpgs, pages); rc = xen_unmap_domain_gfn_range(vma, numgfns, pages);
if (rc == 0) if (rc == 0)
free_xenballooned_pages(numpgs, pages); free_xenballooned_pages(numpgs, pages);
else else
......
...@@ -76,27 +76,27 @@ static unsigned long xen_io_tlb_nslabs; ...@@ -76,27 +76,27 @@ static unsigned long xen_io_tlb_nslabs;
static u64 start_dma_addr; static u64 start_dma_addr;
/* /*
* Both of these functions should avoid PFN_PHYS because phys_addr_t * Both of these functions should avoid XEN_PFN_PHYS because phys_addr_t
* can be 32bit when dma_addr_t is 64bit leading to a loss in * can be 32bit when dma_addr_t is 64bit leading to a loss in
* information if the shift is done before casting to 64bit. * information if the shift is done before casting to 64bit.
*/ */
static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr) static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
{ {
unsigned long bfn = pfn_to_bfn(PFN_DOWN(paddr)); unsigned long bfn = pfn_to_bfn(XEN_PFN_DOWN(paddr));
dma_addr_t dma = (dma_addr_t)bfn << PAGE_SHIFT; dma_addr_t dma = (dma_addr_t)bfn << XEN_PAGE_SHIFT;
dma |= paddr & ~PAGE_MASK; dma |= paddr & ~XEN_PAGE_MASK;
return dma; return dma;
} }
static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr) static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
{ {
unsigned long pfn = bfn_to_pfn(PFN_DOWN(baddr)); unsigned long xen_pfn = bfn_to_pfn(XEN_PFN_DOWN(baddr));
dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT; dma_addr_t dma = (dma_addr_t)xen_pfn << XEN_PAGE_SHIFT;
phys_addr_t paddr = dma; phys_addr_t paddr = dma;
paddr |= baddr & ~PAGE_MASK; paddr |= baddr & ~XEN_PAGE_MASK;
return paddr; return paddr;
} }
...@@ -106,7 +106,7 @@ static inline dma_addr_t xen_virt_to_bus(void *address) ...@@ -106,7 +106,7 @@ static inline dma_addr_t xen_virt_to_bus(void *address)
return xen_phys_to_bus(virt_to_phys(address)); return xen_phys_to_bus(virt_to_phys(address));
} }
static int check_pages_physically_contiguous(unsigned long pfn, static int check_pages_physically_contiguous(unsigned long xen_pfn,
unsigned int offset, unsigned int offset,
size_t length) size_t length)
{ {
...@@ -114,11 +114,11 @@ static int check_pages_physically_contiguous(unsigned long pfn, ...@@ -114,11 +114,11 @@ static int check_pages_physically_contiguous(unsigned long pfn,
int i; int i;
int nr_pages; int nr_pages;
next_bfn = pfn_to_bfn(pfn); next_bfn = pfn_to_bfn(xen_pfn);
nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT; nr_pages = (offset + length + XEN_PAGE_SIZE-1) >> XEN_PAGE_SHIFT;
for (i = 1; i < nr_pages; i++) { for (i = 1; i < nr_pages; i++) {
if (pfn_to_bfn(++pfn) != ++next_bfn) if (pfn_to_bfn(++xen_pfn) != ++next_bfn)
return 0; return 0;
} }
return 1; return 1;
...@@ -126,28 +126,27 @@ static int check_pages_physically_contiguous(unsigned long pfn, ...@@ -126,28 +126,27 @@ static int check_pages_physically_contiguous(unsigned long pfn,
static inline int range_straddles_page_boundary(phys_addr_t p, size_t size) static inline int range_straddles_page_boundary(phys_addr_t p, size_t size)
{ {
unsigned long pfn = PFN_DOWN(p); unsigned long xen_pfn = XEN_PFN_DOWN(p);
unsigned int offset = p & ~PAGE_MASK; unsigned int offset = p & ~XEN_PAGE_MASK;
if (offset + size <= PAGE_SIZE) if (offset + size <= XEN_PAGE_SIZE)
return 0; return 0;
if (check_pages_physically_contiguous(pfn, offset, size)) if (check_pages_physically_contiguous(xen_pfn, offset, size))
return 0; return 0;
return 1; return 1;
} }
static int is_xen_swiotlb_buffer(dma_addr_t dma_addr) static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
{ {
unsigned long bfn = PFN_DOWN(dma_addr); unsigned long bfn = XEN_PFN_DOWN(dma_addr);
unsigned long pfn = bfn_to_local_pfn(bfn); unsigned long xen_pfn = bfn_to_local_pfn(bfn);
phys_addr_t paddr; phys_addr_t paddr = XEN_PFN_PHYS(xen_pfn);
/* If the address is outside our domain, it CAN /* If the address is outside our domain, it CAN
* have the same virtual address as another address * have the same virtual address as another address
* in our domain. Therefore _only_ check address within our domain. * in our domain. Therefore _only_ check address within our domain.
*/ */
if (pfn_valid(pfn)) { if (pfn_valid(PFN_DOWN(paddr))) {
paddr = PFN_PHYS(pfn);
return paddr >= virt_to_phys(xen_io_tlb_start) && return paddr >= virt_to_phys(xen_io_tlb_start) &&
paddr < virt_to_phys(xen_io_tlb_end); paddr < virt_to_phys(xen_io_tlb_end);
} }
...@@ -392,7 +391,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, ...@@ -392,7 +391,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
*/ */
if (dma_capable(dev, dev_addr, size) && if (dma_capable(dev, dev_addr, size) &&
!range_straddles_page_boundary(phys, size) && !range_straddles_page_boundary(phys, size) &&
!xen_arch_need_swiotlb(dev, PFN_DOWN(phys), PFN_DOWN(dev_addr)) && !xen_arch_need_swiotlb(dev, phys, dev_addr) &&
!swiotlb_force) { !swiotlb_force) {
/* we are not interested in the dma_addr returned by /* we are not interested in the dma_addr returned by
* xen_dma_map_page, only in the potential cache flushes executed * xen_dma_map_page, only in the potential cache flushes executed
...@@ -551,7 +550,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, ...@@ -551,7 +550,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
dma_addr_t dev_addr = xen_phys_to_bus(paddr); dma_addr_t dev_addr = xen_phys_to_bus(paddr);
if (swiotlb_force || if (swiotlb_force ||
xen_arch_need_swiotlb(hwdev, PFN_DOWN(paddr), PFN_DOWN(dev_addr)) || xen_arch_need_swiotlb(hwdev, paddr, dev_addr) ||
!dma_capable(hwdev, dev_addr, sg->length) || !dma_capable(hwdev, dev_addr, sg->length) ||
range_straddles_page_boundary(paddr, sg->length)) { range_straddles_page_boundary(paddr, sg->length)) {
phys_addr_t map = swiotlb_tbl_map_single(hwdev, phys_addr_t map = swiotlb_tbl_map_single(hwdev,
......
...@@ -49,6 +49,10 @@ ...@@ -49,6 +49,10 @@
#include "xenbus_probe.h" #include "xenbus_probe.h"
#define XENBUS_PAGES(_grants) (DIV_ROUND_UP(_grants, XEN_PFN_PER_PAGE))
#define XENBUS_MAX_RING_PAGES (XENBUS_PAGES(XENBUS_MAX_RING_GRANTS))
struct xenbus_map_node { struct xenbus_map_node {
struct list_head next; struct list_head next;
union { union {
...@@ -57,10 +61,11 @@ struct xenbus_map_node { ...@@ -57,10 +61,11 @@ struct xenbus_map_node {
} pv; } pv;
struct { struct {
struct page *pages[XENBUS_MAX_RING_PAGES]; struct page *pages[XENBUS_MAX_RING_PAGES];
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
void *addr; void *addr;
} hvm; } hvm;
}; };
grant_handle_t handles[XENBUS_MAX_RING_PAGES]; grant_handle_t handles[XENBUS_MAX_RING_GRANTS];
unsigned int nr_handles; unsigned int nr_handles;
}; };
...@@ -388,7 +393,7 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, ...@@ -388,7 +393,7 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
} }
grefs[i] = err; grefs[i] = err;
vaddr = vaddr + PAGE_SIZE; vaddr = vaddr + XEN_PAGE_SIZE;
} }
return 0; return 0;
...@@ -479,12 +484,12 @@ static int __xenbus_map_ring(struct xenbus_device *dev, ...@@ -479,12 +484,12 @@ static int __xenbus_map_ring(struct xenbus_device *dev,
unsigned int flags, unsigned int flags,
bool *leaked) bool *leaked)
{ {
struct gnttab_map_grant_ref map[XENBUS_MAX_RING_PAGES]; struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS];
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
int i, j; int i, j;
int err = GNTST_okay; int err = GNTST_okay;
if (nr_grefs > XENBUS_MAX_RING_PAGES) if (nr_grefs > XENBUS_MAX_RING_GRANTS)
return -EINVAL; return -EINVAL;
for (i = 0; i < nr_grefs; i++) { for (i = 0; i < nr_grefs; i++) {
...@@ -540,22 +545,22 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, ...@@ -540,22 +545,22 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
{ {
struct xenbus_map_node *node; struct xenbus_map_node *node;
struct vm_struct *area; struct vm_struct *area;
pte_t *ptes[XENBUS_MAX_RING_PAGES]; pte_t *ptes[XENBUS_MAX_RING_GRANTS];
phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
int err = GNTST_okay; int err = GNTST_okay;
int i; int i;
bool leaked; bool leaked;
*vaddr = NULL; *vaddr = NULL;
if (nr_grefs > XENBUS_MAX_RING_PAGES) if (nr_grefs > XENBUS_MAX_RING_GRANTS)
return -EINVAL; return -EINVAL;
node = kzalloc(sizeof(*node), GFP_KERNEL); node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) if (!node)
return -ENOMEM; return -ENOMEM;
area = alloc_vm_area(PAGE_SIZE * nr_grefs, ptes); area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes);
if (!area) { if (!area) {
kfree(node); kfree(node);
return -ENOMEM; return -ENOMEM;
...@@ -591,21 +596,44 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, ...@@ -591,21 +596,44 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev,
return err; return err;
} }
struct map_ring_valloc_hvm
{
unsigned int idx;
/* Why do we need two arrays? See comment of __xenbus_map_ring */
phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
};
static void xenbus_map_ring_setup_grant_hvm(unsigned long gfn,
unsigned int goffset,
unsigned int len,
void *data)
{
struct map_ring_valloc_hvm *info = data;
unsigned long vaddr = (unsigned long)gfn_to_virt(gfn);
info->phys_addrs[info->idx] = vaddr;
info->addrs[info->idx] = vaddr;
info->idx++;
}
static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
grant_ref_t *gnt_ref, grant_ref_t *gnt_ref,
unsigned int nr_grefs, unsigned int nr_grefs,
void **vaddr) void **vaddr)
{ {
struct xenbus_map_node *node; struct xenbus_map_node *node;
int i;
int err; int err;
void *addr; void *addr;
bool leaked = false; bool leaked = false;
/* Why do we need two arrays? See comment of __xenbus_map_ring */ struct map_ring_valloc_hvm info = {
phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; .idx = 0,
unsigned long addrs[XENBUS_MAX_RING_PAGES]; };
unsigned int nr_pages = XENBUS_PAGES(nr_grefs);
if (nr_grefs > XENBUS_MAX_RING_PAGES) if (nr_grefs > XENBUS_MAX_RING_GRANTS)
return -EINVAL; return -EINVAL;
*vaddr = NULL; *vaddr = NULL;
...@@ -614,25 +642,22 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, ...@@ -614,25 +642,22 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
if (!node) if (!node)
return -ENOMEM; return -ENOMEM;
err = alloc_xenballooned_pages(nr_grefs, node->hvm.pages, err = alloc_xenballooned_pages(nr_pages, node->hvm.pages);
false /* lowmem */);
if (err) if (err)
goto out_err; goto out_err;
for (i = 0; i < nr_grefs; i++) { gnttab_foreach_grant(node->hvm.pages, nr_grefs,
unsigned long pfn = page_to_pfn(node->hvm.pages[i]); xenbus_map_ring_setup_grant_hvm,
phys_addrs[i] = (unsigned long)pfn_to_kaddr(pfn); &info);
addrs[i] = (unsigned long)pfn_to_kaddr(pfn);
}
err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles, err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles,
phys_addrs, GNTMAP_host_map, &leaked); info.phys_addrs, GNTMAP_host_map, &leaked);
node->nr_handles = nr_grefs; node->nr_handles = nr_grefs;
if (err) if (err)
goto out_free_ballooned_pages; goto out_free_ballooned_pages;
addr = vmap(node->hvm.pages, nr_grefs, VM_MAP | VM_IOREMAP, addr = vmap(node->hvm.pages, nr_pages, VM_MAP | VM_IOREMAP,
PAGE_KERNEL); PAGE_KERNEL);
if (!addr) { if (!addr) {
err = -ENOMEM; err = -ENOMEM;
...@@ -650,14 +675,13 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, ...@@ -650,14 +675,13 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
out_xenbus_unmap_ring: out_xenbus_unmap_ring:
if (!leaked) if (!leaked)
xenbus_unmap_ring(dev, node->handles, node->nr_handles, xenbus_unmap_ring(dev, node->handles, nr_grefs, info.addrs);
addrs);
else else
pr_alert("leaking %p size %u page(s)", pr_alert("leaking %p size %u page(s)",
addr, nr_grefs); addr, nr_pages);
out_free_ballooned_pages: out_free_ballooned_pages:
if (!leaked) if (!leaked)
free_xenballooned_pages(nr_grefs, node->hvm.pages); free_xenballooned_pages(nr_pages, node->hvm.pages);
out_err: out_err:
kfree(node); kfree(node);
return err; return err;
...@@ -687,10 +711,10 @@ int xenbus_map_ring(struct xenbus_device *dev, grant_ref_t *gnt_refs, ...@@ -687,10 +711,10 @@ int xenbus_map_ring(struct xenbus_device *dev, grant_ref_t *gnt_refs,
unsigned int nr_grefs, grant_handle_t *handles, unsigned int nr_grefs, grant_handle_t *handles,
unsigned long *vaddrs, bool *leaked) unsigned long *vaddrs, bool *leaked)
{ {
phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS];
int i; int i;
if (nr_grefs > XENBUS_MAX_RING_PAGES) if (nr_grefs > XENBUS_MAX_RING_GRANTS)
return -EINVAL; return -EINVAL;
for (i = 0; i < nr_grefs; i++) for (i = 0; i < nr_grefs; i++)
...@@ -723,7 +747,7 @@ EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); ...@@ -723,7 +747,7 @@ EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
{ {
struct xenbus_map_node *node; struct xenbus_map_node *node;
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
unsigned int level; unsigned int level;
int i; int i;
bool leaked = false; bool leaked = false;
...@@ -750,7 +774,7 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) ...@@ -750,7 +774,7 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
unsigned long addr; unsigned long addr;
memset(&unmap[i], 0, sizeof(unmap[i])); memset(&unmap[i], 0, sizeof(unmap[i]));
addr = (unsigned long)vaddr + (PAGE_SIZE * i); addr = (unsigned long)vaddr + (XEN_PAGE_SIZE * i);
unmap[i].host_addr = arbitrary_virt_to_machine( unmap[i].host_addr = arbitrary_virt_to_machine(
lookup_address(addr, &level)).maddr; lookup_address(addr, &level)).maddr;
unmap[i].dev_bus_addr = 0; unmap[i].dev_bus_addr = 0;
...@@ -783,13 +807,33 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) ...@@ -783,13 +807,33 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr)
return err; return err;
} }
struct unmap_ring_vfree_hvm
{
unsigned int idx;
unsigned long addrs[XENBUS_MAX_RING_GRANTS];
};
static void xenbus_unmap_ring_setup_grant_hvm(unsigned long gfn,
unsigned int goffset,
unsigned int len,
void *data)
{
struct unmap_ring_vfree_hvm *info = data;
info->addrs[info->idx] = (unsigned long)gfn_to_virt(gfn);
info->idx++;
}
static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
{ {
int rv; int rv;
struct xenbus_map_node *node; struct xenbus_map_node *node;
void *addr; void *addr;
unsigned long addrs[XENBUS_MAX_RING_PAGES]; struct unmap_ring_vfree_hvm info = {
int i; .idx = 0,
};
unsigned int nr_pages;
spin_lock(&xenbus_valloc_lock); spin_lock(&xenbus_valloc_lock);
list_for_each_entry(node, &xenbus_valloc_pages, next) { list_for_each_entry(node, &xenbus_valloc_pages, next) {
...@@ -809,18 +853,20 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) ...@@ -809,18 +853,20 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
return GNTST_bad_virt_addr; return GNTST_bad_virt_addr;
} }
for (i = 0; i < node->nr_handles; i++) nr_pages = XENBUS_PAGES(node->nr_handles);
addrs[i] = (unsigned long)pfn_to_kaddr(page_to_pfn(node->hvm.pages[i]));
gnttab_foreach_grant(node->hvm.pages, node->nr_handles,
xenbus_unmap_ring_setup_grant_hvm,
&info);
rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles, rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles,
addrs); info.addrs);
if (!rv) { if (!rv) {
vunmap(vaddr); vunmap(vaddr);
free_xenballooned_pages(node->nr_handles, node->hvm.pages); free_xenballooned_pages(nr_pages, node->hvm.pages);
} }
else else
WARN(1, "Leaking %p, size %u page(s)\n", vaddr, WARN(1, "Leaking %p, size %u page(s)\n", vaddr, nr_pages);
node->nr_handles);
kfree(node); kfree(node);
return rv; return rv;
...@@ -841,11 +887,11 @@ int xenbus_unmap_ring(struct xenbus_device *dev, ...@@ -841,11 +887,11 @@ int xenbus_unmap_ring(struct xenbus_device *dev,
grant_handle_t *handles, unsigned int nr_handles, grant_handle_t *handles, unsigned int nr_handles,
unsigned long *vaddrs) unsigned long *vaddrs)
{ {
struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS];
int i; int i;
int err; int err;
if (nr_handles > XENBUS_MAX_RING_PAGES) if (nr_handles > XENBUS_MAX_RING_GRANTS)
return -EINVAL; return -EINVAL;
for (i = 0; i < nr_handles; i++) for (i = 0; i < nr_handles; i++)
......
...@@ -802,7 +802,8 @@ static int __init xenbus_init(void) ...@@ -802,7 +802,8 @@ static int __init xenbus_init(void)
goto out_error; goto out_error;
xen_store_gfn = (unsigned long)v; xen_store_gfn = (unsigned long)v;
xen_store_interface = xen_store_interface =
xen_remap(xen_store_gfn << PAGE_SHIFT, PAGE_SIZE); xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE);
break; break;
default: default:
pr_warn("Xenstore state unknown\n"); pr_warn("Xenstore state unknown\n");
......
...@@ -38,31 +38,28 @@ ...@@ -38,31 +38,28 @@
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/memory.h> #include <xen/interface/memory.h>
/* map fgfn of domid to lpfn in the current domain */ typedef void (*xen_gfn_fn_t)(unsigned long gfn, void *data);
static int map_foreign_page(unsigned long lpfn, unsigned long fgfn,
unsigned int domid)
{
int rc;
struct xen_add_to_physmap_range xatp = {
.domid = DOMID_SELF,
.foreign_domid = domid,
.size = 1,
.space = XENMAPSPACE_gmfn_foreign,
};
xen_ulong_t idx = fgfn;
xen_pfn_t gpfn = lpfn;
int err = 0;
set_xen_guest_handle(xatp.idxs, &idx); /* Break down the pages in 4KB chunk and call fn for each gfn */
set_xen_guest_handle(xatp.gpfns, &gpfn); static void xen_for_each_gfn(struct page **pages, unsigned nr_gfn,
set_xen_guest_handle(xatp.errs, &err); xen_gfn_fn_t fn, void *data)
{
unsigned long xen_pfn = 0;
struct page *page;
int i;
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); for (i = 0; i < nr_gfn; i++) {
return rc < 0 ? rc : err; if ((i % XEN_PFN_PER_PAGE) == 0) {
page = pages[i / XEN_PFN_PER_PAGE];
xen_pfn = page_to_xen_pfn(page);
}
fn(pfn_to_gfn(xen_pfn++), data);
}
} }
struct remap_data { struct remap_data {
xen_pfn_t *fgfn; /* foreign domain's gfn */ xen_pfn_t *fgfn; /* foreign domain's gfn */
int nr_fgfn; /* Number of foreign gfn left to map */
pgprot_t prot; pgprot_t prot;
domid_t domid; domid_t domid;
struct vm_area_struct *vma; struct vm_area_struct *vma;
...@@ -71,24 +68,71 @@ struct remap_data { ...@@ -71,24 +68,71 @@ struct remap_data {
struct xen_remap_gfn_info *info; struct xen_remap_gfn_info *info;
int *err_ptr; int *err_ptr;
int mapped; int mapped;
/* Hypercall parameters */
int h_errs[XEN_PFN_PER_PAGE];
xen_ulong_t h_idxs[XEN_PFN_PER_PAGE];
xen_pfn_t h_gpfns[XEN_PFN_PER_PAGE];
int h_iter; /* Iterator */
}; };
static void setup_hparams(unsigned long gfn, void *data)
{
struct remap_data *info = data;
info->h_idxs[info->h_iter] = *info->fgfn;
info->h_gpfns[info->h_iter] = gfn;
info->h_errs[info->h_iter] = 0;
info->h_iter++;
info->fgfn++;
}
static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
void *data) void *data)
{ {
struct remap_data *info = data; struct remap_data *info = data;
struct page *page = info->pages[info->index++]; struct page *page = info->pages[info->index++];
unsigned long pfn = page_to_pfn(page); pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), info->prot));
pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); int rc, nr_gfn;
int rc; uint32_t i;
struct xen_add_to_physmap_range xatp = {
.domid = DOMID_SELF,
.foreign_domid = info->domid,
.space = XENMAPSPACE_gmfn_foreign,
};
rc = map_foreign_page(pfn, *info->fgfn, info->domid); nr_gfn = min_t(typeof(info->nr_fgfn), XEN_PFN_PER_PAGE, info->nr_fgfn);
*info->err_ptr++ = rc; info->nr_fgfn -= nr_gfn;
if (!rc) {
set_pte_at(info->vma->vm_mm, addr, ptep, pte); info->h_iter = 0;
info->mapped++; xen_for_each_gfn(&page, nr_gfn, setup_hparams, info);
BUG_ON(info->h_iter != nr_gfn);
set_xen_guest_handle(xatp.idxs, info->h_idxs);
set_xen_guest_handle(xatp.gpfns, info->h_gpfns);
set_xen_guest_handle(xatp.errs, info->h_errs);
xatp.size = nr_gfn;
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
/* info->err_ptr expect to have one error status per Xen PFN */
for (i = 0; i < nr_gfn; i++) {
int err = (rc < 0) ? rc : info->h_errs[i];
*(info->err_ptr++) = err;
if (!err)
info->mapped++;
} }
info->fgfn++;
/*
* Note: The hypercall will return 0 in most of the case if even if
* all the fgmfn are not mapped. We still have to update the pte
* as the userspace may decide to continue.
*/
if (!rc)
set_pte_at(info->vma->vm_mm, addr, ptep, pte);
return 0; return 0;
} }
...@@ -102,13 +146,14 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, ...@@ -102,13 +146,14 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
{ {
int err; int err;
struct remap_data data; struct remap_data data;
unsigned long range = nr << PAGE_SHIFT; unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
/* Kept here for the purpose of making sure code doesn't break /* Kept here for the purpose of making sure code doesn't break
x86 PVOPS */ x86 PVOPS */
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
data.fgfn = gfn; data.fgfn = gfn;
data.nr_fgfn = nr;
data.prot = prot; data.prot = prot;
data.domid = domid; data.domid = domid;
data.vma = vma; data.vma = vma;
...@@ -123,21 +168,20 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, ...@@ -123,21 +168,20 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
} }
EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array); EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, static void unmap_gfn(unsigned long gfn, void *data)
int nr, struct page **pages)
{ {
int i; struct xen_remove_from_physmap xrp;
for (i = 0; i < nr; i++) { xrp.domid = DOMID_SELF;
struct xen_remove_from_physmap xrp; xrp.gpfn = gfn;
unsigned long pfn; (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
}
pfn = page_to_pfn(pages[i]); int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
int nr, struct page **pages)
{
xen_for_each_gfn(pages, nr, unmap_gfn, NULL);
xrp.domid = DOMID_SELF;
xrp.gpfn = pfn;
(void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range); EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);
...@@ -11,6 +11,7 @@ struct zone; ...@@ -11,6 +11,7 @@ struct zone;
struct pglist_data; struct pglist_data;
struct mem_section; struct mem_section;
struct memory_block; struct memory_block;
struct resource;
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
...@@ -266,6 +267,7 @@ static inline void remove_memory(int nid, u64 start, u64 size) {} ...@@ -266,6 +267,7 @@ static inline void remove_memory(int nid, u64 start, u64 size) {}
extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
void *arg, int (*func)(struct memory_block *, void *)); void *arg, int (*func)(struct memory_block *, void *));
extern int add_memory(int nid, u64 start, u64 size); extern int add_memory(int nid, u64 start, u64 size);
extern int add_memory_resource(int nid, struct resource *resource);
extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default, extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default,
bool for_device); bool for_device);
extern int arch_add_memory(int nid, u64 start, u64 size, bool for_device); extern int arch_add_memory(int nid, u64 start, u64 size, bool for_device);
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#ifndef __LINUX_PUBLIC_GNTALLOC_H__ #ifndef __LINUX_PUBLIC_GNTALLOC_H__
#define __LINUX_PUBLIC_GNTALLOC_H__ #define __LINUX_PUBLIC_GNTALLOC_H__
#include <linux/types.h>
/* /*
* Allocates a new page and creates a new grant reference. * Allocates a new page and creates a new grant reference.
*/ */
...@@ -19,17 +21,17 @@ _IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref)) ...@@ -19,17 +21,17 @@ _IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
struct ioctl_gntalloc_alloc_gref { struct ioctl_gntalloc_alloc_gref {
/* IN parameters */ /* IN parameters */
/* The ID of the domain to be given access to the grants. */ /* The ID of the domain to be given access to the grants. */
uint16_t domid; __u16 domid;
/* Flags for this mapping */ /* Flags for this mapping */
uint16_t flags; __u16 flags;
/* Number of pages to map */ /* Number of pages to map */
uint32_t count; __u32 count;
/* OUT parameters */ /* OUT parameters */
/* The offset to be used on a subsequent call to mmap(). */ /* The offset to be used on a subsequent call to mmap(). */
uint64_t index; __u64 index;
/* The grant references of the newly created grant, one per page */ /* The grant references of the newly created grant, one per page */
/* Variable size, depending on count */ /* Variable size, depending on count */
uint32_t gref_ids[1]; __u32 gref_ids[1];
}; };
#define GNTALLOC_FLAG_WRITABLE 1 #define GNTALLOC_FLAG_WRITABLE 1
...@@ -43,9 +45,9 @@ _IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref)) ...@@ -43,9 +45,9 @@ _IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
struct ioctl_gntalloc_dealloc_gref { struct ioctl_gntalloc_dealloc_gref {
/* IN parameters */ /* IN parameters */
/* The offset returned in the map operation */ /* The offset returned in the map operation */
uint64_t index; __u64 index;
/* Number of references to unmap */ /* Number of references to unmap */
uint32_t count; __u32 count;
}; };
/* /*
...@@ -67,11 +69,11 @@ struct ioctl_gntalloc_unmap_notify { ...@@ -67,11 +69,11 @@ struct ioctl_gntalloc_unmap_notify {
* be cleared. Otherwise, it can be any byte in the page whose * be cleared. Otherwise, it can be any byte in the page whose
* notification we are adjusting. * notification we are adjusting.
*/ */
uint64_t index; __u64 index;
/* Action(s) to take on unmap */ /* Action(s) to take on unmap */
uint32_t action; __u32 action;
/* Event channel to notify */ /* Event channel to notify */
uint32_t event_channel_port; __u32 event_channel_port;
}; };
/* Clear (set to zero) the byte specified by index */ /* Clear (set to zero) the byte specified by index */
......
...@@ -33,11 +33,13 @@ ...@@ -33,11 +33,13 @@
#ifndef __LINUX_PUBLIC_GNTDEV_H__ #ifndef __LINUX_PUBLIC_GNTDEV_H__
#define __LINUX_PUBLIC_GNTDEV_H__ #define __LINUX_PUBLIC_GNTDEV_H__
#include <linux/types.h>
struct ioctl_gntdev_grant_ref { struct ioctl_gntdev_grant_ref {
/* The domain ID of the grant to be mapped. */ /* The domain ID of the grant to be mapped. */
uint32_t domid; __u32 domid;
/* The grant reference of the grant to be mapped. */ /* The grant reference of the grant to be mapped. */
uint32_t ref; __u32 ref;
}; };
/* /*
...@@ -50,11 +52,11 @@ _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref)) ...@@ -50,11 +52,11 @@ _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
struct ioctl_gntdev_map_grant_ref { struct ioctl_gntdev_map_grant_ref {
/* IN parameters */ /* IN parameters */
/* The number of grants to be mapped. */ /* The number of grants to be mapped. */
uint32_t count; __u32 count;
uint32_t pad; __u32 pad;
/* OUT parameters */ /* OUT parameters */
/* The offset to be used on a subsequent call to mmap(). */ /* The offset to be used on a subsequent call to mmap(). */
uint64_t index; __u64 index;
/* Variable IN parameter. */ /* Variable IN parameter. */
/* Array of grant references, of size @count. */ /* Array of grant references, of size @count. */
struct ioctl_gntdev_grant_ref refs[1]; struct ioctl_gntdev_grant_ref refs[1];
...@@ -70,10 +72,10 @@ _IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref)) ...@@ -70,10 +72,10 @@ _IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
struct ioctl_gntdev_unmap_grant_ref { struct ioctl_gntdev_unmap_grant_ref {
/* IN parameters */ /* IN parameters */
/* The offset was returned by the corresponding map operation. */ /* The offset was returned by the corresponding map operation. */
uint64_t index; __u64 index;
/* The number of pages to be unmapped. */ /* The number of pages to be unmapped. */
uint32_t count; __u32 count;
uint32_t pad; __u32 pad;
}; };
/* /*
...@@ -93,13 +95,13 @@ _IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr)) ...@@ -93,13 +95,13 @@ _IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr))
struct ioctl_gntdev_get_offset_for_vaddr { struct ioctl_gntdev_get_offset_for_vaddr {
/* IN parameters */ /* IN parameters */
/* The virtual address of the first mapped page in a range. */ /* The virtual address of the first mapped page in a range. */
uint64_t vaddr; __u64 vaddr;
/* OUT parameters */ /* OUT parameters */
/* The offset that was used in the initial mmap() operation. */ /* The offset that was used in the initial mmap() operation. */
uint64_t offset; __u64 offset;
/* The number of pages mapped in the VM area that begins at @vaddr. */ /* The number of pages mapped in the VM area that begins at @vaddr. */
uint32_t count; __u32 count;
uint32_t pad; __u32 pad;
}; };
/* /*
...@@ -113,7 +115,7 @@ _IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants)) ...@@ -113,7 +115,7 @@ _IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
struct ioctl_gntdev_set_max_grants { struct ioctl_gntdev_set_max_grants {
/* IN parameter */ /* IN parameter */
/* The maximum number of grants that may be mapped at once. */ /* The maximum number of grants that may be mapped at once. */
uint32_t count; __u32 count;
}; };
/* /*
...@@ -135,11 +137,11 @@ struct ioctl_gntdev_unmap_notify { ...@@ -135,11 +137,11 @@ struct ioctl_gntdev_unmap_notify {
* be cleared. Otherwise, it can be any byte in the page whose * be cleared. Otherwise, it can be any byte in the page whose
* notification we are adjusting. * notification we are adjusting.
*/ */
uint64_t index; __u64 index;
/* Action(s) to take on unmap */ /* Action(s) to take on unmap */
uint32_t action; __u32 action;
/* Event channel to notify */ /* Event channel to notify */
uint32_t event_channel_port; __u32 event_channel_port;
}; };
/* Clear (set to zero) the byte specified by index */ /* Clear (set to zero) the byte specified by index */
......
...@@ -8,30 +8,24 @@ struct balloon_stats { ...@@ -8,30 +8,24 @@ struct balloon_stats {
/* We aim for 'current allocation' == 'target allocation'. */ /* We aim for 'current allocation' == 'target allocation'. */
unsigned long current_pages; unsigned long current_pages;
unsigned long target_pages; unsigned long target_pages;
unsigned long target_unpopulated;
/* Number of pages in high- and low-memory balloons. */ /* Number of pages in high- and low-memory balloons. */
unsigned long balloon_low; unsigned long balloon_low;
unsigned long balloon_high; unsigned long balloon_high;
unsigned long total_pages;
unsigned long schedule_delay; unsigned long schedule_delay;
unsigned long max_schedule_delay; unsigned long max_schedule_delay;
unsigned long retry_count; unsigned long retry_count;
unsigned long max_retry_count; unsigned long max_retry_count;
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
unsigned long hotplug_pages;
unsigned long balloon_hotplug;
#endif
}; };
extern struct balloon_stats balloon_stats; extern struct balloon_stats balloon_stats;
void balloon_set_new_target(unsigned long target); void balloon_set_new_target(unsigned long target);
int alloc_xenballooned_pages(int nr_pages, struct page **pages, int alloc_xenballooned_pages(int nr_pages, struct page **pages);
bool highmem);
void free_xenballooned_pages(int nr_pages, struct page **pages); void free_xenballooned_pages(int nr_pages, struct page **pages);
struct page *get_balloon_scratch_page(void);
void put_balloon_scratch_page(void);
struct device; struct device;
#ifdef CONFIG_XEN_SELFBALLOONING #ifdef CONFIG_XEN_SELFBALLOONING
extern int register_xen_selfballooning(struct device *dev); extern int register_xen_selfballooning(struct device *dev);
......
...@@ -45,8 +45,10 @@ ...@@ -45,8 +45,10 @@
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/features.h> #include <xen/features.h>
#include <xen/page.h>
#include <linux/mm_types.h> #include <linux/mm_types.h>
#include <linux/page-flags.h> #include <linux/page-flags.h>
#include <linux/kernel.h>
#define GNTTAB_RESERVED_XENSTORE 1 #define GNTTAB_RESERVED_XENSTORE 1
...@@ -129,6 +131,15 @@ void gnttab_cancel_free_callback(struct gnttab_free_callback *callback); ...@@ -129,6 +131,15 @@ void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
unsigned long frame, int readonly); unsigned long frame, int readonly);
/* Give access to the first 4K of the page */
static inline void gnttab_page_grant_foreign_access_ref_one(
grant_ref_t ref, domid_t domid,
struct page *page, int readonly)
{
gnttab_grant_foreign_access_ref(ref, domid, xen_page_to_gfn(page),
readonly);
}
void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid, void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
unsigned long pfn); unsigned long pfn);
...@@ -224,4 +235,50 @@ static inline struct xen_page_foreign *xen_page_foreign(struct page *page) ...@@ -224,4 +235,50 @@ static inline struct xen_page_foreign *xen_page_foreign(struct page *page)
#endif #endif
} }
/* Split Linux page in chunk of the size of the grant and call fn
*
* Parameters of fn:
* gfn: guest frame number
* offset: offset in the grant
* len: length of the data in the grant.
* data: internal information
*/
typedef void (*xen_grant_fn_t)(unsigned long gfn, unsigned int offset,
unsigned int len, void *data);
void gnttab_foreach_grant_in_range(struct page *page,
unsigned int offset,
unsigned int len,
xen_grant_fn_t fn,
void *data);
/* Helper to get to call fn only on the first "grant chunk" */
static inline void gnttab_for_one_grant(struct page *page, unsigned int offset,
unsigned len, xen_grant_fn_t fn,
void *data)
{
/* The first request is limited to the size of one grant */
len = min_t(unsigned int, XEN_PAGE_SIZE - (offset & ~XEN_PAGE_MASK),
len);
gnttab_foreach_grant_in_range(page, offset, len, fn, data);
}
/* Get @nr_grefs grants from an array of page and call fn for each grant */
void gnttab_foreach_grant(struct page **pages,
unsigned int nr_grefs,
xen_grant_fn_t fn,
void *data);
/* Get the number of grant in a specified region
*
* start: Offset from the beginning of the first page
* len: total length of data (can cross multiple page)
*/
static inline unsigned int gnttab_count_grant(unsigned int start,
unsigned int len)
{
return XEN_PFN_UP(xen_offset_in_page(start) + len);
}
#endif /* __ASM_GNTTAB_H__ */ #endif /* __ASM_GNTTAB_H__ */
#ifndef _XEN_PAGE_H #ifndef _XEN_PAGE_H
#define _XEN_PAGE_H #define _XEN_PAGE_H
#include <asm/page.h>
/* The hypercall interface supports only 4KB page */
#define XEN_PAGE_SHIFT 12
#define XEN_PAGE_SIZE (_AC(1, UL) << XEN_PAGE_SHIFT)
#define XEN_PAGE_MASK (~(XEN_PAGE_SIZE-1))
#define xen_offset_in_page(p) ((unsigned long)(p) & ~XEN_PAGE_MASK)
/*
* We assume that PAGE_SIZE is a multiple of XEN_PAGE_SIZE
* XXX: Add a BUILD_BUG_ON?
*/
#define xen_pfn_to_page(xen_pfn) \
((pfn_to_page(((unsigned long)(xen_pfn) << XEN_PAGE_SHIFT) >> PAGE_SHIFT)))
#define page_to_xen_pfn(page) \
(((page_to_pfn(page)) << PAGE_SHIFT) >> XEN_PAGE_SHIFT)
#define XEN_PFN_PER_PAGE (PAGE_SIZE / XEN_PAGE_SIZE)
#define XEN_PFN_DOWN(x) ((x) >> XEN_PAGE_SHIFT)
#define XEN_PFN_UP(x) (((x) + XEN_PAGE_SIZE-1) >> XEN_PAGE_SHIFT)
#define XEN_PFN_PHYS(x) ((phys_addr_t)(x) << XEN_PAGE_SHIFT)
#include <asm/xen/page.h> #include <asm/xen/page.h>
/* Return the GFN associated to the first 4KB of the page */
static inline unsigned long xen_page_to_gfn(struct page *page) static inline unsigned long xen_page_to_gfn(struct page *page)
{ {
return pfn_to_gfn(page_to_pfn(page)); return pfn_to_gfn(page_to_xen_pfn(page));
} }
struct xen_memory_region { struct xen_memory_region {
......
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
#include <xen/interface/io/xenbus.h> #include <xen/interface/io/xenbus.h>
#include <xen/interface/io/xs_wire.h> #include <xen/interface/io/xs_wire.h>
#define XENBUS_MAX_RING_PAGE_ORDER 4 #define XENBUS_MAX_RING_GRANT_ORDER 4
#define XENBUS_MAX_RING_PAGES (1U << XENBUS_MAX_RING_PAGE_ORDER) #define XENBUS_MAX_RING_GRANTS (1U << XENBUS_MAX_RING_GRANT_ORDER)
#define INVALID_GRANT_HANDLE (~0U) #define INVALID_GRANT_HANDLE (~0U)
/* Register callback to watch this node. */ /* Register callback to watch this node. */
......
...@@ -1232,23 +1232,21 @@ int zone_for_memory(int nid, u64 start, u64 size, int zone_default, ...@@ -1232,23 +1232,21 @@ int zone_for_memory(int nid, u64 start, u64 size, int zone_default,
} }
/* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
int __ref add_memory(int nid, u64 start, u64 size) int __ref add_memory_resource(int nid, struct resource *res)
{ {
u64 start, size;
pg_data_t *pgdat = NULL; pg_data_t *pgdat = NULL;
bool new_pgdat; bool new_pgdat;
bool new_node; bool new_node;
struct resource *res;
int ret; int ret;
start = res->start;
size = resource_size(res);
ret = check_hotplug_memory_range(start, size); ret = check_hotplug_memory_range(start, size);
if (ret) if (ret)
return ret; return ret;
res = register_memory_resource(start, size);
ret = -EEXIST;
if (!res)
return ret;
{ /* Stupid hack to suppress address-never-null warning */ { /* Stupid hack to suppress address-never-null warning */
void *p = NODE_DATA(nid); void *p = NODE_DATA(nid);
new_pgdat = !p; new_pgdat = !p;
...@@ -1300,13 +1298,28 @@ int __ref add_memory(int nid, u64 start, u64 size) ...@@ -1300,13 +1298,28 @@ int __ref add_memory(int nid, u64 start, u64 size)
/* rollback pgdat allocation and others */ /* rollback pgdat allocation and others */
if (new_pgdat) if (new_pgdat)
rollback_node_hotadd(nid, pgdat); rollback_node_hotadd(nid, pgdat);
release_memory_resource(res);
memblock_remove(start, size); memblock_remove(start, size);
out: out:
mem_hotplug_done(); mem_hotplug_done();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(add_memory_resource);
int __ref add_memory(int nid, u64 start, u64 size)
{
struct resource *res;
int ret;
res = register_memory_resource(start, size);
if (!res)
return -EEXIST;
ret = add_memory_resource(nid, res);
if (ret < 0)
release_memory_resource(res);
return ret;
}
EXPORT_SYMBOL_GPL(add_memory); EXPORT_SYMBOL_GPL(add_memory);
#ifdef CONFIG_MEMORY_HOTREMOVE #ifdef CONFIG_MEMORY_HOTREMOVE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment