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 cycles_t 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\n", h); 69 } 70 if (gru_options & OPT_STATS) 71 update_mcs_stats(opc, get_cycles() - start_time); 72 return status; 73 } 74 75 int cch_allocate(struct gru_context_configuration_handle *cch, 76 int asidval, int sizeavail, unsigned long cbrmap, 77 unsigned long dsrmap) 78 { 79 int i; 80 81 for (i = 0; i < 8; i++) { 82 cch->asid[i] = (asidval++); 83 cch->sizeavail[i] = sizeavail; 84 } 85 cch->dsr_allocation_map = dsrmap; 86 cch->cbr_allocation_map = cbrmap; 87 cch->opc = CCHOP_ALLOCATE; 88 start_instruction(cch); 89 return wait_instruction_complete(cch, cchop_allocate); 90 } 91 92 int cch_start(struct gru_context_configuration_handle *cch) 93 { 94 cch->opc = CCHOP_START; 95 start_instruction(cch); 96 return wait_instruction_complete(cch, cchop_start); 97 } 98 99 int cch_interrupt(struct gru_context_configuration_handle *cch) 100 { 101 cch->opc = CCHOP_INTERRUPT; 102 start_instruction(cch); 103 return wait_instruction_complete(cch, cchop_interrupt); 104 } 105 106 int cch_deallocate(struct gru_context_configuration_handle *cch) 107 { 108 cch->opc = CCHOP_DEALLOCATE; 109 start_instruction(cch); 110 return wait_instruction_complete(cch, cchop_deallocate); 111 } 112 113 int cch_interrupt_sync(struct gru_context_configuration_handle 114 *cch) 115 { 116 cch->opc = CCHOP_INTERRUPT_SYNC; 117 start_instruction(cch); 118 return wait_instruction_complete(cch, cchop_interrupt_sync); 119 } 120 121 int tgh_invalidate(struct gru_tlb_global_handle *tgh, 122 unsigned long vaddr, unsigned long vaddrmask, 123 int asid, int pagesize, int global, int n, 124 unsigned short ctxbitmap) 125 { 126 tgh->vaddr = vaddr; 127 tgh->asid = asid; 128 tgh->pagesize = pagesize; 129 tgh->n = n; 130 tgh->global = global; 131 tgh->vaddrmask = vaddrmask; 132 tgh->ctxbitmap = ctxbitmap; 133 tgh->opc = TGHOP_TLBINV; 134 start_instruction(tgh); 135 return wait_instruction_complete(tgh, tghop_invalidate); 136 } 137 138 void tfh_write_only(struct gru_tlb_fault_handle *tfh, 139 unsigned long pfn, unsigned long vaddr, 140 int asid, int dirty, int pagesize) 141 { 142 tfh->fillasid = asid; 143 tfh->fillvaddr = vaddr; 144 tfh->pfn = pfn; 145 tfh->dirty = dirty; 146 tfh->pagesize = pagesize; 147 tfh->opc = TFHOP_WRITE_ONLY; 148 start_instruction(tfh); 149 } 150 151 void tfh_write_restart(struct gru_tlb_fault_handle *tfh, 152 unsigned long paddr, int gaa, 153 unsigned long vaddr, int asid, int dirty, 154 int pagesize) 155 { 156 tfh->fillasid = asid; 157 tfh->fillvaddr = vaddr; 158 tfh->pfn = paddr >> GRU_PADDR_SHIFT; 159 tfh->gaa = gaa; 160 tfh->dirty = dirty; 161 tfh->pagesize = pagesize; 162 tfh->opc = TFHOP_WRITE_RESTART; 163 start_instruction(tfh); 164 } 165 166 void tfh_restart(struct gru_tlb_fault_handle *tfh) 167 { 168 tfh->opc = TFHOP_RESTART; 169 start_instruction(tfh); 170 } 171 172 void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) 173 { 174 tfh->opc = TFHOP_USER_POLLING_MODE; 175 start_instruction(tfh); 176 } 177 178 void tfh_exception(struct gru_tlb_fault_handle *tfh) 179 { 180 tfh->opc = TFHOP_EXCEPTION; 181 start_instruction(tfh); 182 } 183 184