* [PATCH]Add TR insert/purge interface for add-on component
@ 2008-01-21 3:18 Xu, Anthony
[not found] ` <51CFAB8CB6883745AE7B93B3E084EBE201670418-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
0 siblings, 1 reply; 8+ messages in thread
From: Xu, Anthony @ 2008-01-21 3:18 UTC (permalink / raw)
To: Avi Kivity, Luck, Tony; +Cc: linux-ia64, kvm-devel
Hi Avi/Tony,
This patch adds the TR insert/purge interface for add-on
components.
TR insert/purge can only been executed by TR mapped code, while module
code is mapped by TC,
So module can not execute TR insert/purge.
This patch let modules execute TR insert/purge.
In the meantime, this patch is reponsible of checking sanity of TR
insert/purge.
If TR inserted is overlapped with existing TRs, the operation will fail.
MCA TR recovery is also considered in this patch, MCA TR will reinsert
all TRs which are used before MCA.
This patch is a must to KVM/IA64.
I appreciate your comments! :-)
Thanks,
Anthony
Signed-off-by: Xiantao Zhang < xiantao.zhang@intel.com >
Signed-off-by: Anthony Xu < anthony.xu@intel.com >
---
arch/ia64/kernel/mca.c | 50 ++++++++++++++
arch/ia64/kernel/mca_asm.S | 5 ++
arch/ia64/mm/tlb.c | 159
++++++++++++++++++++++++++++++++++++++++++++
include/asm-ia64/kregs.h | 3 +
include/asm-ia64/tlb.h | 12 +++
5 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 6dbf591..f83bcaf 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -89,6 +89,7 @@
#include <asm/irq.h>
#include <asm/hw_irq.h>
+#include <asm/tlb.h>
#include "mca_drv.h"
#include "entry.h"
@@ -104,8 +105,10 @@ DEFINE_PER_CPU(u64, ia64_mca_data); /* ==
__per_cpu_mca[smp_processor_id()] */
DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area
*/
DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */
DEFINE_PER_CPU(u64, ia64_mca_pal_base); /* vaddr PAL code granule */
+DEFINE_PER_CPU(u64, ia64_mca_tr_reload); /* Flag for TR reload */
unsigned long __per_cpu_mca[NR_CPUS];
+extern struct ia64_tr_entry
__per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX];
/* In mca_asm.S */
extern void ia64_os_init_dispatch_monarch (void);
@@ -1177,6 +1180,49 @@ all_in:
return;
}
+/* mca_insert_tr
+ *
+ * Switch rid when TR reload and needed!
+ * iord: 1: itr, 2: itr;
+ *
+*/
+static void mca_insert_tr(u64 iord)
+{
+
+ int i;
+ u64 old_rr;
+ struct ia64_tr_entry *p;
+ unsigned long psr;
+ int cpu = smp_processor_id();
+
+ psr = ia64_clear_ic();
+ for (i = IA64_TR_ALLOC_BASE; i < IA64_TR_ALLOC_MAX; i++) {
+ p = &__per_cpu_idtrs[cpu][iord-1][i];
+ if (p->pte) {
+ old_rr = ia64_get_rr(p->ifa);
+ if (old_rr != p->rr) {
+ ia64_set_rr(p->ifa, p->rr);
+ ia64_srlz_d();
+ }
+ ia64_ptr(iord, p->ifa, p->itir >> 2);
+ ia64_srlz_i();
+ if (iord & 0x1) {
+ ia64_itr(0x1, i, p->ifa, p->pte, p->itir
>> 2);
+ ia64_srlz_i();
+ }
+ if (iord & 0x2) {
+ ia64_itr(0x2, i, p->ifa, p->pte, p->itir
>> 2);
+ ia64_srlz_d();
+ }
+ if (old_rr != p->rr) {
+ ia64_set_rr(p->ifa, old_rr);
+ ia64_srlz_d();
+ }
+ }
+ }
+ ia64_set_psr(psr);
+}
+
/*
* ia64_mca_handler
*
@@ -1266,6 +1312,10 @@ ia64_mca_handler(struct pt_regs *regs, struct
switch_stack *sw,
monarch_cpu = -1;
#endif
}
+ if (__get_cpu_var(ia64_mca_tr_reload)) {
+ mca_insert_tr(0x1); /*Reload dynamic itrs*/
+ mca_insert_tr(0x2); /*Reload dynamic itrs*/
+ }
if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0,
recover)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 0f5965f..dd37dd0 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -215,8 +215,13 @@ ia64_reload_tr:
mov r20=IA64_TR_CURRENT_STACK
;;
itr.d dtr[r20]=r16
+ GET_THIS_PADDR(r2, ia64_mca_tr_reload)
+ mov r18 = 1
;;
srlz.d
+ ;;
+ st8 [r2] =r18
+ ;;
done_tlb_purge_and_reload:
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index 655da24..0492d1a 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -26,6 +26,8 @@
#include <asm/pal.h>
#include <asm/tlbflush.h>
#include <asm/dma.h>
+#include <asm/processor.h>
+#include <asm/tlb.h>
static struct {
unsigned long mask; /* mask of supported purge page-sizes */
@@ -40,6 +42,9 @@ struct ia64_ctx ia64_ctx = {
DEFINE_PER_CPU(u8, ia64_need_tlb_flush);
+struct ia64_tr_entry __per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX];
+static u64 ia64_max_tr_num = IA64_TR_ALLOC_MAX;
+
/*
* Initializes the ia64_ctx.bitmap array based on max_ctx+1.
* Called after cpu_init() has setup ia64_ctx.max_ctx based on
@@ -190,6 +195,8 @@ ia64_tlb_init (void)
ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet
*/
unsigned long tr_pgbits;
long status;
+ pal_vm_info_1_u_t vm_info_1;
+ pal_vm_info_2_u_t vm_info_2;
if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) !=
0) {
printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with
status=%ld; "
@@ -206,4 +213,156 @@ ia64_tlb_init (void)
local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
local_flush_tlb_all(); /* nuke left overs from bootstrapping...
*/
+
+ if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) != 0)
{
+ printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
+ ia64_max_tr_num = 8;
+ return;
+ }
+ ia64_max_tr_num = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
+ if (ia64_max_tr_num >
(vm_info_1.pal_vm_info_1_s.max_dtr_entry+1))
+ ia64_max_tr_num =
vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
+}
+
+/*
+ * is_tr_overlap
+ *
+ * Check overlap with inserted TRs.
+ */
+static int is_tr_overlap(struct ia64_tr_entry *p, u64 va, u64 log_size)
+{
+ u64 tr_log_size;
+ u64 tr_end;
+ u64 va_rr = ia64_get_rr(va);
+ u64 va_rid = RR_TO_RID(va_rr);
+ u64 va_end = va + (1<<log_size) - 1;
+
+ if (va_rid != RR_TO_RID(p->rr))
+ return 0;
+ tr_log_size = (p->itir & 0xff) >> 2;
+ tr_end = p->ifa + (1<<tr_log_size) - 1;
+
+ if (va > tr_end || p->ifa > va_end)
+ return 0;
+ return 1;
+
+}
+
+/*
+ * ia64_insert_tr in virtual mode. Allocate a TR slot
+ *
+ * target_mask : 0x1 : itr, 0x2 : dtr, 0x3 : idtr
+ *
+ * va : virtual address.
+ * pte : pte entries inserted.
+ * log_size: range to be covered.
+ *
+ * Return value: <0 : error No.
+ *
+ * >=0 : slot number allocated for TR.
+ */
+int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size)
+{
+ int i, r;
+ unsigned long psr;
+ struct ia64_tr_entry *p;
+ int cpu = smp_processor_id();
+
+ r = -EINVAL;
+ /*Check overlap with existing TR entries*/
+ if (target_mask&0x1) {
+ p = &__per_cpu_idtrs[cpu][0][0];
+ for (i = IA64_TR_ALLOC_BASE; i < ia64_max_tr_num; i++,
p++) {
+ if (p->pte&0x1)
+ if (is_tr_overlap(p, va, log_size))
+ goto out;
+ }
+ }
+ if (target_mask&0x2) {
+ p = &__per_cpu_idtrs[cpu][1][0];
+ for (i = IA64_TR_ALLOC_BASE; i < ia64_max_tr_num; i++,
p++) {
+ if (p->pte&0x1)
+ if (is_tr_overlap(p, va, log_size))
+ goto out;
+ }
+ }
+
+ for (i = IA64_TR_ALLOC_BASE; i < ia64_max_tr_num; i++) {
+ switch (target_mask & 0x3) {
+ case 1:
+ if
(!(__per_cpu_idtrs[cpu][0][i].pte&0x1))
+ goto found;
+ continue;
+ case 2:
+ if
(!(__per_cpu_idtrs[cpu][1][i].pte&0x1))
+ goto found;
+ continue;
+ case 3:
+ if
(!(__per_cpu_idtrs[cpu][0][i].pte&0x1) &&
+
!(__per_cpu_idtrs[cpu][1][i].pte&0x1))
+ goto found;
+ continue;
+ default:
+ r = -EINVAL;
+ goto out;
+ }
+ }
+found:
+ /*Record tr info for mca hander use!*/
+ psr = ia64_clear_ic();
+ if (target_mask & 0x1) {
+ ia64_itr(0x1, i, va, pte, log_size);
+ ia64_srlz_i();
+ p = &__per_cpu_idtrs[cpu][0][i];
+ p->ifa = va;
+ p->pte = pte;
+ p->itir = log_size << 2;
+ p->rr = ia64_get_rr(va);
+ }
+ if (target_mask & 0x2) {
+ ia64_itr(0x2, i, va, pte, log_size);
+ ia64_srlz_i();
+ p = &__per_cpu_idtrs[cpu][1][i];
+ p->ifa = va;
+ p->pte = pte;
+ p->itir = log_size << 2;
+ p->rr = ia64_get_rr(va);
+ }
+ ia64_set_psr(psr);
+ r = i;
+out:
+ return r;
+}
+EXPORT_SYMBOL_GPL(ia64_itr_entry);
+
+/*
+ * ia64_purge_tr
+ *
+ * target_mask: 0x1: purge itr, 0x2 : purge dtr, 0x3 purge idtr.
+ * va: begin address to be purged
+ * log_size: size to purege.
+ *
+ */
+void ia64_ptr_entry(u64 target_mask, u64 va, u64 log_size)
+{
+ int i;
+ int cpu = smp_processor_id();
+ struct ia64_tr_entry *p;
+
+ ia64_ptr(target_mask, va, log_size);
+ ia64_srlz_i();
+
+ for (i = IA64_TR_ALLOC_BASE; i < ia64_max_tr_num; i++) {
+ if (target_mask&0x1) {
+ p = &__per_cpu_idtrs[cpu][0][i];
+ if ((p->pte&0x1) && is_tr_overlap(p, va,
log_size))
+ p->pte = 0;
+ }
+ if (target_mask&0x2) {
+ p = &__per_cpu_idtrs[cpu][1][i];
+ if ((p->pte&0x1) && is_tr_overlap(p, va,
log_size))
+ p->pte = 0;
+ }
+ }
}
+EXPORT_SYMBOL_GPL(ia64_ptr_entry);
diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
index 7e55a58..aefcdfe 100644
--- a/include/asm-ia64/kregs.h
+++ b/include/asm-ia64/kregs.h
@@ -31,6 +31,9 @@
#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as
required by EFI */
#define IA64_TR_CURRENT_STACK 1 /* dtr1: maps kernel's memory- &
register-stacks */
+#define IA64_TR_ALLOC_BASE 2 /* itr&dtr: Base of dynamic TR
resource*/
+#define IA64_TR_ALLOC_MAX 32 /* Max number for dynamic use*/
+
/* Processor status register bits: */
#define IA64_PSR_BE_BIT 1
#define IA64_PSR_UP_BIT 2
diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h
index 26edcb7..f57a8c1 100644
--- a/include/asm-ia64/tlb.h
+++ b/include/asm-ia64/tlb.h
@@ -64,6 +64,18 @@ struct mmu_gather {
struct page *pages[FREE_PTE_NR];
};
+struct ia64_tr_entry {
+ u64 ifa;
+ u64 itir;
+ u64 pte;
+ u64 rr;
+}; /*Record for tr entry!*/
+
+extern int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64
log_size);
+extern void ia64_ptr_entry(u64 target_mask, u64 va, u64 log_size);
+
+#define RR_TO_RID(rr) ((rr)<<32>>40)
+
/* Users of the generic TLB shootdown code must declare this storage
space. */
DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
--
^ permalink raw reply related [flat|nested] 8+ messages in thread[parent not found: <51CFAB8CB6883745AE7B93B3E084EBE201670418-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>]
* Re: [PATCH]Add TR insert/purge interface for add-on component [not found] ` <51CFAB8CB6883745AE7B93B3E084EBE201670418-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org> @ 2008-01-21 3:25 ` Matthew Wilcox [not found] ` <20080121032535.GE27250-6jwH94ZQLHl74goWV3ctuw@public.gmane.org> 2008-01-21 3:31 ` Xu, Anthony 2008-01-21 17:49 ` Luck, Tony 1 sibling, 2 replies; 8+ messages in thread From: Matthew Wilcox @ 2008-01-21 3:25 UTC (permalink / raw) To: Xu, Anthony Cc: kvm-devel, Luck, Tony, linux-ia64-u79uwXL29TY76Z2rM5mHXA, Avi Kivity On Mon, Jan 21, 2008 at 11:18:03AM +0800, Xu, Anthony wrote: > Hi Avi/Tony, > This patch adds the TR insert/purge interface for add-on > components. In my world, TR stands for Token Ring. Nowhere in this patch do you explain what TR means to you! -- Intel are signing my paycheques ... these opinions are still mine "Bill, look, we understand that you're interested in selling us this operating system, but compare it to ours. We can't possibly take such a retrograde step." ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <20080121032535.GE27250-6jwH94ZQLHl74goWV3ctuw@public.gmane.org>]
* Re: [PATCH]Add TR insert/purge interface for add-on component [not found] ` <20080121032535.GE27250-6jwH94ZQLHl74goWV3ctuw@public.gmane.org> @ 2008-01-21 3:29 ` KOSAKI Motohiro 0 siblings, 0 replies; 8+ messages in thread From: KOSAKI Motohiro @ 2008-01-21 3:29 UTC (permalink / raw) To: Matthew Wilcox Cc: Luck, Tony, linux-ia64-u79uwXL29TY76Z2rM5mHXA, kvm-devel, Avi Kivity, kosaki.motohiro-+CUm20s59erQFUHtdCDX3A > On Mon, Jan 21, 2008 at 11:18:03AM +0800, Xu, Anthony wrote: > > Hi Avi/Tony, > > This patch adds the TR insert/purge interface for add-on > > components. > > In my world, TR stands for Token Ring. Nowhere in this patch do you > explain what TR means to you! may be, TR is Tlb Register. see IA64 itr instruction :) ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH]Add TR insert/purge interface for add-on component 2008-01-21 3:25 ` Matthew Wilcox [not found] ` <20080121032535.GE27250-6jwH94ZQLHl74goWV3ctuw@public.gmane.org> @ 2008-01-21 3:31 ` Xu, Anthony 1 sibling, 0 replies; 8+ messages in thread From: Xu, Anthony @ 2008-01-21 3:31 UTC (permalink / raw) To: Matthew Wilcox; +Cc: Avi Kivity, Luck, Tony, linux-ia64, kvm-devel Matthew Wilcox wrote: > On Mon, Jan 21, 2008 at 11:18:03AM +0800, Xu, Anthony wrote: >> Hi Avi/Tony, >> This patch adds the TR insert/purge interface for add-on >> components. > > In my world, TR stands for Token Ring. Nowhere in this patch do you > explain what TR means to you! Sorry for confusing word. TR stands for TLB register. In Ia64 platform there are two kinds of TLBs, One is TLB caches, briefly TC, which can be gone at anytime. The other is TLB registers, briefly TR, which will not be gone until software purges it explicitly. - Anthony ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH]Add TR insert/purge interface for add-on component [not found] ` <51CFAB8CB6883745AE7B93B3E084EBE201670418-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org> 2008-01-21 3:25 ` Matthew Wilcox @ 2008-01-21 17:49 ` Luck, Tony 2008-01-22 6:35 ` Xu, Anthony 1 sibling, 1 reply; 8+ messages in thread From: Luck, Tony @ 2008-01-21 17:49 UTC (permalink / raw) To: Xu, Anthony, Avi Kivity; +Cc: kvm-devel, linux-ia64-u79uwXL29TY76Z2rM5mHXA Looks pretty good. Stylistically it would be nicer to initialize ia64_max_tr_num to 8 (with a comment that this is the least smallest allowed value allowed by the architecture - SDM p.2:44 section 4.1.1.1) and increase this if PAL_VM_SUMMARY indicates that the current processor model supports a larger value. That way you are sure that it never has a larger value that it should. N.B. SGI ship systems with mixed processor models, so to be completely correct here you either need ia64_max_tr_num to be a per-cpu value, or to make sure you only set it to the smallest value supported by any cpu on the system. Your overlap checking code only looks like it checks for overlaps among the new entries being inserted via this interface. Is there some other non-obvious way that these are prevented from overlapping with the TR entries in use by the base kernel (ITR[0]+DTR[0] mapping the kernel in region 5, ITR[1] for the PAL code and DTR[1] for the current kernel stack granule? I don't know how kvm will use this interface, perhaps the virtual address range is limited to areas that can't overlap? If so, perhaps the ia64_itr_enty() routine should check that the va,size arguments are in the virtual address range that KVM will use? ia64_itr_entry() should check that 'log_size' is a supported page size for this processor, and that 'va' is suitably aligned for that size. ia64_ptr_entry() perhaps this should just take a 'target_mask' and 'reg' argument. Then it could skip all the overlap checks and just lookup the address+size in the __per_cpu_idtrs[][][] array return an error if you try to purge something that you didn't set up (->pte == 0). Calling this routine 'ia64_purge_tr' (which is the name in the header comment :-) would help note the non-symmetric calling arguments between insert and purge. What is the expected usage pattern for itr, dtr, itr+dtr mappings by KVM? If you are going to allocate enough that there might be contention, it could be better to start the allocation search for i+d entries at the top and work downwards, while allocating just-i and just-d entries from low numbers working up. That might avoid issues with not having an i+d pair available becaue all the odd entries were allocated for 'i' and all the even ones allocated for 'd' ... so even though there are plenty of free TR registers, none of the free ones are in pairs. Maybe we should put a 'kvm_' into the names of the exported interfaces? Sadly there isn't a way to just make these visible to KVM ... but I'd like to make it crystal clear that other drivers should not use these. -Tony ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH]Add TR insert/purge interface for add-on component 2008-01-21 17:49 ` Luck, Tony @ 2008-01-22 6:35 ` Xu, Anthony [not found] ` <51CFAB8CB6883745AE7B93B3E084EBE2016708BB-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Xu, Anthony @ 2008-01-22 6:35 UTC (permalink / raw) To: Luck, Tony, Avi Kivity; +Cc: linux-ia64, kvm-devel Thanks for your comments Luck, Tony wrote: > Looks pretty good. > > Stylistically it would be nicer to initialize ia64_max_tr_num to 8 > (with > a comment that this is the least smallest allowed value allowed by the > architecture - SDM p.2:44 section 4.1.1.1) and increase this if > PAL_VM_SUMMARY indicates that the current processor model supports a > larger value. That > way you are sure that it never has a larger value that it should. N.B. > SGI ship systems with mixed processor models, so to be completely > correct > here you either need ia64_max_tr_num to be a per-cpu value, or to > make sure > you only set it to the smallest value supported by any cpu on the > system. > Agree, we can initialize ia64_max_tr_num to 8. > Your overlap checking code only looks like it checks for overlaps > among > the new entries being inserted via this interface. Is there some > other non-obvious way that these are prevented from overlapping with > the TR entries > in use by the base kernel (ITR[0]+DTR[0] mapping the kernel in region > 5, > ITR[1] for the PAL code and DTR[1] for the current kernel stack > granule? > I don't know how kvm will use this interface, perhaps the virtual > address > range is limited to areas that can't overlap? If so, perhaps the > ia64_itr_enty() routine should check that the va,size arguments are > in the virtual address > range that KVM will use? Kvm only use TRs whose virtual address starts with 0xD000.. I will add virtual address check for va at function ia64_itr_entry and ia64_ptr_entry. > > ia64_itr_entry() should check that 'log_size' is a supported page > size for this processor, and that 'va' is suitably aligned for that > size. > Agree, we need check log_size in ia64_itr_entry and ia64_ptr_entry. Va doesn't need to be aligned for that size, if you look at itr spec. We can make it aligned for that size. > ia64_ptr_entry() perhaps this should just take a 'target_mask' and > 'reg' argument. Then it could skip all the overlap checks and just > lookup > the address+size in the __per_cpu_idtrs[][][] array return an error if > you try to purge something that you didn't set up (->pte == 0). > Calling > this routine 'ia64_purge_tr' (which is the name in the header comment > :-) > would help note the non-symmetric calling arguments between insert > and purge. Ok, we will do it. > > What is the expected usage pattern for itr, dtr, itr+dtr mappings by > KVM? KVM/IA64 use two itrs and two dtrs. > If you are going to allocate enough that there might be contention, it > could be better to start the allocation search for i+d entries at the > top > and work downwards, while allocating just-i and just-d entries from > low > numbers working up. That might avoid issues with not having an i+d > pair available becaue all the odd entries were allocated for 'i' and > all the > even ones allocated for 'd' ... so even though there are plenty of > free > TR registers, none of the free ones are in pairs. The __per_cpu_idtrs is to reflect the machine ITRs and DTRS. And ITR and DTR are separate. It is impossible that odd entries are for 'I' and even ones for 'd'. In theory, i+d pair can not be available even if there are plenty of free. While KVM/IA64 only uses two pair, that will not happen. If we want to provide a general TR insert/purge interfaces, we need to handle this issue. One possible solution is we don't support i+d pair allocation > > Maybe we should put a 'kvm_' into the names of the exported > interfaces? > Sadly there isn't a way to just make these visible to KVM ... but I'd > like > to make it crystal clear that other drivers should not use these. Agree. Will send out patch soon per your comments. Thanks - Anthony ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <51CFAB8CB6883745AE7B93B3E084EBE2016708BB-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>]
* Re: [PATCH]Add TR insert/purge interface for add-on component [not found] ` <51CFAB8CB6883745AE7B93B3E084EBE2016708BB-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org> @ 2008-01-22 6:56 ` Xu, Anthony 2008-01-31 9:37 ` Xu, Anthony 0 siblings, 1 reply; 8+ messages in thread From: Xu, Anthony @ 2008-01-22 6:56 UTC (permalink / raw) To: Xu, Anthony, Luck, Tony, Avi Kivity Cc: kvm-devel, linux-ia64-u79uwXL29TY76Z2rM5mHXA Xu, Anthony wrote: > Thanks for your comments > > > Luck, Tony wrote: >> Looks pretty good. >> >> Stylistically it would be nicer to initialize ia64_max_tr_num to 8 >> (with a comment that this is the least smallest allowed value >> allowed by the architecture - SDM p.2:44 section 4.1.1.1) and >> increase this if PAL_VM_SUMMARY indicates that the current processor >> model supports a larger value. That way you are sure that it never >> has a larger value that it should. N.B. SGI ship systems with mixed >> processor models, so to be completely correct here you either need >> ia64_max_tr_num to be a per-cpu value, or to make sure you only set >> it to the smallest value supported by any cpu on the system. >> > Agree, we can initialize ia64_max_tr_num to 8. We will use per-cpu ia64_max_tr_num. > > > >> Your overlap checking code only looks like it checks for overlaps >> among the new entries being inserted via this interface. Is there >> some other non-obvious way that these are prevented from overlapping >> with the TR entries in use by the base kernel (ITR[0]+DTR[0] mapping >> the kernel in region 5, ITR[1] for the PAL code and DTR[1] for the >> current kernel stack granule? I don't know how kvm will use this >> interface, perhaps the virtual address range is limited to areas >> that can't overlap? If so, perhaps the ia64_itr_enty() routine >> should check that the va,size arguments are in the virtual address >> range that KVM will use? > Kvm only use TRs whose virtual address starts with 0xD000.. > I will add virtual address check for va at function ia64_itr_entry and > ia64_ptr_entry. One concern about this Where can we put Macro #define KVM_ADDRESS 0xD000..? It's not suitable to put it in file tlb.c. > >> >> ia64_itr_entry() should check that 'log_size' is a supported page >> size for this processor, and that 'va' is suitably aligned for that >> size. >> > Agree, we need check log_size in ia64_itr_entry and ia64_ptr_entry. > Va doesn't need to be aligned for that size, if you look at itr spec. > We can make it aligned for that size. > > >> ia64_ptr_entry() perhaps this should just take a 'target_mask' and >> 'reg' argument. Then it could skip all the overlap checks and just >> lookup the address+size in the __per_cpu_idtrs[][][] array return an >> error if you try to purge something that you didn't set up (->pte == >> 0). Calling this routine 'ia64_purge_tr' (which is the name in the >> header comment :-) would help note the non-symmetric calling >> arguments between insert and purge. > Ok, we will do it. > >> >> What is the expected usage pattern for itr, dtr, itr+dtr mappings by >> KVM? > KVM/IA64 use two itrs and two dtrs. > > >> If you are going to allocate enough that there might be contention, >> it could be better to start the allocation search for i+d entries at >> the top and work downwards, while allocating just-i and just-d >> entries from low numbers working up. That might avoid issues with >> not having an i+d pair available becaue all the odd entries were >> allocated for 'i' and all the even ones allocated for 'd' ... so >> even though there are plenty of free TR registers, none of the free >> ones are in pairs. > The __per_cpu_idtrs is to reflect the machine ITRs and DTRS. > And ITR and DTR are separate. > It is impossible that odd entries are for 'I' and even ones for 'd'. > In theory, i+d pair can not be available even if there are plenty of > free. > While KVM/IA64 only uses two pair, that will not happen. > If we want to provide a general TR insert/purge interfaces, we need to > handle this issue. > One possible solution is we don't support i+d pair allocation > > > >> >> Maybe we should put a 'kvm_' into the names of the exported >> interfaces? Sadly there isn't a way to just make these visible to >> KVM ... but I'd like to make it crystal clear that other drivers >> should not use these. Agree. More thinking. If we put kvm_ into the names of the exported interfaces, then it is the kvm specific interfaces, Seems it is not appropriate to put the interfaces in tlb.c. Basically this patch provides common TR insert/purge interface for all modules, not specific to KVM. Currently only KVM/IA64 need these interfaces, maybe later on other modules also need it. What do you think? Thanks, - Anthony > > Will send out patch soon per your comments. > > > Thanks > - Anthony > > > - > To unsubscribe from this list: send the line "unsubscribe linux-ia64" > in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH]Add TR insert/purge interface for add-on component 2008-01-22 6:56 ` Xu, Anthony @ 2008-01-31 9:37 ` Xu, Anthony 0 siblings, 0 replies; 8+ messages in thread From: Xu, Anthony @ 2008-01-31 9:37 UTC (permalink / raw) To: Xu, Anthony, Luck, Tony, Avi Kivity; +Cc: linux-ia64, kvm-devel Hi tony, This is the revised patch per comments. We don't use index as parameter of ia64_ptr_entry, Because it will cause the unconvenientce to user. 1. the user need to remember index. 2. the user may want to use one purge to purge two previous inserts. We add some optimization for ia64_ptr_entry, It only compare dynamical used TRs, As for KVM, it only compares two TRs, So it will not impact formance. Thanks, Anthony >From a10d0415ce8d7836c27da4147d73616bae055dd4 Mon Sep 17 00:00:00 2001 From: Zhang Xiantao <xiantao.zhang@intel.com> Date: Tue, 29 Jan 2008 12:33:48 +0800 Subject: [PATCH] Add API for allocating TR resouce. Dynamic TR resouce should be managed in an uniform way. Signed-off-by: Zhang Xiantao <xiantao.zhang@intel.com> Signed-off-by: Anthony Xu<anthony.xu@intel.com> --- arch/ia64/kernel/mca.c | 50 ++++++++++++++ arch/ia64/kernel/mca_asm.S | 5 ++ arch/ia64/mm/tlb.c | 163 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-ia64/kregs.h | 3 + include/asm-ia64/tlb.h | 12 +++ 5 files changed, 233 insertions(+), 0 deletions(-) diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 6dbf591..4253343 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -89,6 +89,7 @@ #include <asm/irq.h> #include <asm/hw_irq.h> +#include <asm/tlb.h> #include "mca_drv.h" #include "entry.h" @@ -104,8 +105,10 @@ DEFINE_PER_CPU(u64, ia64_mca_data); /* == __per_cpu_mca[smp_processor_id()] */ DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area */ DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */ DEFINE_PER_CPU(u64, ia64_mca_pal_base); /* vaddr PAL code granule */ +DEFINE_PER_CPU(u64, ia64_mca_tr_reload); /* Flag for TR reload */ unsigned long __per_cpu_mca[NR_CPUS]; +extern struct ia64_tr_entry __per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX]; /* In mca_asm.S */ extern void ia64_os_init_dispatch_monarch (void); @@ -1177,6 +1180,49 @@ all_in: return; } +/* mca_insert_tr + * + * Switch rid when TR reload and needed! + * iord: 1: itr, 2: itr; + * +*/ +static void mca_insert_tr(u64 iord) +{ + + int i; + u64 old_rr; + struct ia64_tr_entry *p; + unsigned long psr; + int cpu = smp_processor_id(); + + psr = ia64_clear_ic(); + for (i = IA64_TR_ALLOC_BASE; i < IA64_TR_ALLOC_MAX; i++) { + p = &__per_cpu_idtrs[cpu][iord-1][i]; + if (p->pte&0x1) { + old_rr = ia64_get_rr(p->ifa); + if (old_rr != p->rr) { + ia64_set_rr(p->ifa, p->rr); + ia64_srlz_d(); + } + ia64_ptr(iord, p->ifa, p->itir >> 2); + ia64_srlz_i(); + if (iord & 0x1) { + ia64_itr(0x1, i, p->ifa, p->pte, p->itir >> 2); + ia64_srlz_i(); + } + if (iord & 0x2) { + ia64_itr(0x2, i, p->ifa, p->pte, p->itir >> 2); + ia64_srlz_i(); + } + if (old_rr != p->rr) { + ia64_set_rr(p->ifa, old_rr); + ia64_srlz_d(); + } + } + } + ia64_set_psr(psr); +} + /* * ia64_mca_handler * @@ -1266,6 +1312,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, monarch_cpu = -1; #endif } + if (__get_cpu_var(ia64_mca_tr_reload)) { + mca_insert_tr(0x1); /*Reload dynamic itrs*/ + mca_insert_tr(0x2); /*Reload dynamic itrs*/ + } if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 0f5965f..dd37dd0 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -215,8 +215,13 @@ ia64_reload_tr: mov r20=IA64_TR_CURRENT_STACK ;; itr.d dtr[r20]=r16 + GET_THIS_PADDR(r2, ia64_mca_tr_reload) + mov r18 = 1 ;; srlz.d + ;; + st8 [r2] =r18 + ;; done_tlb_purge_and_reload: diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 655da24..5d7dcdb 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -26,6 +26,8 @@ #include <asm/pal.h> #include <asm/tlbflush.h> #include <asm/dma.h> +#include <asm/processor.h> +#include <asm/tlb.h> static struct { unsigned long mask; /* mask of supported purge page-sizes */ @@ -39,6 +41,9 @@ struct ia64_ctx ia64_ctx = { }; DEFINE_PER_CPU(u8, ia64_need_tlb_flush); +DEFINE_PER_CPU(u8, ia64_tr_num); + +struct ia64_tr_entry __per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX]; /* * Initializes the ia64_ctx.bitmap array based on max_ctx+1. @@ -190,6 +195,9 @@ ia64_tlb_init (void) ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */ unsigned long tr_pgbits; long status; + pal_vm_info_1_u_t vm_info_1; + pal_vm_info_2_u_t vm_info_2; + int cpu = smp_processor_id(); if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld; " @@ -206,4 +214,159 @@ ia64_tlb_init (void) local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; local_flush_tlb_all(); /* nuke left overs from bootstrapping... */ + + if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) != 0) { + printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status); + per_cpu(ia64_tr_num, cpu) = 8; + return; + } + per_cpu(ia64_tr_num, cpu) = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; + if (per_cpu(ia64_tr_num, cpu) > + (vm_info_1.pal_vm_info_1_s.max_dtr_entry+1)) + per_cpu(ia64_tr_num, cpu) = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; +} + +/* + * is_tr_overlap + * + * Check overlap with inserted TRs. + */ +static int is_tr_overlap(struct ia64_tr_entry *p, u64 va, u64 log_size) +{ + u64 tr_log_size; + u64 tr_end; + u64 va_rr = ia64_get_rr(va); + u64 va_rid = RR_TO_RID(va_rr); + u64 va_end = va + (1<<log_size) - 1; + + if (va_rid != RR_TO_RID(p->rr)) + return 0; + tr_log_size = (p->itir & 0xff) >> 2; + tr_end = p->ifa + (1<<tr_log_size) - 1; + + if (va > tr_end || p->ifa > va_end) + return 0; + return 1; + +} + +/* + * ia64_insert_tr in virtual mode. Allocate a TR slot + * + * target_mask : 0x1 : itr, 0x2 : dtr, 0x3 : idtr + * + * va : virtual address. + * pte : pte entries inserted. + * log_size: range to be covered. + * + * Return value: <0 : error No. + * + * >=0 : slot number allocated for TR. + */ +int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size) +{ + int i, r; + unsigned long psr; + struct ia64_tr_entry *p; + int cpu = smp_processor_id(); + + r = -EINVAL; + /*Check overlap with existing TR entries*/ + if (target_mask&0x1) { + p = &__per_cpu_idtrs[cpu][0][0]; + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); + i++, p++) { + if (p->pte&0x1) + if (is_tr_overlap(p, va, log_size)) + goto out; + } + } + if (target_mask&0x2) { + p = &__per_cpu_idtrs[cpu][1][0]; + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); + i++, p++) { + if (p->pte&0x1) + if (is_tr_overlap(p, va, log_size)) + goto out; + } + } + + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); i++) { + switch (target_mask & 0x3) { + case 1: + if (!(__per_cpu_idtrs[cpu][0][i].pte&0x1)) + goto found; + continue; + case 2: + if (!(__per_cpu_idtrs[cpu][1][i].pte&0x1)) + goto found; + continue; + case 3: + if (!(__per_cpu_idtrs[cpu][0][i].pte&0x1) && + !(__per_cpu_idtrs[cpu][1][i].pte&0x1)) + goto found; + continue; + default: + r = -EINVAL; + goto out; + } + } +found: + /*Record tr info for mca hander use!*/ + psr = ia64_clear_ic(); + if (target_mask & 0x1) { + ia64_itr(0x1, i, va, pte, log_size); + ia64_srlz_i(); + p = &__per_cpu_idtrs[cpu][0][i]; + p->ifa = va; + p->pte = pte; + p->itir = log_size << 2; + p->rr = ia64_get_rr(va); + } + if (target_mask & 0x2) { + ia64_itr(0x2, i, va, pte, log_size); + ia64_srlz_i(); + p = &__per_cpu_idtrs[cpu][1][i]; + p->ifa = va; + p->pte = pte; + p->itir = log_size << 2; + p->rr = ia64_get_rr(va); + } + ia64_set_psr(psr); + r = i; +out: + return r; +} +EXPORT_SYMBOL_GPL(ia64_itr_entry); + +/* + * ia64_purge_tr + * + * target_mask: 0x1: purge itr, 0x2 : purge dtr, 0x3 purge idtr. + * va: begin address to be purged + * log_size: size to purege. + * + */ +void ia64_ptr_entry(u64 target_mask, u64 va, u64 log_size) +{ + int i; + int cpu = smp_processor_id(); + struct ia64_tr_entry *p; + + ia64_ptr(target_mask, va, log_size); + ia64_srlz_i(); + + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); i++) { + if (target_mask&0x1) { + p = &__per_cpu_idtrs[cpu][0][i]; + if ((p->pte&0x1) && is_tr_overlap(p, va, log_size)) + p->pte = 0; + } + if (target_mask&0x2) { + p = &__per_cpu_idtrs[cpu][1][i]; + if ((p->pte&0x1) && is_tr_overlap(p, va, log_size)) + p->pte = 0; + } + } } +EXPORT_SYMBOL_GPL(ia64_ptr_entry); diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h index 7e55a58..aefcdfe 100644 --- a/include/asm-ia64/kregs.h +++ b/include/asm-ia64/kregs.h @@ -31,6 +31,9 @@ #define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ #define IA64_TR_CURRENT_STACK 1 /* dtr1: maps kernel's memory- & register-stacks */ +#define IA64_TR_ALLOC_BASE 2 /* itr&dtr: Base of dynamic TR resource*/ +#define IA64_TR_ALLOC_MAX 32 /* Max number for dynamic use*/ + /* Processor status register bits: */ #define IA64_PSR_BE_BIT 1 #define IA64_PSR_UP_BIT 2 diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h index 26edcb7..f57a8c1 100644 --- a/include/asm-ia64/tlb.h +++ b/include/asm-ia64/tlb.h @@ -64,6 +64,18 @@ struct mmu_gather { struct page *pages[FREE_PTE_NR]; }; +struct ia64_tr_entry { + u64 ifa; + u64 itir; + u64 pte; + u64 rr; +}; /*Record for tr entry!*/ + +extern int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size); +extern void ia64_ptr_entry(u64 target_mask, u64 va, u64 log_size); + +#define RR_TO_RID(rr) ((rr)<<32>>40) + /* Users of the generic TLB shootdown code must declare this storage space. */ DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); -- 1.5.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-01-31 9:37 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-21 3:18 [PATCH]Add TR insert/purge interface for add-on component Xu, Anthony
[not found] ` <51CFAB8CB6883745AE7B93B3E084EBE201670418-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2008-01-21 3:25 ` Matthew Wilcox
[not found] ` <20080121032535.GE27250-6jwH94ZQLHl74goWV3ctuw@public.gmane.org>
2008-01-21 3:29 ` KOSAKI Motohiro
2008-01-21 3:31 ` Xu, Anthony
2008-01-21 17:49 ` Luck, Tony
2008-01-22 6:35 ` Xu, Anthony
[not found] ` <51CFAB8CB6883745AE7B93B3E084EBE2016708BB-wq7ZOvIWXbOiAffOGbnezLfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2008-01-22 6:56 ` Xu, Anthony
2008-01-31 9:37 ` Xu, Anthony
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox