blob: 806419a6b44c3adc405731a8310c4b366d2f7990 [file] [log] [blame]
Jack Steinera24e5e12009-04-02 16:59:06 -07001/*
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#else
31#include <asm/tsc.h>
32#define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
33#endif
34
35/* Extract the status field from a kernel handle */
36#define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3)
37
Jack Steinere56484d2009-04-02 16:59:06 -070038struct mcs_op_statistic mcs_op_statistics[mcsop_last];
39
40static void update_mcs_stats(enum mcs_op op, unsigned long clks)
41{
42 atomic_long_inc(&mcs_op_statistics[op].count);
43 atomic_long_add(clks, &mcs_op_statistics[op].total);
44 if (mcs_op_statistics[op].max < clks)
45 mcs_op_statistics[op].max = clks;
46}
47
Jack Steinera24e5e12009-04-02 16:59:06 -070048static void start_instruction(void *h)
49{
50 unsigned long *w0 = h;
51
52 wmb(); /* setting CMD bit must be last */
53 *w0 = *w0 | 1;
54 gru_flush_cache(h);
55}
56
Jack Steiner648eb8e2009-12-15 16:48:07 -080057static void report_instruction_timeout(void *h)
58{
59 unsigned long goff = GSEGPOFF((unsigned long)h);
60 char *id = "???";
61
62 if (TYPE_IS(CCH, goff))
63 id = "CCH";
64 else if (TYPE_IS(TGH, goff))
65 id = "TGH";
66 else if (TYPE_IS(TFH, goff))
67 id = "TFH";
68
69 panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id);
70}
71
Jack Steinera24e5e12009-04-02 16:59:06 -070072static int wait_instruction_complete(void *h, enum mcs_op opc)
73{
74 int status;
Jack Steiner836ce672009-06-17 16:28:22 -070075 unsigned long start_time = get_cycles();
Jack Steinera24e5e12009-04-02 16:59:06 -070076
77 while (1) {
78 cpu_relax();
79 status = GET_MSEG_HANDLE_STATUS(h);
80 if (status != CCHSTATUS_ACTIVE)
81 break;
Jack Steiner648eb8e2009-12-15 16:48:07 -080082 if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
83 report_instruction_timeout(h);
84 start_time = get_cycles();
85 }
Jack Steinera24e5e12009-04-02 16:59:06 -070086 }
Jack Steinere56484d2009-04-02 16:59:06 -070087 if (gru_options & OPT_STATS)
88 update_mcs_stats(opc, get_cycles() - start_time);
Jack Steinera24e5e12009-04-02 16:59:06 -070089 return status;
90}
91
Jack Steiner6e910072009-06-17 16:28:21 -070092int cch_allocate(struct gru_context_configuration_handle *cch)
Jack Steinera24e5e12009-04-02 16:59:06 -070093{
Jack Steinera24e5e12009-04-02 16:59:06 -070094 cch->opc = CCHOP_ALLOCATE;
95 start_instruction(cch);
96 return wait_instruction_complete(cch, cchop_allocate);
97}
98
99int cch_start(struct gru_context_configuration_handle *cch)
100{
101 cch->opc = CCHOP_START;
102 start_instruction(cch);
103 return wait_instruction_complete(cch, cchop_start);
104}
105
106int cch_interrupt(struct gru_context_configuration_handle *cch)
107{
108 cch->opc = CCHOP_INTERRUPT;
109 start_instruction(cch);
110 return wait_instruction_complete(cch, cchop_interrupt);
111}
112
113int cch_deallocate(struct gru_context_configuration_handle *cch)
114{
115 cch->opc = CCHOP_DEALLOCATE;
116 start_instruction(cch);
117 return wait_instruction_complete(cch, cchop_deallocate);
118}
119
120int cch_interrupt_sync(struct gru_context_configuration_handle
121 *cch)
122{
123 cch->opc = CCHOP_INTERRUPT_SYNC;
124 start_instruction(cch);
125 return wait_instruction_complete(cch, cchop_interrupt_sync);
126}
127
128int tgh_invalidate(struct gru_tlb_global_handle *tgh,
129 unsigned long vaddr, unsigned long vaddrmask,
130 int asid, int pagesize, int global, int n,
131 unsigned short ctxbitmap)
132{
133 tgh->vaddr = vaddr;
134 tgh->asid = asid;
135 tgh->pagesize = pagesize;
136 tgh->n = n;
137 tgh->global = global;
138 tgh->vaddrmask = vaddrmask;
139 tgh->ctxbitmap = ctxbitmap;
140 tgh->opc = TGHOP_TLBINV;
141 start_instruction(tgh);
142 return wait_instruction_complete(tgh, tghop_invalidate);
143}
144
145void tfh_write_only(struct gru_tlb_fault_handle *tfh,
146 unsigned long pfn, unsigned long vaddr,
147 int asid, int dirty, int pagesize)
148{
149 tfh->fillasid = asid;
150 tfh->fillvaddr = vaddr;
151 tfh->pfn = pfn;
152 tfh->dirty = dirty;
153 tfh->pagesize = pagesize;
154 tfh->opc = TFHOP_WRITE_ONLY;
155 start_instruction(tfh);
156}
157
158void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
159 unsigned long paddr, int gaa,
160 unsigned long vaddr, int asid, int dirty,
161 int pagesize)
162{
163 tfh->fillasid = asid;
164 tfh->fillvaddr = vaddr;
165 tfh->pfn = paddr >> GRU_PADDR_SHIFT;
166 tfh->gaa = gaa;
167 tfh->dirty = dirty;
168 tfh->pagesize = pagesize;
169 tfh->opc = TFHOP_WRITE_RESTART;
170 start_instruction(tfh);
171}
172
173void tfh_restart(struct gru_tlb_fault_handle *tfh)
174{
175 tfh->opc = TFHOP_RESTART;
176 start_instruction(tfh);
177}
178
179void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
180{
181 tfh->opc = TFHOP_USER_POLLING_MODE;
182 start_instruction(tfh);
183}
184
185void tfh_exception(struct gru_tlb_fault_handle *tfh)
186{
187 tfh->opc = TFHOP_EXCEPTION;
188 start_instruction(tfh);
189}
190