Skip to content

Commit 5e98596

Browse files
dgibsonpaulusmack
authored andcommitted
KVM: PPC: Book3S HV: Outline of KVM-HV HPT resizing implementation
This adds a not yet working outline of the HPT resizing PAPR extension. Specifically it adds the necessary ioctl() functions, their basic steps, the work function which will handle preparation for the resize, and synchronization between these, the guest page fault path and guest HPT update path. The actual guts of the implementation isn't here yet, so for now the calls will always fail. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
1 parent 639e459 commit 5e98596

File tree

4 files changed

+223
-0
lines changed

4 files changed

+223
-0
lines changed

arch/powerpc/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ struct kvm_hpt_info {
252252
int cma;
253253
};
254254

255+
struct kvm_resize_hpt;
256+
255257
struct kvm_arch {
256258
unsigned int lpid;
257259
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
@@ -276,6 +278,7 @@ struct kvm_arch {
276278
u64 process_table;
277279
struct dentry *debugfs_dir;
278280
struct dentry *htab_dentry;
281+
struct kvm_resize_hpt *resize_hpt; /* protected by kvm->lock */
279282
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
280283
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
281284
struct mutex hpt_mutex;

arch/powerpc/include/asm/kvm_ppc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ extern void kvmppc_bookehv_exit(void);
215215
extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu);
216216

217217
extern int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *);
218+
extern long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm,
219+
struct kvm_ppc_resize_hpt *rhpt);
220+
extern long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm,
221+
struct kvm_ppc_resize_hpt *rhpt);
218222

219223
int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
220224

arch/powerpc/kvm/book3s_64_mmu_hv.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,34 @@
4040

4141
#include "trace_hv.h"
4242

43+
//#define DEBUG_RESIZE_HPT 1
44+
45+
#ifdef DEBUG_RESIZE_HPT
46+
#define resize_hpt_debug(resize, ...) \
47+
do { \
48+
printk(KERN_DEBUG "RESIZE HPT %p: ", resize); \
49+
printk(__VA_ARGS__); \
50+
} while (0)
51+
#else
52+
#define resize_hpt_debug(resize, ...) \
53+
do { } while (0)
54+
#endif
55+
4356
static long kvmppc_virtmode_do_h_enter(struct kvm *kvm, unsigned long flags,
4457
long pte_index, unsigned long pteh,
4558
unsigned long ptel, unsigned long *pte_idx_ret);
59+
60+
struct kvm_resize_hpt {
61+
/* These fields read-only after init */
62+
struct kvm *kvm;
63+
struct work_struct work;
64+
u32 order;
65+
66+
/* These fields protected by kvm->lock */
67+
int error;
68+
bool prepare_done;
69+
};
70+
4671
static void kvmppc_rmap_reset(struct kvm *kvm);
4772

4873
int kvmppc_allocate_hpt(struct kvm_hpt_info *info, u32 order)
@@ -1179,6 +1204,172 @@ void kvmppc_unpin_guest_page(struct kvm *kvm, void *va, unsigned long gpa,
11791204
srcu_read_unlock(&kvm->srcu, srcu_idx);
11801205
}
11811206

