diff options
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 37e7cfc53b9c..2f30badc6ffd 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c | |||
@@ -27,9 +27,11 @@ | |||
27 | #ifdef CONFIG_IA64 | 27 | #ifdef CONFIG_IA64 |
28 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
29 | #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) | 29 | #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) |
30 | #define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq) | ||
30 | #else | 31 | #else |
31 | #include <asm/tsc.h> | 32 | #include <asm/tsc.h> |
32 | #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) | 33 | #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) |
34 | #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz) | ||
33 | #endif | 35 | #endif |
34 | 36 | ||
35 | /* Extract the status field from a kernel handle */ | 37 | /* Extract the status field from a kernel handle */ |
@@ -39,21 +41,39 @@ struct mcs_op_statistic mcs_op_statistics[mcsop_last]; | |||
39 | 41 | ||
40 | static void update_mcs_stats(enum mcs_op op, unsigned long clks) | 42 | static void update_mcs_stats(enum mcs_op op, unsigned long clks) |
41 | { | 43 | { |
44 | unsigned long nsec; | ||
45 | |||
46 | nsec = CLKS2NSEC(clks); | ||
42 | atomic_long_inc(&mcs_op_statistics[op].count); | 47 | atomic_long_inc(&mcs_op_statistics[op].count); |
43 | atomic_long_add(clks, &mcs_op_statistics[op].total); | 48 | atomic_long_add(nsec, &mcs_op_statistics[op].total); |
44 | if (mcs_op_statistics[op].max < clks) | 49 | if (mcs_op_statistics[op].max < nsec) |
45 | mcs_op_statistics[op].max = clks; | 50 | mcs_op_statistics[op].max = nsec; |
46 | } | 51 | } |
47 | 52 | ||
48 | static void start_instruction(void *h) | 53 | static void start_instruction(void *h) |
49 | { | 54 | { |
50 | unsigned long *w0 = h; | 55 | unsigned long *w0 = h; |
51 | 56 | ||
52 | wmb(); /* setting CMD bit must be last */ | 57 | wmb(); /* setting CMD/STATUS bits must be last */ |
53 | *w0 = *w0 | 1; | 58 | *w0 = *w0 | 0x20001; |
54 | gru_flush_cache(h); | 59 | gru_flush_cache(h); |
55 | } | 60 | } |
56 | 61 | ||
62 | static void report_instruction_timeout(void *h) | ||
63 | { | ||
64 | unsigned long goff = GSEGPOFF((unsigned long)h); | ||
65 | char *id = "???"; | ||
66 | |||
67 | if (TYPE_IS(CCH, goff)) | ||
68 | id = "CCH"; | ||
69 | else if (TYPE_IS(TGH, goff)) | ||
70 | id = "TGH"; | ||
71 | else if (TYPE_IS(TFH, goff)) | ||
72 | id = "TFH"; | ||
73 | |||
74 | panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id); | ||
75 | } | ||
76 | |||
57 | static int wait_instruction_complete(void *h, enum mcs_op opc) | 77 | static int wait_instruction_complete(void *h, enum mcs_op opc) |
58 | { | 78 | { |
59 | int status; | 79 | int status; |
@@ -64,9 +84,10 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) | |||
64 | status = GET_MSEG_HANDLE_STATUS(h); | 84 | status = GET_MSEG_HANDLE_STATUS(h); |
65 | if (status != CCHSTATUS_ACTIVE) | 85 | if (status != CCHSTATUS_ACTIVE) |
66 | break; | 86 | break; |
67 | if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) | 87 | if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) { |
68 | panic("GRU %p is malfunctioning: start %ld, end %ld\n", | 88 | report_instruction_timeout(h); |
69 | h, start_time, (unsigned long)get_cycles()); | 89 | start_time = get_cycles(); |
90 | } | ||
70 | } | 91 | } |
71 | if (gru_options & OPT_STATS) | 92 | if (gru_options & OPT_STATS) |
72 | update_mcs_stats(opc, get_cycles() - start_time); | 93 | update_mcs_stats(opc, get_cycles() - start_time); |
@@ -75,9 +96,18 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) | |||
75 | 96 | ||
76 | int cch_allocate(struct gru_context_configuration_handle *cch) | 97 | int cch_allocate(struct gru_context_configuration_handle *cch) |
77 | { | 98 | { |
99 | int ret; | ||
100 | |||
78 | cch->opc = CCHOP_ALLOCATE; | 101 | cch->opc = CCHOP_ALLOCATE; |
79 | start_instruction(cch); | 102 | start_instruction(cch); |
80 | return wait_instruction_complete(cch, cchop_allocate); | 103 | ret = wait_instruction_complete(cch, cchop_allocate); |
104 | |||
105 | /* | ||
106 | * Stop speculation into the GSEG being mapped by the previous ALLOCATE. | ||
107 | * The GSEG memory does not exist until the ALLOCATE completes. | ||
108 | */ | ||
109 | sync_core(); | ||
110 | return ret; | ||
81 | } | 111 | } |
82 | 112 | ||
83 | int cch_start(struct gru_context_configuration_handle *cch) | 113 | int cch_start(struct gru_context_configuration_handle *cch) |
@@ -96,9 +126,18 @@ int cch_interrupt(struct gru_context_configuration_handle *cch) | |||
96 | 126 | ||
97 | int cch_deallocate(struct gru_context_configuration_handle *cch) | 127 | int cch_deallocate(struct gru_context_configuration_handle *cch) |
98 | { | 128 | { |
129 | int ret; | ||
130 | |||
99 | cch->opc = CCHOP_DEALLOCATE; | 131 | cch->opc = CCHOP_DEALLOCATE; |
100 | start_instruction(cch); | 132 | start_instruction(cch); |
101 | return wait_instruction_complete(cch, cchop_deallocate); | 133 | ret = wait_instruction_complete(cch, cchop_deallocate); |
134 | |||
135 | /* | ||
136 | * Stop speculation into the GSEG being unmapped by the previous | ||
137 | * DEALLOCATE. | ||
138 | */ | ||
139 | sync_core(); | ||
140 | return ret; | ||
102 | } | 141 | } |
103 | 142 | ||
104 | int cch_interrupt_sync(struct gru_context_configuration_handle | 143 | int cch_interrupt_sync(struct gru_context_configuration_handle |
@@ -126,17 +165,20 @@ int tgh_invalidate(struct gru_tlb_global_handle *tgh, | |||
126 | return wait_instruction_complete(tgh, tghop_invalidate); | 165 | return wait_instruction_complete(tgh, tghop_invalidate); |
127 | } | 166 | } |
128 | 167 | ||
129 | void tfh_write_only(struct gru_tlb_fault_handle *tfh, | 168 | int tfh_write_only(struct gru_tlb_fault_handle *tfh, |
130 | unsigned long pfn, unsigned long vaddr, | 169 | unsigned long paddr, int gaa, |
131 | int asid, int dirty, int pagesize) | 170 | unsigned long vaddr, int asid, int dirty, |
171 | int pagesize) | ||
132 | { | 172 | { |
133 | tfh->fillasid = asid; | 173 | tfh->fillasid = asid; |
134 | tfh->fillvaddr = vaddr; | 174 | tfh->fillvaddr = vaddr; |
135 | tfh->pfn = pfn; | 175 | tfh->pfn = paddr >> GRU_PADDR_SHIFT; |
176 | tfh->gaa = gaa; | ||
136 | tfh->dirty = dirty; | 177 | tfh->dirty = dirty; |
137 | tfh->pagesize = pagesize; | 178 | tfh->pagesize = pagesize; |
138 | tfh->opc = TFHOP_WRITE_ONLY; | 179 | tfh->opc = TFHOP_WRITE_ONLY; |
139 | start_instruction(tfh); | 180 | start_instruction(tfh); |
181 | return wait_instruction_complete(tfh, tfhop_write_only); | ||
140 | } | 182 | } |
141 | 183 | ||
142 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, | 184 | void tfh_write_restart(struct gru_tlb_fault_handle *tfh, |