Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gruhandles.c
Go to the documentation of this file.
1 /*
2  * GRU KERNEL MCS INSTRUCTIONS
3  *
4  * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 #include <linux/kernel.h>
22 #include "gru.h"
23 #include "grulib.h"
24 #include "grutables.h"
25 
26 /* 10 sec */
27 #ifdef CONFIG_IA64
28 #include <asm/processor.h>
29 #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10)
30 #define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq)
31 #else
32 #include <asm/tsc.h>
33 #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
34 #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz)
35 #endif
36 
37 /* Extract the status field from a kernel handle */
38 #define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3)
39 
41 
42 static void update_mcs_stats(enum mcs_op op, unsigned long clks)
43 {
44  unsigned long nsec;
45 
46  nsec = CLKS2NSEC(clks);
47  atomic_long_inc(&mcs_op_statistics[op].count);
48  atomic_long_add(nsec, &mcs_op_statistics[op].total);
49  if (mcs_op_statistics[op].max < nsec)
50  mcs_op_statistics[op].max = nsec;
51 }
52 
53 static void start_instruction(void *h)
54 {
55  unsigned long *w0 = h;
56 
57  wmb(); /* setting CMD/STATUS bits must be last */
58  *w0 = *w0 | 0x20001;
59  gru_flush_cache(h);
60 }
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 
77 static int wait_instruction_complete(void *h, enum mcs_op opc)
78 {
79  int status;
80  unsigned long start_time = get_cycles();
81 
82  while (1) {
83  cpu_relax();
84  status = GET_MSEG_HANDLE_STATUS(h);
85  if (status != CCHSTATUS_ACTIVE)
86  break;
87  if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
88  report_instruction_timeout(h);
89  start_time = get_cycles();
90  }
91  }
92  if (gru_options & OPT_STATS)
93  update_mcs_stats(opc, get_cycles() - start_time);
94  return status;
95 }
96 
98 {
99  int ret;
100 
101  cch->opc = CCHOP_ALLOCATE;
102  start_instruction(cch);
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;
111 }
112 
114 {
115  cch->opc = CCHOP_START;
116  start_instruction(cch);
117  return wait_instruction_complete(cch, cchop_start);
118 }
119 
121 {
122  cch->opc = CCHOP_INTERRUPT;
123  start_instruction(cch);
124  return wait_instruction_complete(cch, cchop_interrupt);
125 }
126 
128 {
129  int ret;
130 
131  cch->opc = CCHOP_DEALLOCATE;
132  start_instruction(cch);
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;
141 }
142 
144  *cch)
145 {
146  cch->opc = CCHOP_INTERRUPT_SYNC;
147  start_instruction(cch);
148  return wait_instruction_complete(cch, cchop_interrupt_sync);
149 }
150 
152  unsigned long vaddr, unsigned long vaddrmask,
153  int asid, int pagesize, int global, int n,
154  unsigned short ctxbitmap)
155 {
156  tgh->vaddr = vaddr;
157  tgh->asid = asid;
158  tgh->pagesize = pagesize;
159  tgh->n = n;
160  tgh->global = global;
161  tgh->vaddrmask = vaddrmask;
162  tgh->ctxbitmap = ctxbitmap;
163  tgh->opc = TGHOP_TLBINV;
164  start_instruction(tgh);
165  return wait_instruction_complete(tgh, tghop_invalidate);
166 }
167 
169  unsigned long paddr, int gaa,
170  unsigned long vaddr, int asid, int dirty,
171  int pagesize)
172 {
173  tfh->fillasid = asid;
174  tfh->fillvaddr = vaddr;
175  tfh->pfn = paddr >> GRU_PADDR_SHIFT;
176  tfh->gaa = gaa;
177  tfh->dirty = dirty;
178  tfh->pagesize = pagesize;
179  tfh->opc = TFHOP_WRITE_ONLY;
180  start_instruction(tfh);
181  return wait_instruction_complete(tfh, tfhop_write_only);
182 }
183 
185  unsigned long paddr, int gaa,
186  unsigned long vaddr, int asid, int dirty,
187  int pagesize)
188 {
189  tfh->fillasid = asid;
190  tfh->fillvaddr = vaddr;
191  tfh->pfn = paddr >> GRU_PADDR_SHIFT;
192  tfh->gaa = gaa;
193  tfh->dirty = dirty;
194  tfh->pagesize = pagesize;
195  tfh->opc = TFHOP_WRITE_RESTART;
196  start_instruction(tfh);
197 }
198 
200 {
201  tfh->opc = TFHOP_RESTART;
202  start_instruction(tfh);
203 }
204 
206 {
208  start_instruction(tfh);
209 }
210 
212 {
213  tfh->opc = TFHOP_EXCEPTION;
214  start_instruction(tfh);
215 }
216