1207+
/*
1208+
* HPT resizing
1209+
*/
1210+
static int resize_hpt_allocate(struct kvm_resize_hpt *resize)
1211+
{
1212+
return 0;
1213+
}
1214+
1215+
static int resize_hpt_rehash(struct kvm_resize_hpt *resize)
1216+
{
1217+
return -EIO;
1218+
}
1219+
1220+
static void resize_hpt_pivot(struct kvm_resize_hpt *resize)
1221+
{
1222+
}
1223+
1224+
static void resize_hpt_release(struct kvm *kvm, struct kvm_resize_hpt *resize)
1225+
{
1226+
BUG_ON(kvm->arch.resize_hpt != resize);
1227+
kvm->arch.resize_hpt = NULL;
1228+
kfree(resize);
1229+
}
1230+
1231+
static void resize_hpt_prepare_work(struct work_struct *work)
1232+
{
1233+
struct kvm_resize_hpt *resize = container_of(work,
1234+
struct kvm_resize_hpt,
1235+
work);
1236+
struct kvm *kvm = resize->kvm;
1237+
int err;
1238+
1239+
resize_hpt_debug(resize, "resize_hpt_prepare_work(): order = %d\n",
1240+
resize->order);
1241+
1242+
err = resize_hpt_allocate(resize);
1243+
1244+
mutex_lock(&kvm->lock);
1245+
1246+
resize->error = err;
1247+
resize->prepare_done = true;
1248+
1249+
mutex_unlock(&kvm->lock);
1250+
}
1251+
1252+
long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm,
1253+
struct kvm_ppc_resize_hpt *rhpt)
1254+
{
1255+
unsigned long flags = rhpt->flags;
1256+
unsigned long shift = rhpt->shift;
1257+
struct kvm_resize_hpt *resize;
1258+
int ret;
1259+
1260+
if (flags != 0)
1261+
return -EINVAL;
1262+
1263+
if (shift && ((shift < 18) || (shift > 46)))
1264+
return -EINVAL;
1265+
1266+
mutex_lock(&kvm->lock);
1267+
1268+
resize = kvm->arch.resize_hpt;
1269+
1270+
if (resize) {
1271+
if (resize->order == shift) {
1272+
/* Suitable resize in progress */
1273+
if (resize->prepare_done) {
1274+
ret = resize->error;
1275+
if (ret != 0)
1276+
resize_hpt_release(kvm, resize);
1277+
} else {
1278+
ret = 100; /* estimated time in ms */
1279+
}
1280+
1281+
goto out;
1282+
}
1283+
1284+
/* not suitable, cancel it */
1285+
resize_hpt_release(kvm, resize);
1286+
}
1287+
1288+
ret = 0;
1289+
if (!shift)
1290+
goto out; /* nothing to do */
1291+
1292+
/* start new resize */
1293+
1294+
resize = kzalloc(sizeof(*resize), GFP_KERNEL);
1295+
resize->order = shift;
1296+
resize->kvm = kvm;
1297+
INIT_WORK(&resize->work, resize_hpt_prepare_work);
1298+
kvm->arch.resize_hpt = resize;
1299+
1300+
schedule_work(&resize->work);
1301+
1302+
ret = 100; /* estimated time in ms */
1303+
1304+
out:
1305+
mutex_unlock(&kvm->lock);
1306+
return ret;
1307+
}
1308+
1309+
static void resize_hpt_boot_vcpu(void *opaque)
1310+
{
1311+
/* Nothing to do, just force a KVM exit */
1312+
}
1313+
1314+
long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm,
1315+
struct kvm_ppc_resize_hpt *rhpt)
1316+
{
1317+
unsigned long flags = rhpt->flags;
1318+
unsigned long shift = rhpt->shift;
1319+
struct kvm_resize_hpt *resize;
1320+
long ret;
1321+
1322+
if (flags != 0)
1323+
return -EINVAL;
1324+
1325+
if (shift && ((shift < 18) || (shift > 46)))
1326+
return -EINVAL;
1327+
1328+
mutex_lock(&kvm->lock);
1329+
1330+
resize = kvm->arch.resize_hpt;
1331+
1332+
/* This shouldn't be possible */
1333+
ret = -EIO;
1334+
if (WARN_ON(!kvm->arch.hpte_setup_done))
1335+
goto out_no_hpt;
1336+
1337+
/* Stop VCPUs from running while we mess with the HPT */
1338+
kvm->arch.hpte_setup_done = 0;
1339+
smp_mb();
1340+
1341+
/* Boot all CPUs out of the guest so they re-read
1342+
* hpte_setup_done */
1343+
on_each_cpu(resize_hpt_boot_vcpu, NULL, 1);
1344+
1345+
ret = -ENXIO;
1346+
if (!resize || (resize->order != shift))
1347+
goto out;
1348+
1349+
ret = -EBUSY;
1350+
if (!resize->prepare_done)
1351+
goto out;
1352+
1353+
ret = resize->error;
1354+
if (ret != 0)
1355+
goto out;
1356+
1357+
ret = resize_hpt_rehash(resize);
1358+
if (ret != 0)
1359+
goto out;
1360+
1361+
resize_hpt_pivot(resize);
1362+
1363+
out:
1364+
/* Let VCPUs run again */
1365+
kvm->arch.hpte_setup_done = 1;
1366+
smp_mb();
1367+
out_no_hpt:
1368+
resize_hpt_release(kvm, resize);
1369+
mutex_unlock(&kvm->lock);
1370+
return ret;
1371+
}
1372+
11821373
/*
11831374
* Functions for reading and writing the hash table via reads and
11841375
* writes on a file descriptor.

arch/powerpc/kvm/book3s_hv.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,6 +3422,9 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
34223422

34233423
kvm->arch.lpcr = lpcr;
34243424

3425+
/* Initialization for future HPT resizes */
3426+
kvm->arch.resize_hpt = NULL;
3427+
34253428
/*
34263429
* Work out how many sets the TLB has, for the use of
34273430
* the TLB invalidation loop in book3s_hv_rmhandlers.S.
@@ -3721,6 +3724,28 @@ static long kvm_arch_vm_ioctl_hv(struct file *filp,
37213724
break;
37223725
}
37233726

3727+
case KVM_PPC_RESIZE_HPT_PREPARE: {
3728+
struct kvm_ppc_resize_hpt rhpt;
3729+
3730+
r = -EFAULT;
3731+
if (copy_from_user(&rhpt, argp, sizeof(rhpt)))
3732+
break;
3733+
3734+
r = kvm_vm_ioctl_resize_hpt_prepare(kvm, &rhpt);
3735+
break;
3736+
}
3737+
3738+
case KVM_PPC_RESIZE_HPT_COMMIT: {
3739+
struct kvm_ppc_resize_hpt rhpt;
3740+
3741+
r = -EFAULT;
3742+
if (copy_from_user(&rhpt, argp, sizeof(rhpt)))
3743+
break;
3744+
3745+
r = kvm_vm_ioctl_resize_hpt_commit(kvm, &rhpt);
3746+
break;
3747+
}
3748+
37243749
default:
37253750
r = -ENOTTY;
37263751
}

0 commit comments

Comments
 (0)