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 #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 38 struct mcs_op_statistic mcs_op_statistics[mcsop_last]; 39 40 static 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 48 static 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 57 static int wait_instruction_complete(void *h, enum mcs_op opc) 58 { 59 int status; 60 unsigned long start_time = get_cycles(); 61 62 while (1) { 63 cpu_relax(); 64 status = GET_MSEG_HANDLE_STATUS(h); 65 if (status != CCHSTATUS_ACTIVE) 66 break; 67 if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) 68 panic("GRU %p is malfunctioning: start %ld, end %ld\n", 69 h, start_time, (unsigned long)get_cycles()); 70 } 71 if (gru_options & OPT_STATS) 72 update_mcs_stats(opc, get_cycles() - start_time); 73 return status; 74 } 75 76 int cch_allocate(struct gru_context_configuration_handle *cch) 77 { 78 cch->opc = CCHOP_ALLOCATE; 79 start_instruction(cch); 80 return wait_instruction_complete(cch, cchop_allocate); 81 } 82 83 int cch_start(struct gru_context_configuration_handle *cch) 84 { 85 cch->opc = CCHOP_START; 86 start_instruction(cch); 87 return wait_instruction_complete(cch, cchop_start); 88 } 89 90 int cch_interrupt(struct gru_context_configuration_handle *cch) 91 { 92 cch->opc = CCHOP_INTERRUPT; 93 start_instruction(cch); 94 return wait_instruction_complete(cch, cchop_interrupt); 95 } 96 97 int cch_deallocate(struct gru_context_configuration_handle *cch) 98 { 99 cch->opc = CCHOP_DEALLOCATE; 100 start_instruction(cch); 101 return wait_instruction_complete(cch, cchop_deallocate); 102 } 103 104 int cch_interrupt_sync(struct gru_context_configuration_handle 105 *cch) 106 { 107 cch->opc = CCHOP_INTERRUPT_SYNC; 108 start_instruction(cch); 109 return wait_instruction_complete(cch, cchop_interrupt_sync); 110 } 111 112 int tgh_invalidate(struct gru_tlb_global_handle *tgh, 113 unsigned long vaddr, unsigned long vaddrmask, 114 int asid, int pagesize, int global, int n, 115 unsigned short ctxbitmap) 116 { 117 tgh->vaddr = vaddr; 118 tgh->asid = asid; 119 tgh->pagesize = pagesize; 120 tgh->n = n; 121 tgh->global = global; 122 tgh->vaddrmask = vaddrmask; 123 tgh->ctxbitmap = ctxbitmap; 124 tgh->opc = TGHOP_TLBINV; 125 start_instruction(tgh); 126 return wait_instruction_complete(tgh, tghop_invalidate); 127 } 128 129 void tfh_write_only(struct gru_tlb_fault_handle *tfh, 130 unsigned long pfn, unsigned long vaddr, 131 int asid, int dirty, int pagesize) 132 { 133 tfh->fillasid = asid; 134 tfh->fillvaddr = vaddr; 135 tfh->pfn = pfn; 136 tfh->dirty = dirty; 137 tfh->pagesize = pagesize; 138 tfh->opc = TFHOP_WRITE_ONLY; 139 start_instruction(tfh); 140 } 141 142 void tfh_write_restart(struct gru_tlb_fault_handle *tfh, 143 unsigned long paddr, int gaa, 144 unsigned long vaddr, int asid, int dirty, 145 int pagesize) 146 { 147 tfh->fillasid = asid; 148 tfh->fillvaddr = vaddr; 149 tfh->pfn = paddr >> GRU_PADDR_SHIFT; 150 tfh->gaa = gaa; 151 tfh->dirty = dirty; 152 tfh->pagesize = pagesize; 153 tfh->opc = TFHOP_WRITE_RESTART; 154 start_instruction(tfh); 155 } 156 157 void tfh_restart(struct gru_tlb_fault_handle *tfh) 158 { 159 tfh->opc = TFHOP_RESTART; 160 start_instruction(tfh); 161 } 162 163 void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) 164 { 165 tfh->opc = TFHOP_USER_POLLING_MODE; 166 start_instruction(tfh); 167 } 168 169 void tfh_exception(struct gru_tlb_fault_handle *tfh) 170 { 171 tfh->opc = TFHOP_EXCEPTION; 172 start_instruction(tfh); 173 } 174 175