diff options
author | Scott Wood <scottwood@freescale.com> | 2011-08-18 16:25:18 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-03-05 07:52:23 -0500 |
commit | 0164c0f0c404017fb04defb0ceb23fd1c3c3a53e (patch) | |
tree | c161e2268a1dfd367701e6208f52461f8e9b1022 | |
parent | 90b92a6f51af9adf8c44e8ab3f435b336e5ba6ff (diff) |
KVM: PPC: e500: clear up confusion between host and guest entries
Split out the portions of tlbe_priv that should be associated with host
entries into tlbe_ref. Base victim selection on the number of hardware
entries, not guest entries.
For TLB1, where one guest entry can be mapped by multiple host entries,
we use the host tlbe_ref for tracking page references. For the guest
TLB0 entries, we still track it with gtlb_priv, to avoid having to
retranslate if the entry is evicted from the host TLB but not the
guest TLB.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/powerpc/include/asm/kvm_e500.h | 24 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mmu-book3e.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.c | 267 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.h | 17 |
4 files changed, 213 insertions, 96 deletions
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h index adbfca9dd100..a5197d816ec7 100644 --- a/arch/powerpc/include/asm/kvm_e500.h +++ b/arch/powerpc/include/asm/kvm_e500.h | |||
@@ -32,13 +32,21 @@ struct tlbe{ | |||
32 | #define E500_TLB_VALID 1 | 32 | #define E500_TLB_VALID 1 |
33 | #define E500_TLB_DIRTY 2 | 33 | #define E500_TLB_DIRTY 2 |
34 | 34 | ||
35 | struct tlbe_priv { | 35 | struct tlbe_ref { |
36 | pfn_t pfn; | 36 | pfn_t pfn; |
37 | unsigned int flags; /* E500_TLB_* */ | 37 | unsigned int flags; /* E500_TLB_* */ |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct tlbe_priv { | ||
41 | struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */ | ||
42 | }; | ||
43 | |||
40 | struct vcpu_id_table; | 44 | struct vcpu_id_table; |
41 | 45 | ||
46 | struct kvmppc_e500_tlb_params { | ||
47 | int entries, ways, sets; | ||
48 | }; | ||
49 | |||
42 | struct kvmppc_vcpu_e500 { | 50 | struct kvmppc_vcpu_e500 { |
43 | /* Unmodified copy of the guest's TLB. */ | 51 | /* Unmodified copy of the guest's TLB. */ |
44 | struct tlbe *gtlb_arch[E500_TLB_NUM]; | 52 | struct tlbe *gtlb_arch[E500_TLB_NUM]; |
@@ -49,6 +57,20 @@ struct kvmppc_vcpu_e500 { | |||
49 | unsigned int gtlb_size[E500_TLB_NUM]; | 57 | unsigned int gtlb_size[E500_TLB_NUM]; |
50 | unsigned int gtlb_nv[E500_TLB_NUM]; | 58 | unsigned int gtlb_nv[E500_TLB_NUM]; |
51 | 59 | ||
60 | /* | ||
61 | * information associated with each host TLB entry -- | ||
62 | * TLB1 only for now. If/when guest TLB1 entries can be | ||
63 | * mapped with host TLB0, this will be used for that too. | ||
64 | * | ||
65 | * We don't want to use this for guest TLB0 because then we'd | ||
66 | * have the overhead of doing the translation again even if | ||
67 | * the entry is still in the guest TLB (e.g. we swapped out | ||
68 | * and back, and our host TLB entries got evicted). | ||
69 | */ | ||
70 | struct tlbe_ref *tlb_refs[E500_TLB_NUM]; | ||
71 | |||
72 | unsigned int host_tlb1_nv; | ||
73 | |||
52 | u32 host_pid[E500_PID_NUM]; | 74 | u32 host_pid[E500_PID_NUM]; |
53 | u32 pid[E500_PID_NUM]; | 75 | u32 pid[E500_PID_NUM]; |
54 | u32 svr; | 76 | u32 svr; |
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index f5f89cafebd0..a0128232d9cc 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h | |||
@@ -167,6 +167,7 @@ | |||
167 | #define TLBnCFG_MAXSIZE 0x000f0000 /* Maximum Page Size (v1.0) */ | 167 | #define TLBnCFG_MAXSIZE 0x000f0000 /* Maximum Page Size (v1.0) */ |
168 | #define TLBnCFG_MAXSIZE_SHIFT 16 | 168 | #define TLBnCFG_MAXSIZE_SHIFT 16 |
169 | #define TLBnCFG_ASSOC 0xff000000 /* Associativity */ | 169 | #define TLBnCFG_ASSOC 0xff000000 /* Associativity */ |
170 | #define TLBnCFG_ASSOC_SHIFT 24 | ||
170 | 171 | ||
171 | /* TLBnPS encoding */ | 172 | /* TLBnPS encoding */ |
172 | #define TLBnPS_4K 0x00000004 | 173 | #define TLBnPS_4K 0x00000004 |
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index b976d8025e58..59221bb1e00e 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/kernel.h> | ||
15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/string.h> | 18 | #include <linux/string.h> |
@@ -26,7 +27,7 @@ | |||
26 | #include "trace.h" | 27 | #include "trace.h" |
27 | #include "timing.h" | 28 | #include "timing.h" |
28 | 29 | ||
29 | #define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1) | 30 | #define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1) |
30 | 31 | ||
31 | struct id { | 32 | struct id { |
32 | unsigned long val; | 33 | unsigned long val; |
@@ -63,7 +64,7 @@ static DEFINE_PER_CPU(struct pcpu_id_table, pcpu_sids); | |||
63 | * The valid range of shadow ID is [1..255] */ | 64 | * The valid range of shadow ID is [1..255] */ |
64 | static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid); | 65 | static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid); |
65 | 66 | ||
66 | static unsigned int tlb1_entry_num; | 67 | static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM]; |
67 | 68 | ||
68 | /* | 69 | /* |
69 | * Allocate a free shadow id and setup a valid sid mapping in given entry. | 70 | * Allocate a free shadow id and setup a valid sid mapping in given entry. |
@@ -237,7 +238,7 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | |||
237 | } | 238 | } |
238 | } | 239 | } |
239 | 240 | ||
240 | static inline unsigned int tlb0_get_next_victim( | 241 | static inline unsigned int gtlb0_get_next_victim( |
241 | struct kvmppc_vcpu_e500 *vcpu_e500) | 242 | struct kvmppc_vcpu_e500 *vcpu_e500) |
242 | { | 243 | { |
243 | unsigned int victim; | 244 | unsigned int victim; |
@@ -252,7 +253,7 @@ static inline unsigned int tlb0_get_next_victim( | |||
252 | static inline unsigned int tlb1_max_shadow_size(void) | 253 | static inline unsigned int tlb1_max_shadow_size(void) |
253 | { | 254 | { |
254 | /* reserve one entry for magic page */ | 255 | /* reserve one entry for magic page */ |
255 | return tlb1_entry_num - tlbcam_index - 1; | 256 | return host_tlb_params[1].entries - tlbcam_index - 1; |
256 | } | 257 | } |
257 | 258 | ||
258 | static inline int tlbe_is_writable(struct tlbe *tlbe) | 259 | static inline int tlbe_is_writable(struct tlbe *tlbe) |
@@ -302,13 +303,12 @@ static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0) | |||
302 | local_irq_restore(flags); | 303 | local_irq_restore(flags); |
303 | } | 304 | } |
304 | 305 | ||
306 | /* esel is index into set, not whole array */ | ||
305 | static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | 307 | static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, |
306 | int tlbsel, int esel, struct tlbe *stlbe) | 308 | int tlbsel, int esel, struct tlbe *stlbe) |
307 | { | 309 | { |
308 | if (tlbsel == 0) { | 310 | if (tlbsel == 0) { |
309 | __write_host_tlbe(stlbe, | 311 | __write_host_tlbe(stlbe, MAS0_TLBSEL(0) | MAS0_ESEL(esel)); |
310 | MAS0_TLBSEL(0) | | ||
311 | MAS0_ESEL(esel & (KVM_E500_TLB0_WAY_NUM - 1))); | ||
312 | } else { | 312 | } else { |
313 | __write_host_tlbe(stlbe, | 313 | __write_host_tlbe(stlbe, |
314 | MAS0_TLBSEL(1) | | 314 | MAS0_TLBSEL(1) | |
@@ -355,8 +355,8 @@ void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) | |||
355 | { | 355 | { |
356 | } | 356 | } |
357 | 357 | ||
358 | static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | 358 | static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, |
359 | int tlbsel, int esel) | 359 | int tlbsel, int esel) |
360 | { | 360 | { |
361 | struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | 361 | struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
362 | struct vcpu_id_table *idt = vcpu_e500->idt; | 362 | struct vcpu_id_table *idt = vcpu_e500->idt; |
@@ -412,18 +412,53 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
412 | preempt_enable(); | 412 | preempt_enable(); |
413 | } | 413 | } |
414 | 414 | ||
415 | static int tlb0_set_base(gva_t addr, int sets, int ways) | ||
416 | { | ||
417 | int set_base; | ||
418 | |||
419 | set_base = (addr >> PAGE_SHIFT) & (sets - 1); | ||
420 | set_base *= ways; | ||
421 | |||
422 | return set_base; | ||
423 | } | ||
424 | |||
425 | static int gtlb0_set_base(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t addr) | ||
426 | { | ||
427 | int sets = KVM_E500_TLB0_SIZE / KVM_E500_TLB0_WAY_NUM; | ||
428 | |||
429 | return tlb0_set_base(addr, sets, KVM_E500_TLB0_WAY_NUM); | ||
430 | } | ||
431 | |||
432 | static int htlb0_set_base(gva_t addr) | ||
433 | { | ||
434 | return tlb0_set_base(addr, host_tlb_params[0].sets, | ||
435 | host_tlb_params[0].ways); | ||
436 | } | ||
437 | |||
438 | static unsigned int get_tlb_esel(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel) | ||
439 | { | ||
440 | unsigned int esel = get_tlb_esel_bit(vcpu_e500); | ||
441 | |||
442 | if (tlbsel == 0) { | ||
443 | esel &= KVM_E500_TLB0_WAY_NUM_MASK; | ||
444 | esel += gtlb0_set_base(vcpu_e500, vcpu_e500->mas2); | ||
445 | } else { | ||
446 | esel &= vcpu_e500->gtlb_size[tlbsel] - 1; | ||
447 | } | ||
448 | |||
449 | return esel; | ||
450 | } | ||
451 | |||
415 | /* Search the guest TLB for a matching entry. */ | 452 | /* Search the guest TLB for a matching entry. */ |
416 | static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, | 453 | static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, |
417 | gva_t eaddr, int tlbsel, unsigned int pid, int as) | 454 | gva_t eaddr, int tlbsel, unsigned int pid, int as) |
418 | { | 455 | { |
419 | int size = vcpu_e500->gtlb_size[tlbsel]; | 456 | int size = vcpu_e500->gtlb_size[tlbsel]; |
420 | int set_base; | 457 | unsigned int set_base; |
421 | int i; | 458 | int i; |
422 | 459 | ||
423 | if (tlbsel == 0) { | 460 | if (tlbsel == 0) { |
424 | int mask = size / KVM_E500_TLB0_WAY_NUM - 1; | 461 | set_base = gtlb0_set_base(vcpu_e500, eaddr); |
425 | set_base = (eaddr >> PAGE_SHIFT) & mask; | ||
426 | set_base *= KVM_E500_TLB0_WAY_NUM; | ||
427 | size = KVM_E500_TLB0_WAY_NUM; | 462 | size = KVM_E500_TLB0_WAY_NUM; |
428 | } else { | 463 | } else { |
429 | set_base = 0; | 464 | set_base = 0; |
@@ -455,29 +490,55 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
455 | return -1; | 490 | return -1; |
456 | } | 491 | } |
457 | 492 | ||
458 | static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv, | 493 | static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, |
459 | struct tlbe *gtlbe, | 494 | struct tlbe *gtlbe, |
460 | pfn_t pfn) | 495 | pfn_t pfn) |
461 | { | 496 | { |
462 | priv->pfn = pfn; | 497 | ref->pfn = pfn; |
463 | priv->flags = E500_TLB_VALID; | 498 | ref->flags = E500_TLB_VALID; |
464 | 499 | ||
465 | if (tlbe_is_writable(gtlbe)) | 500 | if (tlbe_is_writable(gtlbe)) |
466 | priv->flags |= E500_TLB_DIRTY; | 501 | ref->flags |= E500_TLB_DIRTY; |
467 | } | 502 | } |
468 | 503 | ||
469 | static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv) | 504 | static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) |
470 | { | 505 | { |
471 | if (priv->flags & E500_TLB_VALID) { | 506 | if (ref->flags & E500_TLB_VALID) { |
472 | if (priv->flags & E500_TLB_DIRTY) | 507 | if (ref->flags & E500_TLB_DIRTY) |
473 | kvm_release_pfn_dirty(priv->pfn); | 508 | kvm_release_pfn_dirty(ref->pfn); |
474 | else | 509 | else |
475 | kvm_release_pfn_clean(priv->pfn); | 510 | kvm_release_pfn_clean(ref->pfn); |
511 | |||
512 | ref->flags = 0; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
517 | { | ||
518 | int tlbsel = 0; | ||
519 | int i; | ||
476 | 520 | ||
477 | priv->flags = 0; | 521 | for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) { |
522 | struct tlbe_ref *ref = | ||
523 | &vcpu_e500->gtlb_priv[tlbsel][i].ref; | ||
524 | kvmppc_e500_ref_release(ref); | ||
478 | } | 525 | } |
479 | } | 526 | } |
480 | 527 | ||
528 | static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
529 | { | ||
530 | int stlbsel = 1; | ||
531 | int i; | ||
532 | |||
533 | for (i = 0; i < host_tlb_params[stlbsel].entries; i++) { | ||
534 | struct tlbe_ref *ref = | ||
535 | &vcpu_e500->tlb_refs[stlbsel][i]; | ||
536 | kvmppc_e500_ref_release(ref); | ||
537 | } | ||
538 | |||
539 | clear_tlb_privs(vcpu_e500); | ||
540 | } | ||
541 | |||
481 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | 542 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, |
482 | unsigned int eaddr, int as) | 543 | unsigned int eaddr, int as) |
483 | { | 544 | { |
@@ -487,7 +548,7 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | |||
487 | 548 | ||
488 | /* since we only have two TLBs, only lower bit is used. */ | 549 | /* since we only have two TLBs, only lower bit is used. */ |
489 | tlbsel = (vcpu_e500->mas4 >> 28) & 0x1; | 550 | tlbsel = (vcpu_e500->mas4 >> 28) & 0x1; |
490 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; | 551 | victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0; |
491 | pidsel = (vcpu_e500->mas4 >> 16) & 0xf; | 552 | pidsel = (vcpu_e500->mas4 >> 16) & 0xf; |
492 | tsized = (vcpu_e500->mas4 >> 7) & 0x1f; | 553 | tsized = (vcpu_e500->mas4 >> 7) & 0x1f; |
493 | 554 | ||
@@ -508,10 +569,12 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | |||
508 | /* TID must be supplied by the caller */ | 569 | /* TID must be supplied by the caller */ |
509 | static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | 570 | static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, |
510 | struct tlbe *gtlbe, int tsize, | 571 | struct tlbe *gtlbe, int tsize, |
511 | struct tlbe_priv *priv, | 572 | struct tlbe_ref *ref, |
512 | u64 gvaddr, struct tlbe *stlbe) | 573 | u64 gvaddr, struct tlbe *stlbe) |
513 | { | 574 | { |
514 | pfn_t pfn = priv->pfn; | 575 | pfn_t pfn = ref->pfn; |
576 | |||
577 | BUG_ON(!(ref->flags & E500_TLB_VALID)); | ||
515 | 578 | ||
516 | /* Force TS=1 IPROT=0 for all guest mappings. */ | 579 | /* Force TS=1 IPROT=0 for all guest mappings. */ |
517 | stlbe->mas1 = MAS1_TSIZE(tsize) | MAS1_TS | MAS1_VALID; | 580 | stlbe->mas1 = MAS1_TSIZE(tsize) | MAS1_TS | MAS1_VALID; |
@@ -524,16 +587,15 @@ static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
524 | stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN; | 587 | stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN; |
525 | } | 588 | } |
526 | 589 | ||
527 | 590 | /* sesel is an index into the entire array, not just the set */ | |
528 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 591 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
529 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel, | 592 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int sesel, |
530 | struct tlbe *stlbe) | 593 | struct tlbe *stlbe, struct tlbe_ref *ref) |
531 | { | 594 | { |
532 | struct kvm_memory_slot *slot; | 595 | struct kvm_memory_slot *slot; |
533 | unsigned long pfn, hva; | 596 | unsigned long pfn, hva; |
534 | int pfnmap = 0; | 597 | int pfnmap = 0; |
535 | int tsize = BOOK3E_PAGESZ_4K; | 598 | int tsize = BOOK3E_PAGESZ_4K; |
536 | struct tlbe_priv *priv; | ||
537 | 599 | ||
538 | /* | 600 | /* |
539 | * Translate guest physical to true physical, acquiring | 601 | * Translate guest physical to true physical, acquiring |
@@ -629,12 +691,11 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
629 | } | 691 | } |
630 | } | 692 | } |
631 | 693 | ||
632 | /* Drop old priv and setup new one. */ | 694 | /* Drop old ref and setup new one. */ |
633 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; | 695 | kvmppc_e500_ref_release(ref); |
634 | kvmppc_e500_priv_release(priv); | 696 | kvmppc_e500_ref_setup(ref, gtlbe, pfn); |
635 | kvmppc_e500_priv_setup(priv, gtlbe, pfn); | ||
636 | 697 | ||
637 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe); | 698 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, ref, gvaddr, stlbe); |
638 | } | 699 | } |
639 | 700 | ||
640 | /* XXX only map the one-one case, for now use TLB0 */ | 701 | /* XXX only map the one-one case, for now use TLB0 */ |
@@ -642,14 +703,22 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
642 | int esel, struct tlbe *stlbe) | 703 | int esel, struct tlbe *stlbe) |
643 | { | 704 | { |
644 | struct tlbe *gtlbe; | 705 | struct tlbe *gtlbe; |
706 | struct tlbe_ref *ref; | ||
707 | int sesel = esel & (host_tlb_params[0].ways - 1); | ||
708 | int sesel_base; | ||
709 | gva_t ea; | ||
645 | 710 | ||
646 | gtlbe = &vcpu_e500->gtlb_arch[0][esel]; | 711 | gtlbe = &vcpu_e500->gtlb_arch[0][esel]; |
712 | ref = &vcpu_e500->gtlb_priv[0][esel].ref; | ||
713 | |||
714 | ea = get_tlb_eaddr(gtlbe); | ||
715 | sesel_base = htlb0_set_base(ea); | ||
647 | 716 | ||
648 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), | 717 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), |
649 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, | 718 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, |
650 | gtlbe, 0, esel, stlbe); | 719 | gtlbe, 0, sesel_base + sesel, stlbe, ref); |
651 | 720 | ||
652 | return esel; | 721 | return sesel; |
653 | } | 722 | } |
654 | 723 | ||
655 | /* Caller must ensure that the specified guest TLB entry is safe to insert into | 724 | /* Caller must ensure that the specified guest TLB entry is safe to insert into |
@@ -658,14 +727,17 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
658 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 727 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
659 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe) | 728 | u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe) |
660 | { | 729 | { |
730 | struct tlbe_ref *ref; | ||
661 | unsigned int victim; | 731 | unsigned int victim; |
662 | 732 | ||
663 | victim = vcpu_e500->gtlb_nv[1]++; | 733 | victim = vcpu_e500->host_tlb1_nv++; |
664 | 734 | ||
665 | if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size())) | 735 | if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size())) |
666 | vcpu_e500->gtlb_nv[1] = 0; | 736 | vcpu_e500->host_tlb1_nv = 0; |
667 | 737 | ||
668 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe); | 738 | ref = &vcpu_e500->tlb_refs[1][victim]; |
739 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, | ||
740 | victim, stlbe, ref); | ||
669 | 741 | ||
670 | return victim; | 742 | return victim; |
671 | } | 743 | } |
@@ -792,7 +864,7 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb) | |||
792 | 864 | ||
793 | /* since we only have two TLBs, only lower bit is used. */ | 865 | /* since we only have two TLBs, only lower bit is used. */ |
794 | tlbsel = vcpu_e500->mas4 >> 28 & 0x1; | 866 | tlbsel = vcpu_e500->mas4 >> 28 & 0x1; |
795 | victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0; | 867 | victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0; |
796 | 868 | ||
797 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) | 869 | vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim) |
798 | | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); | 870 | | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]); |
@@ -839,7 +911,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
839 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | 911 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
840 | 912 | ||
841 | if (get_tlb_v(gtlbe)) | 913 | if (get_tlb_v(gtlbe)) |
842 | kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); | 914 | inval_gtlbe_on_host(vcpu_e500, tlbsel, esel); |
843 | 915 | ||
844 | gtlbe->mas1 = vcpu_e500->mas1; | 916 | gtlbe->mas1 = vcpu_e500->mas1; |
845 | gtlbe->mas2 = vcpu_e500->mas2; | 917 | gtlbe->mas2 = vcpu_e500->mas2; |
@@ -950,11 +1022,11 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
950 | switch (tlbsel) { | 1022 | switch (tlbsel) { |
951 | case 0: | 1023 | case 0: |
952 | stlbsel = 0; | 1024 | stlbsel = 0; |
953 | sesel = esel; | 1025 | sesel = esel & (host_tlb_params[0].ways - 1); |
954 | priv = &vcpu_e500->gtlb_priv[stlbsel][sesel]; | 1026 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; |
955 | 1027 | ||
956 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K, | 1028 | kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K, |
957 | priv, eaddr, &stlbe); | 1029 | &priv->ref, eaddr, &stlbe); |
958 | break; | 1030 | break; |
959 | 1031 | ||
960 | case 1: { | 1032 | case 1: { |
@@ -1020,32 +1092,76 @@ void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
1020 | 1092 | ||
1021 | int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | 1093 | int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) |
1022 | { | 1094 | { |
1023 | tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF; | 1095 | host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY; |
1096 | host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; | ||
1097 | |||
1098 | /* | ||
1099 | * This should never happen on real e500 hardware, but is | ||
1100 | * architecturally possible -- e.g. in some weird nested | ||
1101 | * virtualization case. | ||
1102 | */ | ||
1103 | if (host_tlb_params[0].entries == 0 || | ||
1104 | host_tlb_params[1].entries == 0) { | ||
1105 | pr_err("%s: need to know host tlb size\n", __func__); | ||
1106 | return -ENODEV; | ||
1107 | } | ||
1108 | |||
1109 | host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >> | ||
1110 | TLBnCFG_ASSOC_SHIFT; | ||
1111 | host_tlb_params[1].ways = host_tlb_params[1].entries; | ||
1112 | |||
1113 | if (!is_power_of_2(host_tlb_params[0].entries) || | ||
1114 | !is_power_of_2(host_tlb_params[0].ways) || | ||
1115 | host_tlb_params[0].entries < host_tlb_params[0].ways || | ||
1116 | host_tlb_params[0].ways == 0) { | ||
1117 | pr_err("%s: bad tlb0 host config: %u entries %u ways\n", | ||
1118 | __func__, host_tlb_params[0].entries, | ||
1119 | host_tlb_params[0].ways); | ||
1120 | return -ENODEV; | ||
1121 | } | ||
1122 | |||
1123 | host_tlb_params[0].sets = | ||
1124 | host_tlb_params[0].entries / host_tlb_params[0].ways; | ||
1125 | host_tlb_params[1].sets = 1; | ||
1024 | 1126 | ||
1025 | vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE; | 1127 | vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE; |
1026 | vcpu_e500->gtlb_arch[0] = | 1128 | vcpu_e500->gtlb_arch[0] = |
1027 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | 1129 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL); |
1028 | if (vcpu_e500->gtlb_arch[0] == NULL) | 1130 | if (vcpu_e500->gtlb_arch[0] == NULL) |
1029 | goto err_out; | 1131 | goto err; |
1030 | 1132 | ||
1031 | vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE; | 1133 | vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE; |
1032 | vcpu_e500->gtlb_arch[1] = | 1134 | vcpu_e500->gtlb_arch[1] = |
1033 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); | 1135 | kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL); |
1034 | if (vcpu_e500->gtlb_arch[1] == NULL) | 1136 | if (vcpu_e500->gtlb_arch[1] == NULL) |
1035 | goto err_out_guest0; | 1137 | goto err; |
1036 | 1138 | ||
1037 | vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *) | 1139 | vcpu_e500->tlb_refs[0] = |
1038 | kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL); | 1140 | kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries, |
1039 | if (vcpu_e500->gtlb_priv[0] == NULL) | 1141 | GFP_KERNEL); |
1040 | goto err_out_guest1; | 1142 | if (!vcpu_e500->tlb_refs[0]) |
1041 | vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *) | 1143 | goto err; |
1042 | kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL); | 1144 | |
1043 | 1145 | vcpu_e500->tlb_refs[1] = | |
1044 | if (vcpu_e500->gtlb_priv[1] == NULL) | 1146 | kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries, |
1045 | goto err_out_priv0; | 1147 | GFP_KERNEL); |
1148 | if (!vcpu_e500->tlb_refs[1]) | ||
1149 | goto err; | ||
1150 | |||
1151 | vcpu_e500->gtlb_priv[0] = | ||
1152 | kzalloc(sizeof(struct tlbe_ref) * vcpu_e500->gtlb_size[0], | ||
1153 | GFP_KERNEL); | ||
1154 | if (!vcpu_e500->gtlb_priv[0]) | ||
1155 | goto err; | ||
1156 | |||
1157 | vcpu_e500->gtlb_priv[1] = | ||
1158 | kzalloc(sizeof(struct tlbe_ref) * vcpu_e500->gtlb_size[1], | ||
1159 | GFP_KERNEL); | ||
1160 | if (!vcpu_e500->gtlb_priv[1]) | ||
1161 | goto err; | ||
1046 | 1162 | ||
1047 | if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL) | 1163 | if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL) |
1048 | goto err_out_priv1; | 1164 | goto err; |
1049 | 1165 | ||
1050 | /* Init TLB configuration register */ | 1166 | /* Init TLB configuration register */ |
1051 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; | 1167 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; |
@@ -1055,31 +1171,26 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
1055 | 1171 | ||
1056 | return 0; | 1172 | return 0; |
1057 | 1173 | ||
1058 | err_out_priv1: | 1174 | err: |
1059 | kfree(vcpu_e500->gtlb_priv[1]); | 1175 | kfree(vcpu_e500->tlb_refs[0]); |
1060 | err_out_priv0: | 1176 | kfree(vcpu_e500->tlb_refs[1]); |
1061 | kfree(vcpu_e500->gtlb_priv[0]); | 1177 | kfree(vcpu_e500->gtlb_priv[0]); |
1062 | err_out_guest1: | 1178 | kfree(vcpu_e500->gtlb_priv[1]); |
1063 | kfree(vcpu_e500->gtlb_arch[1]); | ||
1064 | err_out_guest0: | ||
1065 | kfree(vcpu_e500->gtlb_arch[0]); | 1179 | kfree(vcpu_e500->gtlb_arch[0]); |
1066 | err_out: | 1180 | kfree(vcpu_e500->gtlb_arch[1]); |
1067 | return -1; | 1181 | return -1; |
1068 | } | 1182 | } |
1069 | 1183 | ||
1070 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | 1184 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) |
1071 | { | 1185 | { |
1072 | int stlbsel, i; | 1186 | clear_tlb_refs(vcpu_e500); |
1073 | |||
1074 | /* release all privs */ | ||
1075 | for (stlbsel = 0; stlbsel < 2; stlbsel++) | ||
1076 | for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) { | ||
1077 | struct tlbe_priv *priv = | ||
1078 | &vcpu_e500->gtlb_priv[stlbsel][i]; | ||
1079 | kvmppc_e500_priv_release(priv); | ||
1080 | } | ||
1081 | 1187 | ||
1082 | kvmppc_e500_id_table_free(vcpu_e500); | 1188 | kvmppc_e500_id_table_free(vcpu_e500); |
1189 | |||
1190 | kfree(vcpu_e500->tlb_refs[0]); | ||
1191 | kfree(vcpu_e500->tlb_refs[1]); | ||
1192 | kfree(vcpu_e500->gtlb_priv[0]); | ||
1193 | kfree(vcpu_e500->gtlb_priv[1]); | ||
1083 | kfree(vcpu_e500->gtlb_arch[1]); | 1194 | kfree(vcpu_e500->gtlb_arch[1]); |
1084 | kfree(vcpu_e500->gtlb_arch[0]); | 1195 | kfree(vcpu_e500->gtlb_arch[0]); |
1085 | } | 1196 | } |
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h index 59b88e99a235..b587f691459a 100644 --- a/arch/powerpc/kvm/e500_tlb.h +++ b/arch/powerpc/kvm/e500_tlb.h | |||
@@ -155,23 +155,6 @@ static inline unsigned int get_tlb_esel_bit( | |||
155 | return (vcpu_e500->mas0 >> 16) & 0xfff; | 155 | return (vcpu_e500->mas0 >> 16) & 0xfff; |
156 | } | 156 | } |
157 | 157 | ||
158 | static inline unsigned int get_tlb_esel( | ||
159 | const struct kvmppc_vcpu_e500 *vcpu_e500, | ||
160 | int tlbsel) | ||
161 | { | ||
162 | unsigned int esel = get_tlb_esel_bit(vcpu_e500); | ||
163 | |||
164 | if (tlbsel == 0) { | ||
165 | esel &= KVM_E500_TLB0_WAY_NUM_MASK; | ||
166 | esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK) | ||
167 | << KVM_E500_TLB0_WAY_NUM_BIT; | ||
168 | } else { | ||
169 | esel &= KVM_E500_TLB1_SIZE - 1; | ||
170 | } | ||
171 | |||
172 | return esel; | ||
173 | } | ||
174 | |||
175 | static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, | 158 | static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu, |
176 | const struct tlbe *tlbe) | 159 | const struct tlbe *tlbe) |
177 | { | 160 | { |