GRU - GRU Updates
cover GRU - GRU Updates
This patch set contains a collection of patches to the SGI UV GRU driver. These patches fix various bugs found in the testing of the driver on real hardware.
No changes are made to non-UV files.
PATCH 1/25 GRU - delete obsolete gru instruction opcodes
From: Jack Steiner <[email protected]>
Update the GRU instruction macros to match what is actually implemented in initial silicon.
--- drivers/misc/sgi-gru/gru_instructions.h | 2 -- 1 file changed, 2 deletions(-)
drivers/misc/sgi-gru/gru_instructions.h +0 -2
@@ -217,8 +217,6 @@ struct gru_instruction {#define EOP_ERR_XOR 0x03/* Logical XOR with memory */ #define EOP_ERR_ADD 0x04/* Add value to memory */ #define EOP_ERR_CSWAP 0x08/* Compare with operand2, write operand1 if match*/ -#define EOP_ERR_EPOLL 0x09/* Poll for equality */ -#define EOP_ERR_NPOLL 0x0a/* Poll for inequality */ /* GAMXR - SGI Arithmetic unit */ #define EOP_XR_CSWAP 0x0b/* Masked compare exchange */
PATCH 2/25 GRU - skip gru tlb purging of gru contexts:w
In reply to [email protected]From: Jack Steiner <[email protected]>
Skip purging the GRU TLB if the purge request is for the GRU itself. The driver will not create TLB mappings for vmas that map the GRU address space. Purging them is unnecessary.
This is only an optimization and is not functionally required. However, if GRU resources are oversubscribed (unusual except for stress tests), purging can be frequent.
--- drivers/misc/sgi-gru/grufault.c | 8 ++++---- drivers/misc/sgi-gru/grufile.c | 2 +- drivers/misc/sgi-gru/gruprocfs.c | 1 + drivers/misc/sgi-gru/grutables.h | 3 ++- drivers/misc/sgi-gru/grutlbpurge.c | 11 +++++++++-- 5 files changed, 17 insertions(+), 8 deletions(-)
drivers/misc/sgi-gru/grufault.c +4 -4
@@ -57,11 +57,11 @@ static inline int is_gru_paddr(unsigned/* * Find the vma of a GRU segment. Caller must hold mmap_sem. */ -struct vm_area_struct *gru_find_vma (unsigned long vaddr) +struct vm_area_struct *gru_find_vma (struct mm_struct *mm,unsigned long vaddr) {struct vm_area_struct *vma; - vma =find_vma (current->mm, vaddr); + vma =find_vma (mm, vaddr);if (vma && vma->vm_start <= vaddr && vma->vm_ops == &gru_vm_ops)return vma;return NULL ;
@@ -82,7 +82,7 @@ static struct gru_thread_state *gru_findstruct gru_thread_state *gts =NULL ;down_read (&mm->mmap_sem); - vma =gru_find_vma (vaddr); + vma =gru_find_vma (current->mm, vaddr);if (vma) gts =gru_find_thread_state (vma,TSID (vaddr, vma));if (gts)
@@ -99,7 +99,7 @@ static struct gru_thread_state *gru_allostruct gru_thread_state *gts =ERR_PTR (-EINVAL );down_write (&mm->mmap_sem); - vma =gru_find_vma (vaddr); + vma =gru_find_vma (current->mm, vaddr);if (!vma) goto err;
drivers/misc/sgi-gru/grufile.c +1 -1
@@ -145,7 +145,7 @@ static int gru_create_new_context(unsign req.options |=GRU_OPT_MISS_FMM_INTR ;down_write (¤t->mm->mmap_sem); - vma =gru_find_vma (req.gseg); + vma =gru_find_vma (current->mm, req.gseg);if (vma) { vdata = vma->vm_private_data; vdata->vd_user_options = req.options;
drivers/misc/sgi-gru/gruprocfs.c +1 -0
@@ -87,6 +87,7 @@ static int statistics_show(struct seq_fiprintstat (s, tlb_dropin_fail_no_exception);printstat (s, tfh_stale_on_fault);printstat (s, mmu_invalidate_range); +printstat (s, mmu_invalidate_range_flush);printstat (s, mmu_invalidate_page);printstat (s, flush_tlb);printstat (s, flush_tlb_gru);
drivers/misc/sgi-gru/grutables.h +2 -1
@@ -213,6 +213,7 @@ struct gru_stats_s {atomic_long_t tlb_dropin_fail_no_exception;atomic_long_t tfh_stale_on_fault;atomic_long_t mmu_invalidate_range; +atomic_long_t mmu_invalidate_range_flush;atomic_long_t mmu_invalidate_page;atomic_long_t flush_tlb;atomic_long_t flush_tlb_gru;
@@ -653,7 +654,7 @@ extern int gru_get_exception_detail(unsiextern int gru_set_context_option (unsigned long address);extern void gru_check_context_placement (struct gru_thread_state *gts);extern int gru_cpu_fault_map_id (void ); -extern struct vm_area_struct *gru_find_vma (unsigned long vaddr); +extern struct vm_area_struct *gru_find_vma (struct mm_struct *mm,unsigned long vaddr);extern void gru_flush_all_tlb (struct gru_state *gru);extern int gru_proc_init (void );extern void gru_proc_exit (void );
drivers/misc/sgi-gru/grutlbpurge.c +9 -2
@@ -226,11 +226,19 @@ static void gru_invalidate_range_start(s struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, ms_notifier); +if (mm &&atomic_read (&mm->mm_users) &&unlikely (down_write_trylock (&mm->mmap_sem))) { +up_write (&mm->mmap_sem); + }STAT (mmu_invalidate_range);atomic_inc (&gms->ms_range_active);gru_dbg (grudev,"gms %p, start 0x%lx, end 0x%lx, act %d\n" , gms, start, end,atomic_read (&gms->ms_range_active)); -gru_flush_tlb_range (gms, start, end - start); + +/* No need to flush if unmapping a GRU context */ +if (!gru_find_vma (mm, start)) { +STAT (mmu_invalidate_range_flush); +gru_flush_tlb_range (gms, start, end - start); + } } static void gru_invalidate_range_end(struct mmu_notifier *mn,
@@ -242,7 +250,6 @@ static void gru_invalidate_range_end(str/* ..._and_test() provides needed barrier */ (void )atomic_dec_and_test (&gms->ms_range_active); -wake_up_all (&gms->ms_wait_queue);gru_dbg (grudev,"gms %p, start 0x%lx, end 0x%lx\n" , gms, start, end); }
PATCH 3/25 GRU - update gru tlb miss statistics
In reply to [email protected]From: Jack Steiner <[email protected]>
Update the GRU TLB dropin statistics. Add counts to indicate number of TLB miss interrupts and a separate count of TLB entries actually written. Also minor code cleanup of the TLB fault path.
--- drivers/misc/sgi-gru/gru.h | 3 ++- drivers/misc/sgi-gru/grufault.c | 33 +++++++++++++++++++++++++-------- drivers/misc/sgi-gru/gruprocfs.c | 1 + drivers/misc/sgi-gru/grutables.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-)
drivers/misc/sgi-gru/gru.h +2 -1
@@ -61,7 +61,8 @@ struct gru_gseg_statistics {unsigned long upm_tlbmiss;unsigned long tlbdropin;unsigned long context_stolen; -unsigned long reserved[10 ]; +unsigned long interrupts; +unsigned long reserved[9 ]; };/* Flags for GRU options on the gru_create_context() call */
drivers/misc/sgi-gru/grufault.c +25 -8
@@ -289,8 +289,10 @@ static int gru_vtop(struct gru_thread_streturn VTOP_SUCCESS ; inval: +STAT (tlb_dropin_fail_invalid);return VTOP_INVALID ; upm: +STAT (tlb_dropin_fail_retry);return VTOP_RETRY ; }
@@ -422,7 +424,7 @@ static int gru_try_dropin(struct gru_staif (ret ==VTOP_INVALID ) goto failinval;if (ret ==VTOP_RETRY ) - goto failupm; + goto failretry;if (!(gts->ts_sizeavail &GRU_SIZEAVAIL (pageshift))) { gts->ts_sizeavail |=GRU_SIZEAVAIL (pageshift);
@@ -438,9 +440,9 @@ static int gru_try_dropin(struct gru_sta }gru_cb_set_istatus_active (cbk); - gts->ustats.tlbdropin++;tfh_write_restart (tfh, gpa,GAA_RAM , vaddr, asid, write,GRU_PAGESIZE (pageshift)); + gts->ustats.tlbdropin++; gru_dbg(grudev, "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x," " rw %d, ps %d, gpa 0x%lx\n",
@@ -453,20 +455,33 @@ failnoasid:/* No asid (delayed unload). */ STAT (tlb_dropin_fail_no_asid);gru_dbg (grudev,"FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n" , tfh, vaddr); -if (!cbk) +if (atomic)tfh_user_polling_mode (tfh);else gru_flush_cache (tfh);gru_flush_cache_cbe (cbe);return -EAGAIN ; +failretry: +/* vtop failed - retry */ +if (atomic) +tfh_user_polling_mode (tfh); +else +gru_flush_cache (tfh); +gru_flush_cache_cbe (cbe); +gru_dbg (grudev,"FAILED retry tfh: 0x%p, vaddr 0x%lx\n" , tfh, vaddr); +return -EAGAIN ; + failupm:/* Atomic failure switch CBR to UPM */ -tfh_user_polling_mode (tfh); +if (atomic) +tfh_user_polling_mode (tfh); +else +gru_flush_cache (tfh);gru_flush_cache_cbe (cbe);STAT (tlb_dropin_fail_upm);gru_dbg (grudev,"FAILED upm tfh: 0x%p, vaddr 0x%lx\n" , tfh, vaddr); -return 1 ; +return -EAGAIN ; failfmm:/* FMM state on UPM call */
@@ -501,13 +516,12 @@ failinval:/* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ tfh_exception (tfh);gru_flush_cache_cbe (cbe); -STAT (tlb_dropin_fail_invalid);gru_dbg (grudev,"FAILED inval tfh: 0x%p, vaddr 0x%lx\n" , tfh, vaddr);return -EFAULT ; failactive:/* Range invalidate active. Switch to UPM iff atomic */ -if (!cbk) +if (atomic)tfh_user_polling_mode (tfh);else gru_flush_cache (tfh);
@@ -531,7 +545,7 @@ static irqreturn_t gru_intr(int chiplet,struct gru_thread_state *gts;struct gru_tlb_fault_handle *tfh =NULL ;struct completion *cmp; -int cbrnum, ctxnum; +int cbrnum, ctxnum, multi =0 ;STAT (intr);
@@ -581,7 +595,10 @@ static irqreturn_t gru_intr(int chiplet,* This is running in interrupt context. Trylock the mmap_sem. * If it fails, retry the fault in user context. */ +if (!multi) + gts->ustats.interrupts++; gts->ustats.fmm_tlbmiss++; + multi =1 ;if (!gts->ts_force_cch_reload &&down_read_trylock (>s->ts_mm->mmap_sem)) {gru_try_dropin (gru, gts, tfh,NULL );
drivers/misc/sgi-gru/gruprocfs.c +1 -0
@@ -79,6 +79,7 @@ static int statistics_show(struct seq_fiprintstat (s, tlb_dropin);printstat (s, tlb_preload_page);printstat (s, tlb_dropin_fail_no_asid); +printstat (s, tlb_dropin_fail_retry);printstat (s, tlb_dropin_fail_upm);printstat (s, tlb_dropin_fail_invalid);printstat (s, tlb_dropin_fail_range_active);
drivers/misc/sgi-gru/grutables.h +1 -0
@@ -205,6 +205,7 @@ struct gru_stats_s {atomic_long_t tlb_dropin;atomic_long_t tlb_preload_page;atomic_long_t tlb_dropin_fail_no_asid; +atomic_long_t tlb_dropin_fail_retry;atomic_long_t tlb_dropin_fail_upm;atomic_long_t tlb_dropin_fail_invalid;atomic_long_t tlb_dropin_fail_range_active;
PATCH 4/25 GRU - mmap gru contexts using nonlinear
In reply to [email protected]From: Jack Steiner <[email protected]>
Add VM_NONLINEAR to the vm_flags used to map the GRU.
--- drivers/misc/sgi-gru/grufile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/sgi-gru/grufile.c +1 -1
@@ -110,7 +110,7 @@ static int gru_file_mmap(struct file *fi vma->vm_flags |= (VM_IO |VM_DONTCOPY |VM_LOCKED |VM_DONTEXPAND |VM_PFNMAP | -VM_RESERVED ); +VM_RESERVED |VM_NONLINEAR ); vma->vm_page_prot =PAGE_SHARED ; vma->vm_ops = &gru_vm_ops;
PATCH 5/25 GRU - cbe cache flush
In reply to [email protected]From: Jack Steiner <[email protected]>
In some cases, for performance reasons flushing the SGI GRU cbe needs to dirty the cacheline before doing the cacheline flush. This ensures that the dirty cacheline actually goes back to the caching home agent. Update a reserved field in the CBE instead of a field that might be used. This _should_ not be required (dirtying any field should be ok) but early silicon has an issue here.
Note that flushing the CL is not a requirement - only a performance enhancement.
--- drivers/misc/sgi-gru/grufault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/sgi-gru/grufault.c +1 -1
@@ -306,7 +306,7 @@ upm:static void gru_flush_cache_cbe (struct gru_control_block_extended *cbe) {if (unlikely (cbe)) { - cbe->cbrexecstatus =0 ;/* make CL dirty */ + cbe->reserved6 =0 ;/* make CL dirty */ gru_flush_cache (cbe); } }
PATCH 6/25 GRU - change context stealing
In reply to [email protected]From: Jack Steiner <[email protected]>
This patch substantially reworks the way the GRU driver steals contexts from users in order to use the GRU resources for kernel use.
The new version fixes some ugly locking bugs and is overall more efficient.
--- drivers/misc/sgi-gru/grufault.c | 2 drivers/misc/sgi-gru/grukservices.c | 271 +++++++++++++++++------------------- drivers/misc/sgi-gru/gruprocfs.c | 12 + drivers/misc/sgi-gru/grutables.h | 37 +++- drivers/misc/sgi-gru/grutlbpurge.c | 2 5 files changed, 167 insertions(+), 157 deletions(-)
drivers/misc/sgi-gru/grufault.c +1 -1
@@ -564,7 +564,7 @@ static irqreturn_t gru_intr(int chiplet,for_each_cbr_in_tfm (cbrnum, dmap.fault_bits) {STAT (intr_cbr); - cmp = gru->gs_blade->bs_async_wq; + cmp = gru->gs_async_wq[cbrnum];if (cmp)complete (cmp); gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n",
drivers/misc/sgi-gru/grukservices.c +130 -141
524 lines not on this page · raw message
drivers/misc/sgi-gru/gruprocfs.c +9 -3
@@ -52,9 +52,15 @@ static int statistics_show(struct seq_fiprintstat (s, assign_context_failed);printstat (s, free_context);printstat (s, load_user_context); -printstat (s, load_kernel_context); -printstat (s, lock_kernel_context); -printstat (s, unlock_kernel_context); +printstat (s, load_kcontext); +printstat (s, load_kcontext_assign); +printstat (s, load_kcontext_steal); +printstat (s, lock_kcontext); +printstat (s, unlock_kcontext); +printstat (s, get_kcontext_cbr); +printstat (s, get_kcontext_cbr_busy); +printstat (s, lock_async_resource); +printstat (s, unlock_async_resource);printstat (s, steal_user_context);printstat (s, steal_kernel_context);printstat (s, steal_context_failed);
drivers/misc/sgi-gru/grutables.h +27 -10
@@ -163,6 +163,8 @@ extern unsigned int gru_max_gids;#define GRU_DRIVER_ID_STR "SGI GRU Device Driver"#define GRU_DRIVER_VERSION_STR "0.85" +#define gru_random () get_cycles() +/* * GRU statistics. */
@@ -178,9 +180,15 @@ struct gru_stats_s {atomic_long_t assign_context_failed;atomic_long_t free_context;atomic_long_t load_user_context; -atomic_long_t load_kernel_context; -atomic_long_t lock_kernel_context; -atomic_long_t unlock_kernel_context; +atomic_long_t load_kcontext; +atomic_long_t load_kcontext_assign; +atomic_long_t load_kcontext_steal; +atomic_long_t lock_kcontext; +atomic_long_t unlock_kcontext; +atomic_long_t get_kcontext_cbr; +atomic_long_t get_kcontext_cbr_busy; +atomic_long_t lock_async_resource; +atomic_long_t unlock_async_resource;atomic_long_t steal_user_context;atomic_long_t steal_kernel_context;atomic_long_t steal_context_failed;
@@ -443,14 +451,11 @@ struct gru_state {resources */ unsigned long gs_dsr_map;/* bitmap used to manage DATA resources */ -unsigned int gs_reserved_cbrs;/* Number of kernel- -reserved cbrs */ -unsigned int gs_reserved_dsr_bytes;/* Bytes of kernel- -reserved dsrs */ unsigned short gs_active_contexts;/* number of contexts in use */ struct gru_thread_state *gs_gts[GRU_NUM_CCH ];/* GTS currently using the context */ +struct completion *gs_async_wq[GRU_NUM_CB ];int gs_irq[GRU_NUM_TFM ];/* Interrupt irqs */ };
@@ -466,8 +471,7 @@ struct gru_blade_state {struct gru_thread_state *bs_kgts;/* GTS for kernel use */ /* ---- the following are used for managing kernel async GRU CBRs --- */ -int bs_async_dsr_bytes;/* DSRs for async */ -int bs_async_cbrs;/* CBRs AU for async */ +void *bs_async_cbr;/* CBR for async */ struct completion *bs_async_wq;/* ---- the following are protected by the bs_lock spinlock ---- */
@@ -558,11 +562,24 @@ struct gru_blade_state {/*----------------------------------------------------------------------------- * Lock / Unlock GRU handles -* Use the "delresp" bit in the handle as a "lock" bit. +* Use the "delresp" bit in MCS handles as a "lock" bit. +* Use the "unmapped" bit in CBRs as a "lock" bit. +* +* Return: 0 = lock failed, 1 = locked */ /* Lock hierarchy checking enabled only in emulator */ +static inline int trylock_cbr_handle (void *h) +{ +return !test_and_set_bit (2 , h); +} + +static inline void unlock_cbr_handle (void *h) +{ +clear_bit (2 , h); +} +/* 0 = lock failed, 1 = locked */ static inline int __trylock_handle (void *h) {
drivers/misc/sgi-gru/grutlbpurge.c +0 -2
@@ -40,8 +40,6 @@#include "grutables.h" #include <asm/uv/uv_hub.h> -#define gru_random () get_cycles() -/* ---------------------------------- TLB Invalidation functions -------- * get_tgh_handle *
PATCH 7/25 GRU - add context lock flag to gru status
In reply to [email protected]From: Jack Steiner <[email protected]>
Add a flag to the GRU cch_status file to indicate if the cch is locked. This is useful for debugging.
--- drivers/misc/sgi-gru/gruprocfs.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/misc/sgi-gru/gruprocfs.c +6 -5
@@ -190,21 +190,22 @@ static int cch_seq_show(struct seq_fileconst char *mode[] = {"??" ,"UPM" ,"INTR" ,"OS_POLL" };if (gid ==0 ) -seq_printf (file,"#%5s%5s%6s%7s%9s%6s%8s%8s\n" ,"gid" ,"bid" , -"ctx#" ,"asid" ,"pid" ,"cbrs" ,"dsbytes" ,"mode" ); +seq_printf (file,"#%5s%5s%6s%7s%9s%6s%8s%8s%7s\n" ,"gid" ,"bid" , +"ctx#" ,"asid" ,"pid" ,"cbrs" ,"dsbytes" ,"mode" ,"locked" );if (gru)for (i =0 ; i <GRU_NUM_CCH ; i++) { ts = gru->gs_gts[i];if (!ts)continue ; -seq_printf (file," %5d%5d%6d%7d%9d%6d%8d%8s\n" , +seq_printf (file," %5d%5d%6d%7d%9d%6d%8d%8s%7s\n" , gru->gs_gid, gru->gs_blade_id, i,is_kernel_context (ts) ?0 : ts->ts_gms->ms_asids[gid].mt_asid,is_kernel_context (ts) ?0 : ts->ts_tgid_owner, ts->ts_cbr_au_count *GRU_CBR_AU_SIZE , - ts->ts_cbr_au_count *GRU_DSR_AU_BYTES , + ts->ts_dsr_au_count *GRU_DSR_AU_BYTES , mode[ts->ts_user_options & -GRU_OPT_MISS_MASK ]); +GRU_OPT_MISS_MASK ], +mutex_is_locked (&ts->ts_ctxlock) ?"LOCKED" :"-" ); }return 0 ;
PATCH 8/25 GRU - flush gru tlb when driver is loaded
In reply to [email protected]From: Jack Steiner <[email protected]>
Flush the GRU TLB when the GRU driver is loaded. There may be stale entries in the TLB if a previous GRU was unloaded since the system was last reset.
--- drivers/misc/sgi-gru/grutlbpurge.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/misc/sgi-gru/grutlbpurge.c +2 -0
@@ -380,4 +380,6 @@ void gru_tgh_flush_init(struct gru_state/* first starting TGH index to use for remote purges */ gru->gs_tgh_first_remote = (cpus + (1 << shift) -1 ) >> shift; +/* flush the GRU TLB in case there are stale entries present */ +gru_flush_all_tlb (gru); }
PATCH 9/25 GRU - add software reserved bits to cbr definition
In reply to [email protected]From: Jack Steiner <[email protected]>
The GRU hardware has reserved a few bits for software use. Add these "software reserved" fields to the structure definitions.
--- drivers/misc/sgi-gru/gru_instructions.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/misc/sgi-gru/gru_instructions.h +13 -6
@@ -112,7 +112,8 @@ struct gru_instruction_bits { unsigned char reserved3: 1; unsigned char tlb_fault_color: 1;/* DW 1 */ -unsigned long idef4;/* 42 bits: TRi1, BufSize */ +unsigned int idef4;/* 32 bits: TRi1, BufSize */ +unsigned int sw_reserved;/* DW 2-6 */ unsigned long idef1;/* BAddr0 */ unsigned long idef5;/* Nelem */
@@ -136,7 +137,13 @@ struct gru_instruction {unsigned int tri0; }; }; -unsigned long tri1_bufsize;/* DW 1 */ +union { +unsigned long tri1_bufsize_64;/* DW 1 */ +struct { +unsigned int tri1_bufsize_32; +unsigned int sw_reserved; + }; + };unsigned long baddr0;/* DW 2 */ unsigned long nelem;/* DW 3 */ unsigned long op1_stride;/* DW 4 */
@@ -411,7 +418,7 @@ static inline void gru_ivload(void *cb, ins->baddr0 = (long )mem_addr; ins->nelem = nelem; - ins->tri1_bufsize = tri1; + ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVLOAD ,0 , xtype,IAA_RAM ,0 , tri0,CB_IMA (hints))); }
@@ -424,7 +431,7 @@ static inline void gru_ivstore(void *cb, ins->baddr0 = (long )mem_addr; ins->nelem = nelem; - ins->tri1_bufsize = tri1; + ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVSTORE ,0 , xtype,IAA_RAM ,0 , tri0,CB_IMA (hints))); }
@@ -452,7 +459,7 @@ static inline void gru_ivset(void *cb, u ins->baddr0 = (long )mem_addr; ins->op2_value_baddr1 = value; ins->nelem = nelem; - ins->tri1_bufsize = tri1; + ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVSET ,0 , xtype,IAA_RAM ,0 ,0 ,CB_IMA (hints))); }
@@ -488,7 +495,7 @@ static inline void gru_bcopy(void *cb, c ins->baddr0 = (long )src; ins->op2_value_baddr1 = (long )dest; ins->nelem = nelem; - ins->tri1_bufsize = bufsize; + ins->tri1_bufsize_64 = bufsize;gru_start_instruction (ins,__opdword (OP_BCOPY ,0 , xtype,IAA_RAM ,IAA_RAM , tri0,CB_IMA (hints))); }
PATCH 10/25 GRU - eliminate gru contention on mmap_sem
In reply to [email protected]From: Jack Steiner <[email protected]>
Rework the way the mmap_sem is used by the GRU driver. The old code had a few pathes that acquired the lock for write. By changing the place that the mmu_notifier was allocated/freed, the mmap_sem is no longer acquired for write. This eliminates some contention on the lock and improves performance of threaded tests that use the gru.
This also eliminates an endcase where zap_vma_range() could be called without holding the mmap_sem .
--- drivers/misc/sgi-gru/grufault.c | 11 ++++--- drivers/misc/sgi-gru/grufile.c | 16 +++++++---- drivers/misc/sgi-gru/gruhandles.c | 5 --- drivers/misc/sgi-gru/grumain.c | 51 ++++++++++++++++++++++--------------- drivers/misc/sgi-gru/grutables.h | 11 +++++++ drivers/misc/sgi-gru/grutlbpurge.c | 18 +++---------- 6 files changed, 63 insertions(+), 49 deletions(-)
drivers/misc/sgi-gru/grufault.c +6 -5
@@ -98,7 +98,7 @@ static struct gru_thread_state *gru_allostruct vm_area_struct *vma;struct gru_thread_state *gts =ERR_PTR (-EINVAL ); -down_write (&mm->mmap_sem); +down_read (&mm->mmap_sem); vma =gru_find_vma (current->mm, vaddr);if (!vma) goto err;
@@ -107,11 +107,10 @@ static struct gru_thread_state *gru_alloif (IS_ERR (gts)) goto err;mutex_lock (>s->ts_ctxlock); -downgrade_write (&mm->mmap_sem);return gts; err: -up_write (&mm->mmap_sem); +up_read (&mm->mmap_sem);return gts; }
@@ -764,18 +763,20 @@ static int gru_unload_all_contexts(void)struct gru_thread_state *gts;struct gru_state *gru;int gid, ctxnum; +struct gru_blade_state *blade;if (!capable (CAP_SYS_ADMIN ))return -EPERM ;foreach_gid (gid) { gru =GID_TO_GRU (gid); + blade = gru->gs_blade;spin_lock (&gru->gs_lock);for (ctxnum =0 ; ctxnum <GRU_NUM_CCH ; ctxnum++) { gts = gru->gs_gts[ctxnum]; -if (gts &&mutex_trylock (>s->ts_ctxlock)) { +if (gts &&gru_is_gts_stealable (gts, blade)) {spin_unlock (&gru->gs_lock);gru_unload_context (gts,1 ); -mutex_unlock (>s->ts_ctxlock); +gru_gts_stolen (gts, blade);spin_lock (&gru->gs_lock); } }
drivers/misc/sgi-gru/grufile.c +11 -5
@@ -88,6 +88,7 @@ static void gru_vma_close(struct vm_areamutex_unlock (>s->ts_ctxlock);gts_drop (gts); } +gru_drop_mmu_notifier (vdata->vd_gms);kfree (vdata);STAT (vdata_free); }
@@ -101,6 +102,8 @@ static void gru_vma_close(struct vm_area*/ static int gru_file_mmap (struct file *file,struct vm_area_struct *vma) { +struct gru_vma_data *vdata; +if ((vma->vm_flags & (VM_SHARED |VM_WRITE )) != (VM_SHARED |VM_WRITE ))return -EPERM ;
@@ -114,9 +117,10 @@ static int gru_file_mmap(struct file *fi vma->vm_page_prot =PAGE_SHARED ; vma->vm_ops = &gru_vm_ops; - vma->vm_private_data =gru_alloc_vma_data (vma,0 ); -if (!vma->vm_private_data) -return -ENOMEM ; + vdata =gru_alloc_vma_data (vma,0 ); +if (IS_ERR (vdata)) +return PTR_ERR (vdata); + vma->vm_private_data = vdata;gru_dbg (grudev,"file %p, vaddr 0x%lx, vma %p, vdata %p\n" , file, vma->vm_start, vma, vma->vm_private_data);
@@ -144,18 +148,20 @@ static int gru_create_new_context(unsignif (!(req.options &GRU_OPT_MISS_MASK )) req.options |=GRU_OPT_MISS_FMM_INTR ; -down_write (¤t->mm->mmap_sem); +down_read (¤t->mm->mmap_sem); vma =gru_find_vma (current->mm, req.gseg);if (vma) { vdata = vma->vm_private_data; +spin_lock (&vdata->vd_lock); vdata->vd_user_options = req.options; vdata->vd_dsr_au_count =GRU_DS_BYTES_TO_AU (req.data_segment_bytes); vdata->vd_cbr_au_count =GRU_CB_COUNT_TO_AU (req.control_blocks); vdata->vd_tlb_preload_count = req.tlb_preload_count; +spin_unlock (&vdata->vd_lock); ret =0 ; } -up_write (¤t->mm->mmap_sem); +up_read (¤t->mm->mmap_sem);return ret; }
drivers/misc/sgi-gru/gruhandles.c +0 -5
@@ -132,11 +132,6 @@ int cch_deallocate(struct gru_context_costart_instruction (cch); ret =wait_instruction_complete (cch, cchop_deallocate); -/* -* Stop speculation into the GSEG being unmapped by the previous -* DEALLOCATE. -*/ -sync_core ();return ret; }
drivers/misc/sgi-gru/grumain.c +31 -20
124 lines not on this page · raw message
drivers/misc/sgi-gru/grutables.h +10 -1
@@ -115,10 +115,14 @@* task -->| * task ---+---> mm ->------ (notifier) -------+-> gms * | | +* | +------------->| +* | / | * |--> vma -> vdata ---> gts--->| GSEG1 (thread1) * | | | * | +-> gts--->| GSEG1 (thread2) * | | +* | +------------->| +* | / | * |--> vma -> vdata ---> gts--->| GSEG2 (thread2) * . * .
@@ -336,6 +340,7 @@ struct gru_mm_struct {wait_queue_head_t ms_wait_queue;DECLARE_BITMAP (ms_asidmap,GRU_MAX_GRUS );struct gru_mm_tracker ms_asids[GRU_MAX_GRUS ]; +struct mm_struct *ms_mm;/* for mmu_notifier_unreg */ };/*
@@ -345,6 +350,7 @@ struct gru_mm_struct {struct gru_vma_data {spinlock_t vd_lock;/* Serialize access to vma */ struct list_head vd_head;/* head of linked list of gts */ +struct gru_mm_struct *vd_gms;/* asid & ioproc struct */ long vd_user_options;/* misc user option flags */ int vd_cbr_au_count;int vd_dsr_au_count;
@@ -469,7 +475,6 @@ struct gru_blade_state {reserved DSR */ struct rw_semaphore bs_kgts_sema;/* lock for kgts */ struct gru_thread_state *bs_kgts;/* GTS for kernel use */ -/* ---- the following are used for managing kernel async GRU CBRs --- */ void *bs_async_cbr;/* CBR for async */ struct completion *bs_async_wq;
@@ -670,6 +675,10 @@ extern int gru_user_flush_tlb(unsigned lextern int gru_user_unload_context (unsigned long arg);extern int gru_get_exception_detail (unsigned long arg);extern int gru_set_context_option (unsigned long address); +extern int gru_is_gts_stealable (struct gru_thread_state *gts, +struct gru_blade_state *blade); +extern void gru_gts_stolen (struct gru_thread_state *gts, +struct gru_blade_state *blade);extern void gru_check_context_placement (struct gru_thread_state *gts);extern int gru_cpu_fault_map_id (void );extern struct vm_area_struct *gru_find_vma (struct mm_struct *mm,unsigned long vaddr);
drivers/misc/sgi-gru/grutlbpurge.c +5 -13
@@ -263,21 +263,10 @@ static void gru_invalidate_page(struct mgru_dbg (grudev,"gms %p, address 0x%lx\n" , gms, address); } -static void gru_release (struct mmu_notifier *mn,struct mm_struct *mm) -{ - struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, - ms_notifier); - - gms->ms_released =1 ; -gru_dbg (grudev,"gms %p\n" , gms); -} - -static const struct mmu_notifier_ops gru_mmuops = { .invalidate_page = gru_invalidate_page, .invalidate_range_start = gru_invalidate_range_start, .invalidate_range_end = gru_invalidate_range_end, - .release = gru_release, };/* Move this to the basic mmu_notifier file. But for now... */
@@ -316,6 +305,7 @@ struct gru_mm_struct *gru_register_mmu_nSTAT (gms_alloc);spin_lock_init (&gms->ms_asid_lock); gms->ms_notifier.ops = &gru_mmuops; + gms->ms_mm = current->mm;atomic_set (&gms->ms_refcnt,1 );init_waitqueue_head (&gms->ms_wait_queue); err =__mmu_notifier_register (&gms->ms_notifier, current->mm);
@@ -328,6 +318,9 @@ struct gru_mm_struct *gru_register_mmu_nreturn gms; error:kfree (gms); +/* mmu_notifier_register EINTR is reported as EAGAIN */ +if (err == -EINTR ) + err = -EAGAIN ;return ERR_PTR (err); }
@@ -336,8 +329,7 @@ void gru_drop_mmu_notifier(struct gru_mmgru_dbg (grudev,"gms %p, refcnt %d, released %d\n" , gms,atomic_read (&gms->ms_refcnt), gms->ms_released);if (atomic_dec_return (&gms->ms_refcnt) ==0 ) { -if (!gms->ms_released) -mmu_notifier_unregister (&gms->ms_notifier, current->mm); +mmu_notifier_unregister (&gms->ms_notifier, gms->ms_mm);kfree (gms);STAT (gms_free); }
PATCH 11/25 GRU - interrupt fix for processors without core 0
In reply to [email protected]From: Jack Steiner <[email protected]>
GRU interrupts for the kernel context are targeted to core 0 of the lowest socket on the blade.
Fix an endcase for 6-socket processors that do not have a APICID for core 0. (There are potentially 8 cores in the socket. A 6 core socket has 2 cores disabled. If core 0 was disabled, the old code did not work).
--- drivers/misc/sgi-gru/grumain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/sgi-gru/grumain.c +1 -1
@@ -618,7 +618,7 @@ void gru_load_context(struct gru_thread_ cch->unmap_enable =1 ; cch->tfm_done_bit_enable =1 ; cch->cb_int_enable =1 ; - cch->tlb_int_select =0 ;/* For now, ints go to cpu 0 */ + cch->tlb_int_select =uv_cpu_core_number (0 );/* For now, ints go to cpu 0 */ }else { cch->unmap_enable =0 ; cch->tfm_done_bit_enable =0 ;
PATCH 12/25 GRU - add gru hub number to context status
In reply to [email protected]From: Jack Steiner <[email protected]>
Add the GRU hub number to the output of the GRU cch_status & gru_status files (in /proc/sgi_uv/gru).
--- drivers/misc/sgi-gru/gruprocfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/misc/sgi-gru/gruprocfs.c +6 -6
@@ -217,18 +217,18 @@ static int gru_seq_show(struct seq_filestruct gru_state *gru =GID_TO_GRU (gid);if (gid ==0 ) { -seq_printf (file,"#%5s%5s%7s%6s%6s%8s%6s%6s\n" ,"gid" ,"nid" , +seq_printf (file,"#%5s%5s%7s%6s%6s%8s%6s%6s\n" ,"hub" ,"gid" ,"ctx" ,"cbr" ,"dsr" ,"ctx" ,"cbr" ,"dsr" ); -seq_printf (file,"#%5s%5s%7s%6s%6s%8s%6s%6s\n" ,"" ,"" ,"busy" , -"busy" ,"busy" ,"free" ,"free" ,"free" ); +seq_printf (file,"#%5s%5s%7s%6s%6s%8s%6s%6s\n" ,"" ,"" ,"total" , +"total" ,"total" ,"free" ,"free" ,"free" ); }if (gru) { ctxfree =GRU_NUM_CCH - gru->gs_active_contexts; cbrfree =hweight64 (gru->gs_cbr_map) *GRU_CBR_AU_SIZE ; dsrfree =hweight64 (gru->gs_dsr_map) *GRU_DSR_AU_BYTES ; -seq_printf (file," %5d%5d%7ld%6ld%6ld%8ld%6ld%6ld\n" , - gru->gs_gid, gru->gs_blade_id,GRU_NUM_CCH - ctxfree, -GRU_NUM_CBE - cbrfree,GRU_NUM_DSR_BYTES - dsrfree, +seq_printf (file," %5d%5d%7d%6d%6d%8ld%6ld%6ld\n" , + gru->gs_blade_id, gru->gs_gid, +GRU_NUM_CCH ,GRU_NUM_CBE ,GRU_NUM_DSR_BYTES , ctxfree, cbrfree, dsrfree); }
PATCH 13/25 GRU - delete obsolete debug code
In reply to [email protected]From: Jack Steiner <[email protected]>
SGI UV driver. Delete some debug code that has outlived it's usefullness. The code is not part of a supported API
--- drivers/misc/sgi-gru/grufile.c | 25 ------------------------- drivers/misc/sgi-gru/grulib.h | 3 --- 2 files changed, 28 deletions(-)
drivers/misc/sgi-gru/grufile.c +0 -25
@@ -166,28 +166,6 @@ static int gru_create_new_context(unsignreturn ret; } -/* -* Get GRU configuration info (temp - for emulator testing) -*/ -static long gru_get_config_info (unsigned long arg) -{ -struct gru_config_info info; -int nodesperblade; - -if (num_online_nodes () >1 && - (uv_node_to_blade_id (1 ) ==uv_node_to_blade_id (0 ))) - nodesperblade =2 ; -else - nodesperblade =1 ; - info.cpus =num_online_cpus (); - info.nodes =num_online_nodes (); - info.blades = info.nodes / nodesperblade; - info.chiplets =GRU_CHIPLETS_PER_BLADE * info.blades; - -if (copy_to_user ((void __user *)arg, &info,sizeof (info))) -return -EFAULT ; -return 0 ; -}/* * gru_file_unlocked_ioctl
@@ -226,9 +204,6 @@ static long gru_file_unlocked_ioctl(strucase GRU_KTEST : err =gru_ktest (arg);break ; -case GRU_GET_CONFIG_INFO : - err =gru_get_config_info (arg); -break ;case GRU_DUMP_CHIPLET_STATE : err =gru_dump_chiplet_request (arg);break ;
drivers/misc/sgi-gru/grulib.h +0 -3
@@ -53,9 +53,6 @@/* For user TLB flushing (primarily for tests) */ #define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *) -/* Get some config options (primarily for tests & emulator) */ -#define GRU_GET_CONFIG_INFO _IOWR(GRU_IOCTL_NUM, 51, void *) -/* Various kernel self-tests */ #define GRU_KTEST _IOWR(GRU_IOCTL_NUM, 52, void *)
PATCH 14/25 GRU - add polling for tlb misses
In reply to [email protected]From: Jack Steiner <[email protected]>
Currently, the GRU driver processes TLB misses by sending an interrupt to the cpu. The TLB is updated from the interrupt handler.
Some workloads have unused cpus. This patch (still experimental) uses idle cpus to poll for TLB misses. When a miss occurs, the TLB is updated directly w/o having to send interrupts to the cpu.
--- drivers/misc/sgi-gru/gru.h | 1 drivers/misc/sgi-gru/grufault.c | 50 ++++++++++++++++++++++++++++++++++----- drivers/misc/sgi-gru/grufile.c | 20 +++++++++++++++ drivers/misc/sgi-gru/grulib.h | 10 +++++++ drivers/misc/sgi-gru/grumain.c | 33 +++++++++++-------------- drivers/misc/sgi-gru/gruprocfs.c | 2 + drivers/misc/sgi-gru/grutables.h | 7 ++++- 7 files changed, 97 insertions(+), 26 deletions(-)
drivers/misc/sgi-gru/gru.h +0 -1
@@ -71,7 +71,6 @@ struct gru_gseg_statistics {#define GRU_OPT_MISS_USER_POLL 0x0001/* User will poll CB for faults */ #define GRU_OPT_MISS_FMM_INTR 0x0002/* Send interrupt to cpu to handle fault */ -#define GRU_OPT_MISS_FMM_POLL 0x0003/* Use system polling thread */ #define GRU_OPT_MISS_MASK 0x0003/* Mask for TLB MISS option */
drivers/misc/sgi-gru/grufault.c +44 -6
80 lines not on this page · raw message
drivers/misc/sgi-gru/grufile.c +20 -0
@@ -127,6 +127,23 @@ static int gru_file_mmap(struct file *fireturn 0 ; } +int gru_enable_polling_mode (unsigned long arg) +{ +struct gru_fmm_polling_req req; +struct gru_state *gru; + +if (copy_from_user (&req, (void __user *)arg,sizeof (req))) +return -EFAULT ; + +if (req.gid >= gru_max_gids) +return -EINVAL ; + + gru =GID_TO_GRU (req.gid); +gru_intr_poll (gru->gs_chiplet_id, gru->gs_blade_id); +return 0 ; +} + +/* * Create a new GRU context */
@@ -186,6 +203,9 @@ static long gru_file_unlocked_ioctl(strucase GRU_SET_CONTEXT_OPTION : err =gru_set_context_option (arg);break ; +case GRU_FMM_POLLING_MODE : + err =gru_enable_polling_mode (arg); +break ;case GRU_USER_GET_EXCEPTION_DETAIL : err =gru_get_exception_detail (arg);break ;
drivers/misc/sgi-gru/grulib.h +10 -0
@@ -50,6 +50,9 @@/* For getting gseg statistics */ #define GRU_GET_GSEG_STATISTICS _IOWR(GRU_IOCTL_NUM, 12, void *) +/* For switching a GRU to FMM polling mode */ +#define GRU_FMM_POLLING_MODE _IOWR(GRU_IOCTL_NUM, 13, void *) +/* For user TLB flushing (primarily for tests) */ #define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *)
@@ -85,6 +88,13 @@ struct gru_unload_context_req { };/* +* Structure used to initiate GRU polling for TLB misses +*/ +struct gru_fmm_polling_req { +unsigned int gid; +}; + +/* * Structure used to set context options */ enum {sco_gseg_owner, sco_cch_req_slice, sco_blade_chiplet};
drivers/misc/sgi-gru/grumain.c +15 -18
@@ -51,7 +51,7 @@ struct device *grudev = &gru_device;* multiple cpus may be using the same map. * ZZZ should be inline but did not work on emulator */ -int gru_cpu_fault_map_id (void ) +int gru_cpu_fault_map_id (struct gru_state *gru) {#ifdef CONFIG_IA64 return uv_blade_processor_id () %GRU_NUM_TFM ;
@@ -59,6 +59,8 @@ int gru_cpu_fault_map_id(void)int cpu =smp_processor_id ();int id, core; +if (gru->gs_fmm_polling_mode) +return 0 ; core =uv_cpu_core_number (cpu); id = core +UV_MAX_INT_CORES *uv_cpu_socket_number (cpu);return id;
@@ -596,14 +598,11 @@ void gru_load_context(struct gru_thread_ cch =get_cch (gru->gs_gru_base_vaddr, ctxnum);lock_cch_handle (cch); - cch->tfm_fault_bit_enable = - (gts->ts_user_options ==GRU_OPT_MISS_FMM_POLL - || gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ); - cch->tlb_int_enable = (gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ); -if (cch->tlb_int_enable) { - gts->ts_tlb_int_select =gru_cpu_fault_map_id (); - cch->tlb_int_select = gts->ts_tlb_int_select; - } + cch->tfm_fault_bit_enable = gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ; + gts->ts_tlb_int_select =gru_cpu_fault_map_id (gru); + cch->tlb_int_select = gts->ts_tlb_int_select; + cch->tlb_int_enable = !gru->gs_fmm_polling_mode && + gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ;if (gts->ts_cch_req_slice >=0 ) { cch->req_slice_set_enable =1 ; cch->req_slice = gts->ts_cch_req_slice;
@@ -671,11 +670,9 @@ int gru_update_cch(struct gru_thread_staBUG ();for (i =0 ; i <8 ; i++) cch->sizeavail[i] = gts->ts_sizeavail; - gts->ts_tlb_int_select =gru_cpu_fault_map_id (); - cch->tlb_int_select =gru_cpu_fault_map_id (); - cch->tfm_fault_bit_enable = - (gts->ts_user_options ==GRU_OPT_MISS_FMM_POLL - || gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ); + gts->ts_tlb_int_select =gru_cpu_fault_map_id (gru); + cch->tlb_int_select = gts->ts_tlb_int_select; + cch->tfm_fault_bit_enable = gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ;if (cch_start (cch))BUG (); ret =1 ;
@@ -692,14 +689,14 @@ exit:* - task has migrated to a different cpu on the same blade where * it was previously running. */ -static int gru_retarget_intr (struct gru_thread_state *gts) +static int gru_retarget_intr (struct gru_state *gru,struct gru_thread_state *gts) {if (gts->ts_tlb_int_select <0 - || gts->ts_tlb_int_select ==gru_cpu_fault_map_id ()) + || gts->ts_tlb_int_select ==gru_cpu_fault_map_id (gru))return 0 ;gru_dbg (grudev,"retarget from %d to %d\n" , gts->ts_tlb_int_select, -gru_cpu_fault_map_id ()); +gru_cpu_fault_map_id (gru));return gru_update_cch (gts); }
@@ -745,7 +742,7 @@ void gru_check_context_placement(structif (!gru_check_chiplet_assignment (gru, gts)) {STAT (check_context_unload);gru_unload_context (gts,1 ); - }else if (gru_retarget_intr (gts)) { + }else if (gru_retarget_intr (gru, gts)) {STAT (check_context_retarget_intr); } }
drivers/misc/sgi-gru/gruprocfs.c +2 -0
@@ -72,6 +72,8 @@ static int statistics_show(struct seq_fiprintstat (s, intr);printstat (s, intr_cbr);printstat (s, intr_tfh); +printstat (s, intr_poll); +printstat (s, intr_poll_found);printstat (s, intr_spurious);printstat (s, intr_mm_lock_failed);printstat (s, call_os);
drivers/misc/sgi-gru/grutables.h +6 -1
@@ -204,6 +204,8 @@ struct gru_stats_s {atomic_long_t intr;atomic_long_t intr_cbr;atomic_long_t intr_tfh; +atomic_long_t intr_poll; +atomic_long_t intr_poll_found;atomic_long_t intr_spurious;atomic_long_t intr_mm_lock_failed;atomic_long_t call_os;
@@ -438,6 +440,8 @@ struct gru_state {local flush */ unsigned char gs_tgh_first_remote;/* starting TGH# for remote flush */ +unsigned char gs_fmm_polling_mode;/* Chiplet is in TFH polling mode +for TLB misses */ spinlock_t gs_asid_lock;/* lock used for assigning asids */ spinlock_t gs_lock;/* lock used for
@@ -668,6 +672,7 @@ extern void gru_kservices_exit(void);extern irqreturn_t gru0_intr (int irq,void *dev_id);extern irqreturn_t gru1_intr (int irq,void *dev_id);extern irqreturn_t gru_intr_mblade (int irq,void *dev_id); +extern void gru_intr_poll (int chiplet,int blade);extern int gru_dump_chiplet_request (unsigned long arg);extern long gru_get_gseg_statistics (unsigned long arg);extern int gru_handle_user_call_os (unsigned long address);
@@ -680,7 +685,7 @@ extern int gru_is_gts_stealable(struct gextern void gru_gts_stolen (struct gru_thread_state *gts,struct gru_blade_state *blade);extern void gru_check_context_placement (struct gru_thread_state *gts); -extern int gru_cpu_fault_map_id (void ); +extern int gru_cpu_fault_map_id (struct gru_state *gru);extern struct vm_area_struct *gru_find_vma (struct mm_struct *mm,unsigned long vaddr);extern void gru_flush_all_tlb (struct gru_state *gru);extern int gru_proc_init (void );
PATCH 15/25 GRU - reorder interrupt processing
In reply to [email protected]From: Jack Steiner <[email protected]>
Reorder the servicing of CBR completion interrupts & TLB miss interrupts. There is a small performance gain to service TLB misses first. Completion interrupts are rare.
--- drivers/misc/sgi-gru/grufault.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
drivers/misc/sgi-gru/grufault.c +13 -11
@@ -7,7 +7,7 @@* These misses are reported either via interrupts or user polling of * the user CB. * -* Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. +* Copyright (c) 2008-2010 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by
@@ -559,19 +559,10 @@ static irqreturn_t gru_intr(int chiplet, imap.fault_bits[0 ], imap.fault_bits[1 ], dmap.fault_bits[0], dmap.fault_bits[1]); -for_each_cbr_in_tfm (cbrnum, dmap.fault_bits) { -STAT (intr_cbr); - cmp = gru->gs_async_wq[cbrnum]; -if (cmp) -complete (cmp); -gru_dbg (grudev,"gid %d, cbr_done %d, done %d\n" , - gru->gs_gid, cbrnum, cmp ? cmp->done :-1 ); - } -for_each_cbr_in_tfm (cbrnum, imap.fault_bits) { -STAT (intr_tfh); tfh =get_tfh_by_index (gru, cbrnum);prefetchw (tfh);/* Helps on hdw, required for emulator */ +STAT (intr_tfh);/* * When hardware sets a bit in the faultmap, it implicitly
@@ -596,6 +587,8 @@ static irqreturn_t gru_intr(int chiplet, gts->ustats.interrupts++; gts->ustats.fmm_tlbmiss++; multi =1 ; +if (!gts->ts_mm) +continue ;if (!gts->ts_force_cch_reload &&down_read_trylock (>s->ts_mm->mmap_sem)) {gru_try_dropin (gru, gts, tfh,NULL );
@@ -605,6 +598,15 @@ static irqreturn_t gru_intr(int chiplet,STAT (intr_mm_lock_failed); } } +for_each_cbr_in_tfm (cbrnum, dmap.fault_bits) { +STAT (intr_cbr); + cmp = gru->gs_async_wq[cbrnum]; +if (cmp) +complete (cmp); +gru_dbg (grudev,"gid %d, cbr_done %d, done %d\n" , + gru->gs_gid, cbrnum, cmp ? cmp->done :-1 ); + } +return IRQ_HANDLED ; }
PATCH 16/25 GRU - add refcnt to vdata structure
In reply to [email protected]From: Jack Steiner <[email protected]>
The GRU vdata structure must have a reference count.
--- drivers/misc/sgi-gru/grufile.c | 21 +++++++++++++++++++-- drivers/misc/sgi-gru/grumain.c | 1 + drivers/misc/sgi-gru/gruprocfs.c | 1 + drivers/misc/sgi-gru/grutables.h | 2 ++ 4 files changed, 23 insertions(+), 2 deletions(-)
drivers/misc/sgi-gru/grufile.c +19 -2
@@ -65,6 +65,19 @@ static struct miscdevice gru_miscdev;* Called when unmapping a device mapping. Frees all gru resources * and tables belonging to the vma. */ +static void gru_vma_open (struct vm_area_struct *vma) +{ +struct gru_vma_data *vdata; + +if (!vma->vm_private_data) +return ; +STAT (vdata_open); + vdata = vma->vm_private_data; +atomic_inc (&vdata->vd_refcnt); +gru_dbg (grudev,"vma %p, file %p, vdata %p\n" , vma, vma->vm_file, + vdata); +} +static void gru_vma_close (struct vm_area_struct *vma) {struct gru_vma_data *vdata;
@@ -75,9 +88,12 @@ static void gru_vma_close(struct vm_areareturn ; vdata = vma->vm_private_data; +gru_dbg (grudev,"vma %p, file %p, vdata %p, refcnt %d\n" , vma, vma->vm_file, + vdata,atomic_read (&vdata->vd_refcnt)); +if (atomic_dec_return (&vdata->vd_refcnt) !=0 ) +return ; + vma->vm_private_data =NULL ; -gru_dbg (grudev,"vma %p, file %p, vdata %p\n" , vma, vma->vm_file, - vdata);list_for_each_safe (entry, next, &vdata->vd_head) { gts = list_entry(entry, struct gru_thread_state, ts_next);
@@ -597,6 +613,7 @@ static struct miscdevice gru_miscdev = { };const struct vm_operations_struct gru_vm_ops = { + .open = gru_vma_open, .close = gru_vma_close, .fault = gru_fault, };
drivers/misc/sgi-gru/grumain.c +1 -0
@@ -374,6 +374,7 @@ struct gru_vma_data *gru_alloc_vma_data(if (IS_ERR (gms)) goto err; vdata->vd_gms = gms; +atomic_set (&vdata->vd_refcnt,1 );STAT (vdata_alloc);INIT_LIST_HEAD (&vdata->vd_head);
Index: linux/drivers/misc/sgi-gru/gruprocfs.c
===================================================================
--- linux.orig/drivers/misc/sgi-gru/gruprocfs.c 2010-07-19 10:25:41.078288158 -0500
+++ linux/drivers/misc/sgi-gru/gruprocfs.c 2010-07-19 10:25:49.214243610 -0500
@@ -42,6 +42,7 @@ static void printstat_val(struct seq_fil
static int statistics_show(struct seq_file *s, void *p) {
printstat(s, vdata_alloc);
+ printstat(s, vdata_open);
printstat(s, vdata_free);
printstat(s, gts_alloc);
printstat(s, gts_free);
drivers/misc/sgi-gru/grutables.h +2 -0
@@ -174,6 +174,7 @@ extern unsigned int gru_max_gids;*/ struct gru_stats_s {atomic_long_t vdata_alloc; +atomic_long_t vdata_open;atomic_long_t vdata_free;atomic_long_t gts_alloc;atomic_long_t gts_free;
@@ -351,6 +352,7 @@ struct gru_mm_struct {*/ struct gru_vma_data {spinlock_t vd_lock;/* Serialize access to vma */ +atomic_t vd_refcnt;struct list_head vd_head;/* head of linked list of gts */ struct gru_mm_struct *vd_gms;/* asid & ioproc struct */ long vd_user_options;/* misc user option flags */
PATCH 17/25 GRU - no panic on gru malfunction
In reply to [email protected]From: Jack Steiner <[email protected]>
If the GRU malfunctions, print a message instead of panicing the system. This simplifies debugging since some of the debug tools can be used on a live system. Flush the cache on instruction timeouts in case the malfunction is related to a coherency issue (never seen this but I'm paranoid).
--- drivers/misc/sgi-gru/gruhandles.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/misc/sgi-gru/gruhandles.c +2 -1
@@ -71,7 +71,7 @@ static void report_instruction_timeout(velse if (TYPE_IS (TFH , goff)) id ="TFH" ; -panic (KERN_ALERT "GRU %p (%s) is malfunctioning\n" , h, id); +printk (KERN_ALERT "GRU:%d %p (%s) is malfunctioning\n" ,smp_processor_id (), h, id); }static int wait_instruction_complete (void *h,enum mcs_op opc)
@@ -85,6 +85,7 @@ static int wait_instruction_complete(voiif (status !=CCHSTATUS_ACTIVE )break ;if (GRU_OPERATION_TIMEOUT < (get_cycles () - start_time)) { +gru_flush_cache (h);report_instruction_timeout (h); start_time =get_cycles (); }
PATCH 18/25 GRU - contexts must contain cbrs
In reply to [email protected]From: Jack Steiner <[email protected]>
Don't allow users to create GRU contexts with 0 CBRs. This does not make sense & is not allowed by the chiplet. The chiplet will flag this as an error and fail to allocate the context.
--- drivers/misc/sgi-gru/grufile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/sgi-gru/grufile.c +1 -1
@@ -175,7 +175,7 @@ static int gru_create_new_context(unsignif (req.data_segment_bytes > max_user_dsr_bytes)return -EINVAL ; -if (req.control_blocks > max_user_cbrs || !req.maximum_thread_count) +if (req.control_blocks ==0 || req.control_blocks > max_user_cbrs || !req.maximum_thread_count)return -EINVAL ;if (!(req.options &GRU_OPT_MISS_MASK ))
PATCH 19/25 GRU - update debug messages and comments
In reply to [email protected]From: Jack Steiner <[email protected]>
Misc clean:
- update debug messages
- update stale comments in the code
--- drivers/misc/sgi-gru/grufault.c | 1 - drivers/misc/sgi-gru/grukservices.h | 3 +-- drivers/misc/sgi-gru/grulib.h | 1 - drivers/misc/sgi-gru/grumain.c | 26 +++++++++++++------------- drivers/misc/sgi-gru/grutlbpurge.c | 1 - 5 files changed, 14 insertions(+), 18 deletions(-)
drivers/misc/sgi-gru/grufault.c +0 -1
@@ -209,7 +209,6 @@ static int non_atomic_pte_lookup(struct* * Convert a user virtual address to a physical address * Only supports Intel large pages (2MB only) on x86_64. -* ZZZ - hugepage support is incomplete * * NOTE: mmap_sem is already held on entry to this function. This * guarantees existence of the page tables.
drivers/misc/sgi-gru/grukservices.h +1 -2
@@ -36,9 +36,8 @@* - multiple senders * - cross partition message * -* Missing features ZZZ: +* Missing features: * - user options for dealing with timeouts, queue full, etc. -* - gru_create_message_queue() needs interrupt vector info */ struct gru_message_queue_desc {
drivers/misc/sgi-gru/grulib.h +0 -1
@@ -25,7 +25,6 @@/* * Maximum number of GRU segments that a user can have open -* ZZZ temp - set high for testing. Revisit. */ #define GRU_MAX_OPEN_CONTEXTS 32
drivers/misc/sgi-gru/grumain.c +13 -13
@@ -265,7 +265,7 @@ static int gru_load_mm_tracker(struct grspin_unlock (&gms->ms_asid_lock);gru_dbg (grudev, -"gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n" , +"gid %d, gts 0x%p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n" , gru->gs_gid, gts, gms, gts->ts_ctxnum, asid, gms->ms_asidmap[0 ]);return asid;
@@ -284,7 +284,7 @@ static void gru_unload_mm_tracker(structspin_lock (&gru->gs_asid_lock);BUG_ON ((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); asids->mt_ctxbitmap ^= ctxbitmap; -gru_dbg (grudev,"gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n" , +gru_dbg (grudev,"gid %d, gts 0x%p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n" , gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0 ]);spin_unlock (&gru->gs_asid_lock);spin_unlock (&gms->ms_asid_lock);
@@ -350,12 +350,12 @@ struct gru_thread_state *gru_alloc_gts(sif (vma) {struct gru_vma_data *vdata = vma->vm_private_data; - gts->ts_gms = vdata->vd_gms;; + gts->ts_gms = vdata->vd_gms; gts->ts_mm = current->mm; gts->ts_vma = vma; } -gru_dbg (grudev,"alloc gts %p\n" , gts); +gru_dbg (grudev,"alloc gts 0x%p\n" , gts);return gts; }
@@ -399,7 +399,7 @@ struct gru_thread_state *gru_find_threadspin_lock (&vdata->vd_lock); gts =gru_find_current_gts_nolock (vdata, tsid);spin_unlock (&vdata->vd_lock); -gru_dbg (grudev,"vma %p, gts %p\n" , vma, gts); +gru_dbg (grudev,"vma %p, gts 0x%p\n" , vma, gts);return gts; }
@@ -430,7 +430,7 @@ struct gru_thread_state *gru_alloc_threalist_add (>s->ts_next, &vdata->vd_head); }spin_unlock (&vdata->vd_lock); -gru_dbg (grudev,"vma %p, gts %p\n" , vma, gts); +gru_dbg (grudev,"vma %p, gts 0x%p\n" , vma, gts);return gts; }
@@ -442,7 +442,7 @@ static void gru_free_gru_context(structstruct gru_state *gru; gru = gts->ts_gru; -gru_dbg (grudev,"gts %p, gid %d\n" , gts, gru->gs_gid); +gru_dbg (grudev,"gts 0x%p, gid %d\n" , gts, gru->gs_gid);spin_lock (&gru->gs_lock); gru->gs_gts[gts->ts_ctxnum] =NULL ;
@@ -565,7 +565,7 @@ void gru_unload_context(struct gru_threazap_vma_ptes (gts->ts_vma,UGRUADDR (gts),GRU_GSEG_PAGESIZE ); cch =get_cch (gru->gs_gru_base_vaddr, ctxnum); -gru_dbg (grudev,"gts %p, cbrmap 0x%lx, dsrmap 0x%lx\n" , +gru_dbg (grudev,"gts 0x%p, cbrmap 0x%lx, dsrmap 0x%lx\n" , gts, gts->ts_cbr_map, gts->ts_dsr_map);lock_cch_handle (cch);if (cch_interrupt_sync (cch))
@@ -633,7 +633,7 @@ void gru_load_context(struct gru_thread_ err =cch_allocate (cch);if (err) {gru_dbg (grudev, -"err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n" , +"err %d: cch %p, gts 0x%p, cbr 0x%lx, dsr 0x%lx\n" , err, cch, gts, gts->ts_cbr_map, gts->ts_dsr_map);BUG (); }
@@ -645,7 +645,7 @@ void gru_load_context(struct gru_thread_BUG ();unlock_cch_handle (cch); -gru_dbg (grudev,"gid %d, gts %p, cbrmap 0x%lx, dsrmap 0x%lx, tie %d, tis %d\n" , +gru_dbg (grudev,"gid %d, gts 0x%p, cbrmap 0x%lx, dsrmap 0x%lx, tie %d, tis %d\n" , gts->ts_gru->gs_gid, gts, gts->ts_cbr_map, gts->ts_dsr_map, (gts->ts_user_options ==GRU_OPT_MISS_FMM_INTR ), gts->ts_tlb_int_select); }
@@ -851,7 +851,7 @@ void gru_steal_context(struct gru_threadSTAT (steal_context_failed); }gru_dbg (grudev, -"stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;" +"stole gid %d, ctxnum %d from gts 0x%p. Need cb %d, ds %d;" " avail cb %ld, ds %ld\n" , gru->gs_gid, ctxnum, ngts, cbr, dsr,hweight64 (gru->gs_cbr_map),hweight64 (gru->gs_dsr_map));
@@ -913,8 +913,8 @@ again:STAT (assign_context);gru_dbg (grudev, -"gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n" , -gseg_virtual_address (gts->ts_gru, gts->ts_ctxnum), gts, +"gseg %p, pid %d, gts 0x%p, gid %d, ctx %d, cbr %d, dsr %d\n" , +gseg_virtual_address (gts->ts_gru, gts->ts_ctxnum), current->pid, gts, gts->ts_gru->gs_gid, gts->ts_ctxnum, gts->ts_cbr_au_count, gts->ts_dsr_au_count); }else {
drivers/misc/sgi-gru/grutlbpurge.c +0 -1
@@ -162,7 +162,6 @@ void gru_flush_tlb_range(struct gru_mm_sunsigned long num;int grupagesize, pagesize, pageshift, gid, asid; -/* ZZZ TODO - handle huge pages */ pageshift =PAGE_SHIFT ; pagesize = (1UL << pageshift); grupagesize =GRU_PAGESIZE (pageshift);
PATCH 20/25 GRU - add gsh information to gru dumps
In reply to [email protected]From: Jack Steiner <[email protected]>
Add support for dumpping the GRU GSH state. This provides addition debugging information for GRU failures.
Add missing cache flush instructions. For performance reasons, the CBE does not alway maintain cache-coherency.
--- drivers/misc/sgi-gru/grukdump.c | 17 ++++++++++++++++- drivers/misc/sgi-gru/grulib.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-)
drivers/misc/sgi-gru/grukdump.c +16 -1
@@ -54,10 +54,16 @@ static int gru_dump_context_data(void *g cb = gseg +GRU_CB_BASE ; cbe = grubase +GRU_CBE_BASE ; tfh = grubase +GRU_TFH_BASE ; +sync_core (); +gru_flush_cache (cbe);for_each_cbr_in_allocation_map (i, &cch->cbr_allocation_map, scr) { -if (flush_cbrs) +if (flush_cbrs) {gru_flush_cache (cb); +gru_flush_cache (tfh + i *GRU_HANDLE_STRIDE ); + } +gru_flush_cache (cbe + i *GRU_HANDLE_STRIDE ); +sync_core ();if (gru_user_copy_handle (&ubuf, cb)) goto fail;if (gru_user_copy_handle (&ubuf, tfh + i *GRU_HANDLE_STRIDE ))
@@ -130,6 +136,7 @@ static int gru_dump_context(struct gru_smemset (&hdr,0 ,sizeof (hdr)); grubase = gru->gs_gru_base_vaddr; cch =get_cch (grubase, ctxnum); +gru_flush_cache (cch);for (try =0 ; try <CCH_LOCK_ATTEMPTS ; try++) { cch_locked =trylock_cch_handle (cch);if (cch_locked)
@@ -184,6 +191,12 @@ fail:unlock_cch_handle (cch);return -EFAULT ; } +static void dump_gsh_state (struct gru_state *gru, +struct gru_dump_chiplet_state_req *req) +{ +memset (&req->gsh_cb_state,0 ,sizeof (req->gsh_cb_state)); +memset (&req->gsh_cch_state,0 ,sizeof (req->gsh_cch_state)); +}int gru_dump_chiplet_request (unsigned long arg) {
@@ -214,6 +227,8 @@ int gru_dump_chiplet_request(unsigned lo goto fail; ubuf += ret; +dump_gsh_state (gru, &req); +for (ctxnum =0 ; ctxnum <GRU_NUM_CCH ; ctxnum++) {if (req.ctxnum == ctxnum || req.ctxnum <0 ) { ret = gru_dump_context(gru, ctxnum, ubuf, ubufend,
drivers/misc/sgi-gru/grulib.h +2 -0
@@ -130,6 +130,8 @@ struct gru_dump_chiplet_state_req {size_t buflen;/* ---- output --- */ unsigned int num_contexts; +unsigned long gsh_cb_state[16 ]; +unsigned long gsh_cch_state[16 ]; };#define GRU_DUMP_MAGIC 0x3474ab6c
PATCH 21/25 GRU - delete unused gru statistics structure
In reply to [email protected]From: Jack Steiner <[email protected]>
Delete unused structure that was left over from debugging.
--- drivers/misc/sgi-gru/gru.h | 15 --------------- 1 file changed, 15 deletions(-)
drivers/misc/sgi-gru/gru.h +0 -15
@@ -39,21 +39,6 @@#endif /* -* Structure for obtaining GRU resource information -*/ -struct gru_chiplet_info { -int node; -int chiplet; -int blade; -int total_dsr_bytes; -int total_cbr; -int total_user_dsr_bytes; -int total_user_cbr; -int free_user_dsr_bytes; -int free_user_cbr; -}; - -/* * Statictics kept for each context. */ struct gru_gseg_statistics {
PATCH 22/25 GRU - gru api cleanup
In reply to [email protected]From: Jack Steiner <[email protected]>
Header file cleanup & reorganization. A variant of the gru_instructions.h header file is part of the user API. Move items that are NOT part of the user API from this header file to internal header files.
- move the CBX definition
- move the exception retrybits
- remove the option for mapped/unmapped mode from the instruction macros. Users always run in mapped mode; the kernel always runs in ummapped mode. This option does not need to an option exposed via the macros
--- drivers/misc/sgi-gru/gru_instructions.h | 88 +++++++------------------------- drivers/misc/sgi-gru/gruhandles.h | 1 drivers/misc/sgi-gru/grulib.h | 34 ++++++++++++ 3 files changed, 55 insertions(+), 68 deletions(-)
drivers/misc/sgi-gru/gru_instructions.h +20 -68
@@ -71,21 +71,6 @@ extern void gru_wait_abort_proc(void *cb#define CBSS_PUT_NACKED 5/* -* Structure used to fetch exception detail for CBs that terminate with -* CBS_EXCEPTION -*/ -struct control_block_extended_exc_detail { -unsigned long cb; -int opc; -int ecause; -int exopc; -long exceptdet0; -int exceptdet1; -int cbrstate; -int cbrexecstatus; -}; - -/* * Instruction formats */
@@ -289,19 +274,6 @@ struct gru_instruction {#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT)#define CBR_EXS_CB_INT_PENDING (1 << CBR_EXS_CB_INT_PENDING_BIT) -/* -* Exceptions are retried for the following cases. If any OTHER bits are set -* in ecause, the exception is not retryable. -*/ -#define EXCEPTION_RETRY_BITS (CBE_CAUSE_EXECUTION_HW_ERROR | \ - CBE_CAUSE_TLBHW_ERROR | \ - CBE_CAUSE_RA_REQUEST_TIMEOUT | \ - CBE_CAUSE_RA_RESPONSE_NON_FATAL | \ - CBE_CAUSE_HA_RESPONSE_NON_FATAL | \ - CBE_CAUSE_RA_RESPONSE_DATA_ERROR | \ - CBE_CAUSE_HA_RESPONSE_DATA_ERROR \ - ) -/* Message queue head structure */ union gru_mesqhead {unsigned long val;
@@ -311,7 +283,6 @@ union gru_mesqhead { }; }; -/* Generate the low word of a GRU instruction */ static inline unsigned long __opdword(unsigned char opcode, unsigned char exopc, unsigned char xtype,
@@ -324,6 +295,7 @@ __opdword(unsigned char opcode, unsigned (iaa0 <<GRU_CB_IAA0_SHFT ) | (iaa1 <<GRU_CB_IAA1_SHFT ) | (ima <<GRU_CB_IMA_SHFT ) | + (IMA_UNMAPPED <<GRU_CB_IMA_SHFT ) | (xtype <<GRU_CB_XTYPE_SHFT ) | (opcode <<GRU_CB_OPC_SHFT ) | (exopc <<GRU_CB_EXOPC_SHFT );
@@ -349,12 +321,6 @@ static inline void gru_start_instruction } -/* Convert "hints" to IMA */ -#define CB_IMA (h) ((h) | IMA_UNMAPPED) - -/* Convert data segment cache line index into TRI0 / TRI1 value */ -#define GRU_DINDEX (i) ((i) * GRU_CACHE_LINE_BYTES) -/* Inline functions for GRU instructions. * Note: * - nelem and stride are in elements
@@ -369,7 +335,7 @@ static inline void gru_vload_phys(void * ins->nelem =1 ; ins->op1_stride =1 ;gru_start_instruction (ins,__opdword (OP_VLOAD ,0 ,XTYPE_DW , iaa,0 , - (unsigned long )tri0,CB_IMA (hints))); + (unsigned long )tri0, hints)); } static inline void gru_vstore_phys(void *cb, unsigned long gpa,
@@ -381,7 +347,7 @@ static inline void gru_vstore_phys(void ins->nelem =1 ; ins->op1_stride =1 ;gru_start_instruction (ins,__opdword (OP_VSTORE ,0 ,XTYPE_DW , iaa,0 , - (unsigned long )tri0,CB_IMA (hints))); + (unsigned long )tri0, hints)); } static inline void gru_vload(void *cb, unsigned long mem_addr,
@@ -394,7 +360,7 @@ static inline void gru_vload(void *cb, u ins->nelem = nelem; ins->op1_stride = stride;gru_start_instruction (ins,__opdword (OP_VLOAD ,0 , xtype,IAA_RAM ,0 , - (unsigned long )tri0,CB_IMA (hints))); + (unsigned long )tri0, hints)); } static inline void gru_vstore(void *cb, unsigned long mem_addr,
@@ -407,7 +373,7 @@ static inline void gru_vstore(void *cb, ins->nelem = nelem; ins->op1_stride = stride;gru_start_instruction (ins,__opdword (OP_VSTORE ,0 , xtype,IAA_RAM ,0 , - tri0,CB_IMA (hints))); + tri0, hints)); } static inline void gru_ivload(void *cb, unsigned long mem_addr,
@@ -420,7 +386,7 @@ static inline void gru_ivload(void *cb, ins->nelem = nelem; ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVLOAD ,0 , xtype,IAA_RAM ,0 , - tri0,CB_IMA (hints))); + tri0, hints)); } static inline void gru_ivstore(void *cb, unsigned long mem_addr,
@@ -433,7 +399,7 @@ static inline void gru_ivstore(void *cb, ins->nelem = nelem; ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVSTORE ,0 , xtype,IAA_RAM ,0 , - tri0,CB_IMA (hints))); + tri0, hints)); } static inline void gru_vset(void *cb, unsigned long mem_addr,
@@ -447,7 +413,7 @@ static inline void gru_vset(void *cb, un ins->nelem = nelem; ins->op1_stride = stride;gru_start_instruction (ins,__opdword (OP_VSET ,0 , xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_ivset(void *cb, unsigned long mem_addr,
@@ -461,7 +427,7 @@ static inline void gru_ivset(void *cb, u ins->nelem = nelem; ins->tri1_bufsize_64 = tri1;gru_start_instruction (ins,__opdword (OP_IVSET ,0 , xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_vflush(void *cb, unsigned long mem_addr,
@@ -474,14 +440,14 @@ static inline void gru_vflush(void *cb, ins->op1_stride = stride; ins->nelem = nelem;gru_start_instruction (ins,__opdword (OP_VFLUSH ,0 , xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); }static inline void gru_nop (void *cb,int hints) {struct gru_instruction *ins = (void *)cb; -gru_start_instruction (ins,__opdword (OP_NOP ,0 ,0 ,0 ,0 ,0 ,CB_IMA (hints))); +gru_start_instruction (ins,__opdword (OP_NOP ,0 ,0 ,0 ,0 ,0 , hints)); }
@@ -497,7 +463,7 @@ static inline void gru_bcopy(void *cb, c ins->nelem = nelem; ins->tri1_bufsize_64 = bufsize;gru_start_instruction (ins,__opdword (OP_BCOPY ,0 , xtype,IAA_RAM , -IAA_RAM , tri0,CB_IMA (hints))); +IAA_RAM , tri0, hints)); } static inline void gru_bstore(void *cb, const unsigned long src,
@@ -510,7 +476,7 @@ static inline void gru_bstore(void *cb, ins->op2_value_baddr1 = (long )dest; ins->nelem = nelem;gru_start_instruction (ins,__opdword (OP_BSTORE ,0 , xtype,0 ,IAA_RAM , - tri0,CB_IMA (hints))); + tri0, hints)); } static inline void gru_gamir(void *cb, int exopc, unsigned long src,
@@ -520,7 +486,7 @@ static inline void gru_gamir(void *cb, i ins->baddr0 = (long )src;gru_start_instruction (ins,__opdword (OP_GAMIR , exopc, xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_gamirr(void *cb, int exopc, unsigned long src,
@@ -530,7 +496,7 @@ static inline void gru_gamirr(void *cb, ins->baddr0 = (long )src;gru_start_instruction (ins,__opdword (OP_GAMIRR , exopc, xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_gamer(void *cb, int exopc, unsigned long src,
@@ -544,7 +510,7 @@ static inline void gru_gamer(void *cb, i ins->op1_stride = operand1; ins->op2_value_baddr1 = operand2;gru_start_instruction (ins,__opdword (OP_GAMER , exopc, xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_gamerr(void *cb, int exopc, unsigned long src,
@@ -557,7 +523,7 @@ static inline void gru_gamerr(void *cb, ins->op1_stride = operand1; ins->op2_value_baddr1 = operand2;gru_start_instruction (ins,__opdword (OP_GAMERR , exopc, xtype,IAA_RAM ,0 , -0 ,CB_IMA (hints))); +0 , hints)); } static inline void gru_gamxr(void *cb, unsigned long src,
@@ -568,7 +534,7 @@ static inline void gru_gamxr(void *cb, u ins->baddr0 = (long )src; ins->nelem =4 ;gru_start_instruction (ins,__opdword (OP_GAMXR ,EOP_XR_CSWAP ,XTYPE_DW , -IAA_RAM ,0 ,0 ,CB_IMA (hints))); +IAA_RAM ,0 ,0 , hints)); } static inline void gru_mesq(void *cb, unsigned long queue,
@@ -580,7 +546,7 @@ static inline void gru_mesq(void *cb, un ins->baddr0 = (long )queue; ins->nelem = nelem;gru_start_instruction (ins,__opdword (OP_MESQ ,0 ,XTYPE_CL ,IAA_RAM ,0 , - tri0,CB_IMA (hints))); + tri0, hints)); }static inline unsigned long gru_get_amo_value (void *cb)
@@ -613,12 +579,6 @@ static inline union gru_mesqhead gru_mereturn mqh; } -/* -* Get struct control_block_extended_exc_detail for CB. -*/ -extern int gru_get_cb_exception_detail (void *cb, -struct control_block_extended_exc_detail *excdet); -#define GRU_EXC_STR_SIZE 256
@@ -671,6 +631,7 @@ static inline int gru_check_status(voidstruct gru_control_block_status *cbs = (void *)cb;int ret; +barrier (); ret = cbs->istatus;if (ret !=CBS_ACTIVE ) ret =gru_check_status_proc (cb);
@@ -700,15 +661,6 @@ static inline void gru_wait_abort(void * }/* -* Get a pointer to the start of a gseg -* p - Any valid pointer within the gseg -*/ -static inline void *gru_get_gseg_pointer (void *p) -{ -return (void *)((unsigned long )p & ~(GRU_GSEG_PAGESIZE -1 )); -} - -/* * Get a pointer to a control block * gseg - GSeg address returned from gru_get_thread_gru_segment() * index - index of desired CB
drivers/misc/sgi-gru/gruhandles.h +1 -0
@@ -22,6 +22,7 @@#ifndef __GRUHANDLES_H__#define __GRUHANDLES_H__ +#include "grulib.h" #include "gru_instructions.h" /*
drivers/misc/sgi-gru/grulib.h +34 -0
@@ -62,6 +62,25 @@#define THREAD_POINTER (p, th) (p + GRU_GSEG_PAGESIZE * (th))#define GSEG_START (cb) ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1))) +/* +* Size used to map GRU GSeg +*/ +#define GRU_GSEG_PAGESIZE (256 * 1024UL) + +/* +* Exceptions are retried for the following cases. If any OTHER bits are set +* in ecause, the exception is not retryable. +*/ +#define EXCEPTION_RETRY_BITS (CBE_CAUSE_EXECUTION_HW_ERROR | \ + CBE_CAUSE_TLBHW_ERROR | \ + CBE_CAUSE_RA_REQUEST_TIMEOUT | \ + CBE_CAUSE_RA_RESPONSE_NON_FATAL | \ + CBE_CAUSE_HA_RESPONSE_NON_FATAL | \ + CBE_CAUSE_RA_RESPONSE_DATA_ERROR | \ + CBE_CAUSE_HA_RESPONSE_DATA_ERROR \ + ) + +struct gru_get_gseg_statistics_req {unsigned long gseg;struct gru_gseg_statistics stats;
@@ -134,6 +153,21 @@ struct gru_dump_chiplet_state_req {unsigned long gsh_cch_state[16 ]; }; +/* +* Structure used to fetch exception detail for CBs that terminate with +* CBS_EXCEPTION +*/ +struct control_block_extended_exc_detail { +unsigned long cb; +int opc; +int ecause; +int exopc; +long exceptdet0; +int exceptdet1; +int cbrstate; +int cbrexecstatus; +}; +#define GRU_DUMP_MAGIC 0x3474ab6cstruct gru_dump_context_header {unsigned int magic;
PATCH 23/25 GRU - update driverr version
In reply to [email protected]From: Jack Steiner <[email protected]>
Update the GRU driver version to 1.0.
--- drivers/misc/sgi-gru/grutables.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/sgi-gru/grutables.h +1 -1
@@ -165,7 +165,7 @@ extern unsigned int gru_max_gids;#define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE)#define GRU_DRIVER_ID_STR "SGI GRU Device Driver" -#define GRU_DRIVER_VERSION_STR "0.85" +#define GRU_DRIVER_VERSION_STR "1.00"#define gru_random () get_cycles()
PATCH 24/25 GRU - rename gru pagesize defines
In reply to [email protected]From: Jack Steiner <[email protected]>
Change the name of GRU_GSEG_PAGESIZE to GRU_MIN_GSEG_PAGESIZE to more accurately reflect it's use. This is in preparation for allocating contexts using hugepages.
--- drivers/misc/sgi-gru/gru.h | 10 ++-------- drivers/misc/sgi-gru/gru_instructions.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-)
drivers/misc/sgi-gru/gru.h +2 -8
@@ -28,15 +28,9 @@#define GRU_DS_BASE 0x20000/* -* Size used to map GRU GSeg +* Minimum page size used to map a GRU context */ -#if defined(CONFIG_IA64 ) -#define GRU_GSEG_PAGESIZE (256 * 1024UL) -#elif defined(CONFIG_X86_64 ) -#define GRU_GSEG_PAGESIZE (256 * 1024UL)/* ZZZ 2MB ??? */ -#else -#error "Unsupported architecture" -#endif +#define GRU_MIN_GSEG_PAGESIZE (256 * 1024UL)/* * Statictics kept for each context.
drivers/misc/sgi-gru/gru_instructions.h +1 -1
@@ -687,6 +687,6 @@ static inline void *gru_get_data_pointer*/ static inline int gru_get_tri (void *vaddr) { -return ((unsigned long )vaddr & (GRU_GSEG_PAGESIZE -1 )) -GRU_DS_BASE ; +return ((unsigned long )vaddr & (GRU_MIN_GSEG_PAGESIZE -1 )) -GRU_DS_BASE ; }#endif /* __GRU_INSTRUCTIONS_H__ */
PATCH 25/25 GRU - update cbrstate definitions
In reply to [email protected]From: Jack Steiner <[email protected]>
Update the CBRSTATE definitions to match what was actually implemented in hardware.
--- drivers/misc/sgi-gru/gruhandles.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/misc/sgi-gru/gruhandles.h +8 -4
@@ -478,15 +478,19 @@ enum gru_cbr_state {CBRSTATE_INACTIVE ,CBRSTATE_IDLE ,CBRSTATE_PE_CHECK , +CBRSTATE_DSR_PRE ,CBRSTATE_QUEUED , +CBRSTATE_ISSUED ,CBRSTATE_WAIT_RESPONSE , -CBRSTATE_INTERRUPTED , -CBRSTATE_INTERRUPTED_MISS_FMM , +CBRSTATE_DSR_POST ,CBRSTATE_BUSY_INTERRUPT_MISS_FMM , +CBRSTATE_INTERRUPTED_MISS_FMM , +CBRSTATE_BUSY_INTERRUPT_MISS_UPM ,CBRSTATE_INTERRUPTED_MISS_UPM , -CBRSTATE_BUSY_INTERRUPTED_MISS_UPM , -CBRSTATE_REQUEST_ISSUE ,CBRSTATE_BUSY_INTERRUPT , +CBRSTATE_INTERRUPTED , +CBRSTATE_BCPY_CHECK , + CBRSTATE_WAIT_DONE, };/* CBE cbrexecstatus bits - defined in gru_instructions.h*/