diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:06:39 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:06:39 -0800 |
commit | 9cfc86249f32d984339c6d1f8a1fd1326989b3b8 (patch) | |
tree | 56428d319483f54949de8d9d0a5b3f715287ed91 /drivers/misc/sgi-gru/gruhandles.c | |
parent | f42647acc4eab1befa9e290691ed7a40f9a7d3cc (diff) | |
parent | 243797f59b748f679ab88d456fcc4f92236d724b (diff) |
Merge branch 'akpm'
* akpm: (173 commits)
genalloc: use bitmap_find_next_zero_area
ia64: use bitmap_find_next_zero_area
sparc: use bitmap_find_next_zero_area
mlx4: use bitmap_find_next_zero_area
isp1362-hcd: use bitmap_find_next_zero_area
iommu-helper: use bitmap library
bitmap: introduce bitmap_set, bitmap_clear, bitmap_find_next_zero_area
qnx4: use hweight8
qnx4fs: remove remains of the (defunct) write support
resource: constify arg to resource_size() and resource_type()
gru: send cross partition interrupts using the gru
gru: function to generate chipset IPI values
gru: update driver version number
gru: improve GRU TLB dropin statistics
gru: fix GRU interrupt race at deallocate
gru: add hugepage support
gru: fix bug in allocation of kernel contexts
gru: update GRU structures to match latest hardware spec
gru: check for correct GRU chiplet assignment
gru: remove stray local_irq_enable
...
Diffstat (limited to 'drivers/misc/sgi-gru/gruhandles.c')
-rw-r--r-- | drivers/misc/sgi-gru/gruhandles.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c index 37e7cfc53b9..2f30badc6ff 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c @@ -27,9 +27,11 @@ #ifdef CONFIG_IA64 #include <asm/processor.h> #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) +#define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq) #else #include <asm/tsc.h> #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) +#define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz) #endif /* Extract the status field from a kernel handle */ @@ -39,21 +41,39 @@ struct mcs_op_statistic mcs_op_statistics[mcsop_last]; static void update_mcs_stats(enum mcs_op op, unsigned long clks) { + unsigned long nsec; + + nsec = CLKS2NSEC(clks); atomic_long_inc(&mcs_op_statistics[op].count); - atomic_long_add(clks, &mcs_op_statistics[op].total); - if (mcs_op_statistics[op].max < clks) - mcs_op_statistics[op].max = clks; + atomic_long_add(nsec, &mcs_op_statistics[op].total); + if (mcs_op_statistics[op].max < nsec) + mcs_op_statistics[op].max = nsec; } static void start_instruction(void *h) { unsigned long *w0 = h; - wmb(); /* setting CMD bit must be last */ - *w0 = *w0 | 1; + wmb(); /* setting CMD/STATUS bits must be last */ + *w0 = *w0 | 0x20001; gru_flush_cache(h); } +static void report_instruction_timeout(void *h) +{ + unsigned long goff = GSEGPOFF((unsigned long)h); + char *id = "???"; + + if (TYPE_IS(CCH, goff)) + id = "CCH"; + else if (TYPE_IS(TGH, goff)) + id = "TGH"; + else if (TYPE_IS(TFH, goff)) + id = "TFH"; + + panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id); +} + static int wait_instruction_complete(void *h, enum mcs_op opc) { int status; @@ -64,9 +84,10 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) status = GET_MSEG_HANDLE_STATUS(h); if (status != CCHSTATUS_ACTIVE) break; - if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) - panic("GRU %p is malfunctioning: start %ld, end %ld\n", - h, start_time, (unsigned long)get_cycles()); + if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) { + report_instruction_timeout(h); + start_time = get_cycles(); + } } if (gru_options & OPT_STATS) update_mcs_stats(opc, get_cycles() - start_time); @@ -75,9 +96,18 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) int cch_allocate(struct gru_context_configuration_handle *cch) { + int ret; + cch->opc = CCHOP_ALLOCATE; start_instruction(cch); - return wait_instruction_complete(cch, cchop_allocate); + ret = wait_instruction_complete(cch, cchop_allocate); + + /* + * Stop speculation into the GSEG being mapped by the previous ALLOCATE. + * The GSEG memory does not exist until the ALLOCATE completes. + */ + sync_core(); + return ret; } int cch_start(struct gru_context_configuration_handle *cch) @@ -96,9 +126,18 @@ int cch_interrupt(struct gru_context_configuration_handle *cch) int cch_deallocate(struct gru_context_configuration_handle *cch) { + int ret; + cch->opc = CCHOP_DEALLOCATE; start_instruction(cch); - return wait_instruction_complete(cch, cchop_deallocate); + ret = wait_instruction_complete(cch, cchop_deallocate); + + /* + * Stop speculation into the GSEG being unmapped by the previous + * DEALLOCATE. + */ + sync_core(); + return ret; } int cch_interrupt_sync(struct gru_context_configuration_handle @@ -126,17 +165,20 @@ int tgh_invalidate(struct gru_tlb_global_handle *tgh, return wait_instruction_complete(tgh, tghop_invalidate); } -void tfh_write_only(struct gru_tlb_fault_handle *tfh, - unsigned long pfn, unsigned long vaddr, - int asid, int dirty, int pagesize) +int tfh_write_only(struct gru_tlb_fault_handle *tfh, + unsigned long paddr, int gaa, + unsigned long vaddr, int asid, int dirty, + int pagesize) { tfh->fillasid = asid; tfh->fillvaddr = vaddr; - tfh->pfn = pfn; + tfh->pfn = paddr >> GRU_PADDR_SHIFT; + tfh->gaa = gaa; tfh->dirty = dirty; tfh->pagesize = pagesize; tfh->opc = TFHOP_WRITE_ONLY; start_instruction(tfh); + return wait_instruction_complete(tfh, tfhop_write_only); } void tfh_write_restart(struct gru_tlb_fault_handle *tfh, |