#include <asm/vmx_vcpu.h>
#include <asm/vmx_pal_vsa.h>
#include <xen/sched-if.h>
+#include <asm/vhpt.h>
static int default_vtlb_sz = DEFAULT_VTLB_SZ;
static int default_vhpt_sz = DEFAULT_VHPT_SZ;
}
}
-static int canonicalize_vhpt_size(int sz)
-{
- /* minimum 32KB */
- if (sz < 15)
- return 15;
- /* maximum 8MB (since purging TR is hard coded) */
- if (sz > IA64_GRANULE_SHIFT - 1)
- return IA64_GRANULE_SHIFT - 1;
- return sz;
-}
-
static void __init parse_vhpt_size(char *s)
{
int sz = parse_size_and_unit(s, NULL);
static int init_domain_vhpt(struct vcpu *v)
{
int rc;
+ u64 size = v->domain->arch.hvm_domain.params[HVM_PARAM_VHPT_SIZE];
+
+ if (size == 0)
+ size = default_vhpt_sz;
+ else
+ size = canonicalize_vhpt_size(size);
- rc = thash_alloc(&(v->arch.vhpt), default_vhpt_sz, "vhpt");
+ rc = thash_alloc(&(v->arch.vhpt), size, "vhpt");
v->arch.arch_vmx.mpta = v->arch.vhpt.pta.val;
return rc;
}
ds->maxmem = d->arch.convmem_end;
ds->xsi_va = d->arch.shared_info_va;
ds->hypercall_imm = d->arch.breakimm;
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ ds->vhpt_size_log2 = d->arch.vhpt_size_log2;
+#endif
/* Copy back. */
if ( copy_to_guest(u_domctl, op, 1) )
ret = -EFAULT;
for_each_vcpu (d, v)
v->arch.breakimm = d->arch.breakimm;
}
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ if (ds->vhpt_size_log2 == -1) {
+ d->arch.has_pervcpu_vhpt = 0;
+ ds->vhpt_size_log2 = -1;
+ printk(XENLOG_INFO "XEN_DOMCTL_arch_setup: "
+ "domain %d VHPT is global.\n", d->domain_id);
+ } else {
+ d->arch.has_pervcpu_vhpt = 1;
+ d->arch.vhpt_size_log2 = ds->vhpt_size_log2;
+ printk(XENLOG_INFO "XEN_DOMCTL_arch_setup: "
+ "domain %d VHPT is per vcpu. size=2**%d\n",
+ d->domain_id, ds->vhpt_size_log2);
+ }
+#endif
if (ds->xsi_va)
d->arch.shared_info_va = ds->xsi_va;
ret = dom_fw_setup(d, ds->bp, ds->maxmem);
#endif
static void
-__vhpt_flush(unsigned long vhpt_maddr)
+__vhpt_flush(unsigned long vhpt_maddr, unsigned long vhpt_size_log2)
{
struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr);
+ unsigned long num_entries = 1 << (vhpt_size_log2 - 5);
int i;
- for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++)
+ for (i = 0; i < num_entries; i++, v++)
v->ti_tag = INVALID_TI_TAG;
}
{
/* increment flush clock before flush */
u32 flush_time = tlbflush_clock_inc_and_return();
- __vhpt_flush(__ia64_per_cpu_var(vhpt_paddr));
+ __vhpt_flush(__ia64_per_cpu_var(vhpt_paddr), VHPT_SIZE_LOG2);
/* this must be after flush */
tlbflush_update_time(&__get_cpu_var(vhpt_tlbflush_timestamp),
flush_time);
void
vcpu_vhpt_flush(struct vcpu* v)
{
- __vhpt_flush(vcpu_vhpt_maddr(v));
+ unsigned long vhpt_size_log2 = VHPT_SIZE_LOG2;
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ if (HAS_PERVCPU_VHPT(v->domain))
+ vhpt_size_log2 = v->arch.pta.size;
+#endif
+ __vhpt_flush(vcpu_vhpt_maddr(v), vhpt_size_log2);
perfc_incr(vcpu_vhpt_flush);
}
static void
-vhpt_erase(unsigned long vhpt_maddr)
+vhpt_erase(unsigned long vhpt_maddr, unsigned long vhpt_size_log2)
{
struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr);
+ unsigned long num_entries = 1 << (vhpt_size_log2 - 5);
int i;
- for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) {
+ for (i = 0; i < num_entries; i++, v++) {
v->itir = 0;
v->CChain = 0;
v->page_flags = 0;
__get_cpu_var(vhpt_pend) = paddr + (1 << VHPT_SIZE_LOG2) - 1;
printk(XENLOG_DEBUG "vhpt_init: vhpt paddr=0x%lx, end=0x%lx\n",
paddr, __get_cpu_var(vhpt_pend));
- vhpt_erase(paddr);
+ vhpt_erase(paddr, VHPT_SIZE_LOG2);
// we don't enable VHPT here.
// context_switch() or schedule_tail() does it.
}
{
unsigned long vhpt_size_log2 = VHPT_SIZE_LOG2;
+ if (v->domain->arch.vhpt_size_log2 > 0)
+ vhpt_size_log2 =
+ canonicalize_vhpt_size(v->domain->arch.vhpt_size_log2);
+ printk(XENLOG_DEBUG "%s vhpt_size_log2=%ld\n",
+ __func__, vhpt_size_log2);
v->arch.vhpt_entries =
(1UL << vhpt_size_log2) / sizeof(struct vhpt_lf_entry);
v->arch.vhpt_page =
v->arch.pta.val = 0; // to zero reserved bits
v->arch.pta.ve = 1; // enable vhpt
- v->arch.pta.size = VHPT_SIZE_LOG2;
+ v->arch.pta.size = vhpt_size_log2;
v->arch.pta.vf = 1; // long format
v->arch.pta.base = __va_ul(v->arch.vhpt_maddr) >> 15;
- vhpt_erase(v->arch.vhpt_maddr);
+ vhpt_erase(v->arch.vhpt_maddr, vhpt_size_log2);
smp_mb(); // per vcpu vhpt may be used by another physical cpu.
return 0;
}
{
if (likely(v->arch.vhpt_page != NULL))
free_domheap_pages(v->arch.vhpt_page,
- VHPT_SIZE_LOG2 - PAGE_SHIFT);
+ v->arch.pta.size - PAGE_SHIFT);
}
#endif