1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * GRU KERNEL MCS INSTRUCTIONS
5 * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
8 #include <linux/kernel.h>
11 #include "grutables.h"
14 #include <linux/sync_core.h>
16 #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
17 #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz)
19 /* Extract the status field from a kernel handle */
20 #define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3)
22 struct mcs_op_statistic mcs_op_statistics[mcsop_last];
24 static void update_mcs_stats(enum mcs_op op, unsigned long clks)
28 nsec = CLKS2NSEC(clks);
29 atomic_long_inc(&mcs_op_statistics[op].count);
30 atomic_long_add(nsec, &mcs_op_statistics[op].total);
31 if (mcs_op_statistics[op].max < nsec)
32 mcs_op_statistics[op].max = nsec;
35 static void start_instruction(void *h)
37 unsigned long *w0 = h;
39 wmb(); /* setting CMD/STATUS bits must be last */
44 static void report_instruction_timeout(void *h)
46 unsigned long goff = GSEGPOFF((unsigned long)h);
49 if (TYPE_IS(CCH, goff))
51 else if (TYPE_IS(TGH, goff))
53 else if (TYPE_IS(TFH, goff))
56 panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id);
59 static int wait_instruction_complete(void *h, enum mcs_op opc)
62 unsigned long start_time = get_cycles();
66 status = GET_MSEG_HANDLE_STATUS(h);
67 if (status != CCHSTATUS_ACTIVE)
69 if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
70 report_instruction_timeout(h);
71 start_time = get_cycles();
74 if (gru_options & OPT_STATS)
75 update_mcs_stats(opc, get_cycles() - start_time);
79 int cch_allocate(struct gru_context_configuration_handle *cch)
83 cch->opc = CCHOP_ALLOCATE;
84 start_instruction(cch);
85 ret = wait_instruction_complete(cch, cchop_allocate);
88 * Stop speculation into the GSEG being mapped by the previous ALLOCATE.
89 * The GSEG memory does not exist until the ALLOCATE completes.
95 int cch_start(struct gru_context_configuration_handle *cch)
97 cch->opc = CCHOP_START;
98 start_instruction(cch);
99 return wait_instruction_complete(cch, cchop_start);
102 int cch_interrupt(struct gru_context_configuration_handle *cch)
104 cch->opc = CCHOP_INTERRUPT;
105 start_instruction(cch);
106 return wait_instruction_complete(cch, cchop_interrupt);
109 int cch_deallocate(struct gru_context_configuration_handle *cch)
113 cch->opc = CCHOP_DEALLOCATE;
114 start_instruction(cch);
115 ret = wait_instruction_complete(cch, cchop_deallocate);
118 * Stop speculation into the GSEG being unmapped by the previous
125 int cch_interrupt_sync(struct gru_context_configuration_handle
128 cch->opc = CCHOP_INTERRUPT_SYNC;
129 start_instruction(cch);
130 return wait_instruction_complete(cch, cchop_interrupt_sync);
133 int tgh_invalidate(struct gru_tlb_global_handle *tgh,
134 unsigned long vaddr, unsigned long vaddrmask,
135 int asid, int pagesize, int global, int n,
136 unsigned short ctxbitmap)
140 tgh->pagesize = pagesize;
142 tgh->global = global;
143 tgh->vaddrmask = vaddrmask;
144 tgh->ctxbitmap = ctxbitmap;
145 tgh->opc = TGHOP_TLBINV;
146 start_instruction(tgh);
147 return wait_instruction_complete(tgh, tghop_invalidate);
150 int tfh_write_only(struct gru_tlb_fault_handle *tfh,
151 unsigned long paddr, int gaa,
152 unsigned long vaddr, int asid, int dirty,
155 tfh->fillasid = asid;
156 tfh->fillvaddr = vaddr;
157 tfh->pfn = paddr >> GRU_PADDR_SHIFT;
160 tfh->pagesize = pagesize;
161 tfh->opc = TFHOP_WRITE_ONLY;
162 start_instruction(tfh);
163 return wait_instruction_complete(tfh, tfhop_write_only);
166 void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
167 unsigned long paddr, int gaa,
168 unsigned long vaddr, int asid, int dirty,
171 tfh->fillasid = asid;
172 tfh->fillvaddr = vaddr;
173 tfh->pfn = paddr >> GRU_PADDR_SHIFT;
176 tfh->pagesize = pagesize;
177 tfh->opc = TFHOP_WRITE_RESTART;
178 start_instruction(tfh);
181 void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)
183 tfh->opc = TFHOP_USER_POLLING_MODE;
184 start_instruction(tfh);
187 void tfh_exception(struct gru_tlb_fault_handle *tfh)
189 tfh->opc = TFHOP_EXCEPTION;
190 start_instruction(tfh);