1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a24e5e1cSJack Steiner /* 3a24e5e1cSJack Steiner * GRU KERNEL MCS INSTRUCTIONS 4a24e5e1cSJack Steiner * 5a24e5e1cSJack Steiner * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. 6a24e5e1cSJack Steiner */ 7a24e5e1cSJack Steiner 8a24e5e1cSJack Steiner #include <linux/kernel.h> 9a24e5e1cSJack Steiner #include "gru.h" 10a24e5e1cSJack Steiner #include "grulib.h" 11a24e5e1cSJack Steiner #include "grutables.h" 12a24e5e1cSJack Steiner 13a24e5e1cSJack Steiner /* 10 sec */ 14a24e5e1cSJack Steiner #ifdef CONFIG_IA64 15a24e5e1cSJack Steiner #include <asm/processor.h> 16a24e5e1cSJack Steiner #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) 17563447d7SJack Steiner #define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq) 18a24e5e1cSJack Steiner #else 19a24e5e1cSJack Steiner #include <asm/tsc.h> 20a24e5e1cSJack Steiner #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) 21563447d7SJack Steiner #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz) 22a24e5e1cSJack Steiner #endif 23a24e5e1cSJack Steiner 24a24e5e1cSJack Steiner /* Extract the status field from a kernel handle */ 25a24e5e1cSJack Steiner #define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) 26a24e5e1cSJack Steiner 27e56484daSJack Steiner struct mcs_op_statistic mcs_op_statistics[mcsop_last]; 28e56484daSJack Steiner 29e56484daSJack Steiner static void update_mcs_stats(enum mcs_op op, unsigned long clks) 30e56484daSJack Steiner { 31563447d7SJack Steiner unsigned long nsec; 32563447d7SJack Steiner 33563447d7SJack Steiner nsec = CLKS2NSEC(clks); 34e56484daSJack Steiner atomic_long_inc(&mcs_op_statistics[op].count); 35563447d7SJack Steiner atomic_long_add(nsec, &mcs_op_statistics[op].total); 36563447d7SJack Steiner if (mcs_op_statistics[op].max < nsec) 37563447d7SJack Steiner mcs_op_statistics[op].max = nsec; 38e56484daSJack Steiner } 39e56484daSJack Steiner 40a24e5e1cSJack Steiner static void start_instruction(void *h) 41a24e5e1cSJack Steiner { 42a24e5e1cSJack Steiner unsigned long *w0 = h; 43a24e5e1cSJack Steiner 4457ebb034SJack Steiner wmb(); /* setting CMD/STATUS bits must be last */ 4557ebb034SJack Steiner *w0 = *w0 | 0x20001; 46a24e5e1cSJack Steiner gru_flush_cache(h); 47a24e5e1cSJack Steiner } 48a24e5e1cSJack Steiner 49648eb8e5SJack Steiner static void report_instruction_timeout(void *h) 50648eb8e5SJack Steiner { 51648eb8e5SJack Steiner unsigned long goff = GSEGPOFF((unsigned long)h); 52648eb8e5SJack Steiner char *id = "???"; 53648eb8e5SJack Steiner 54648eb8e5SJack Steiner if (TYPE_IS(CCH, goff)) 55648eb8e5SJack Steiner id = "CCH"; 56648eb8e5SJack Steiner else if (TYPE_IS(TGH, goff)) 57648eb8e5SJack Steiner id = "TGH"; 58648eb8e5SJack Steiner else if (TYPE_IS(TFH, goff)) 59648eb8e5SJack Steiner id = "TFH"; 60648eb8e5SJack Steiner 61648eb8e5SJack Steiner panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id); 62648eb8e5SJack Steiner } 63648eb8e5SJack Steiner 64a24e5e1cSJack Steiner static int wait_instruction_complete(void *h, enum mcs_op opc) 65a24e5e1cSJack Steiner { 66a24e5e1cSJack Steiner int status; 67836ce679SJack Steiner unsigned long start_time = get_cycles(); 68a24e5e1cSJack Steiner 69a24e5e1cSJack Steiner while (1) { 70a24e5e1cSJack Steiner cpu_relax(); 71a24e5e1cSJack Steiner status = GET_MSEG_HANDLE_STATUS(h); 72a24e5e1cSJack Steiner if (status != CCHSTATUS_ACTIVE) 73a24e5e1cSJack Steiner break; 74648eb8e5SJack Steiner if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) { 75648eb8e5SJack Steiner report_instruction_timeout(h); 76648eb8e5SJack Steiner start_time = get_cycles(); 77648eb8e5SJack Steiner } 78a24e5e1cSJack Steiner } 79e56484daSJack Steiner if (gru_options & OPT_STATS) 80e56484daSJack Steiner update_mcs_stats(opc, get_cycles() - start_time); 81a24e5e1cSJack Steiner return status; 82a24e5e1cSJack Steiner } 83a24e5e1cSJack Steiner 846e910074SJack Steiner int cch_allocate(struct gru_context_configuration_handle *cch) 85a24e5e1cSJack Steiner { 8667bf04a5SJack Steiner int ret; 8767bf04a5SJack Steiner 88a24e5e1cSJack Steiner cch->opc = CCHOP_ALLOCATE; 89a24e5e1cSJack Steiner start_instruction(cch); 9067bf04a5SJack Steiner ret = wait_instruction_complete(cch, cchop_allocate); 9167bf04a5SJack Steiner 9267bf04a5SJack Steiner /* 9367bf04a5SJack Steiner * Stop speculation into the GSEG being mapped by the previous ALLOCATE. 9467bf04a5SJack Steiner * The GSEG memory does not exist until the ALLOCATE completes. 9567bf04a5SJack Steiner */ 9667bf04a5SJack Steiner sync_core(); 9767bf04a5SJack Steiner return ret; 98a24e5e1cSJack Steiner } 99a24e5e1cSJack Steiner 100a24e5e1cSJack Steiner int cch_start(struct gru_context_configuration_handle *cch) 101a24e5e1cSJack Steiner { 102a24e5e1cSJack Steiner cch->opc = CCHOP_START; 103a24e5e1cSJack Steiner start_instruction(cch); 104a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_start); 105a24e5e1cSJack Steiner } 106a24e5e1cSJack Steiner 107a24e5e1cSJack Steiner int cch_interrupt(struct gru_context_configuration_handle *cch) 108a24e5e1cSJack Steiner { 109a24e5e1cSJack Steiner cch->opc = CCHOP_INTERRUPT; 110a24e5e1cSJack Steiner start_instruction(cch); 111a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_interrupt); 112a24e5e1cSJack Steiner } 113a24e5e1cSJack Steiner 114a24e5e1cSJack Steiner int cch_deallocate(struct gru_context_configuration_handle *cch) 115a24e5e1cSJack Steiner { 11667bf04a5SJack Steiner int ret; 11767bf04a5SJack Steiner 118a24e5e1cSJack Steiner cch->opc = CCHOP_DEALLOCATE; 119a24e5e1cSJack Steiner start_instruction(cch); 12067bf04a5SJack Steiner ret = wait_instruction_complete(cch, cchop_deallocate); 12167bf04a5SJack Steiner 12267bf04a5SJack Steiner /* 12367bf04a5SJack Steiner * Stop speculation into the GSEG being unmapped by the previous 12467bf04a5SJack Steiner * DEALLOCATE. 12567bf04a5SJack Steiner */ 12667bf04a5SJack Steiner sync_core(); 12767bf04a5SJack Steiner return ret; 128a24e5e1cSJack Steiner } 129a24e5e1cSJack Steiner 130a24e5e1cSJack Steiner int cch_interrupt_sync(struct gru_context_configuration_handle 131a24e5e1cSJack Steiner *cch) 132a24e5e1cSJack Steiner { 133a24e5e1cSJack Steiner cch->opc = CCHOP_INTERRUPT_SYNC; 134a24e5e1cSJack Steiner start_instruction(cch); 135a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_interrupt_sync); 136a24e5e1cSJack Steiner } 137a24e5e1cSJack Steiner 138a24e5e1cSJack Steiner int tgh_invalidate(struct gru_tlb_global_handle *tgh, 139a24e5e1cSJack Steiner unsigned long vaddr, unsigned long vaddrmask, 140a24e5e1cSJack Steiner int asid, int pagesize, int global, int n, 141a24e5e1cSJack Steiner unsigned short ctxbitmap) 142a24e5e1cSJack Steiner { 143a24e5e1cSJack Steiner tgh->vaddr = vaddr; 144a24e5e1cSJack Steiner tgh->asid = asid; 145a24e5e1cSJack Steiner tgh->pagesize = pagesize; 146a24e5e1cSJack Steiner tgh->n = n; 147a24e5e1cSJack Steiner tgh->global = global; 148a24e5e1cSJack Steiner tgh->vaddrmask = vaddrmask; 149a24e5e1cSJack Steiner tgh->ctxbitmap = ctxbitmap; 150a24e5e1cSJack Steiner tgh->opc = TGHOP_TLBINV; 151a24e5e1cSJack Steiner start_instruction(tgh); 152a24e5e1cSJack Steiner return wait_instruction_complete(tgh, tghop_invalidate); 153a24e5e1cSJack Steiner } 154a24e5e1cSJack Steiner 155c550222fSJack Steiner int tfh_write_only(struct gru_tlb_fault_handle *tfh, 156c550222fSJack Steiner unsigned long paddr, int gaa, 157c550222fSJack Steiner unsigned long vaddr, int asid, int dirty, 158c550222fSJack Steiner int pagesize) 159a24e5e1cSJack Steiner { 160a24e5e1cSJack Steiner tfh->fillasid = asid; 161a24e5e1cSJack Steiner tfh->fillvaddr = vaddr; 162c550222fSJack Steiner tfh->pfn = paddr >> GRU_PADDR_SHIFT; 163c550222fSJack Steiner tfh->gaa = gaa; 164a24e5e1cSJack Steiner tfh->dirty = dirty; 165a24e5e1cSJack Steiner tfh->pagesize = pagesize; 166a24e5e1cSJack Steiner tfh->opc = TFHOP_WRITE_ONLY; 167a24e5e1cSJack Steiner start_instruction(tfh); 168c550222fSJack Steiner return wait_instruction_complete(tfh, tfhop_write_only); 169a24e5e1cSJack Steiner } 170a24e5e1cSJack Steiner 171a24e5e1cSJack Steiner void tfh_write_restart(struct gru_tlb_fault_handle *tfh, 172a24e5e1cSJack Steiner unsigned long paddr, int gaa, 173a24e5e1cSJack Steiner unsigned long vaddr, int asid, int dirty, 174a24e5e1cSJack Steiner int pagesize) 175a24e5e1cSJack Steiner { 176a24e5e1cSJack Steiner tfh->fillasid = asid; 177a24e5e1cSJack Steiner tfh->fillvaddr = vaddr; 178a24e5e1cSJack Steiner tfh->pfn = paddr >> GRU_PADDR_SHIFT; 179a24e5e1cSJack Steiner tfh->gaa = gaa; 180a24e5e1cSJack Steiner tfh->dirty = dirty; 181a24e5e1cSJack Steiner tfh->pagesize = pagesize; 182a24e5e1cSJack Steiner tfh->opc = TFHOP_WRITE_RESTART; 183a24e5e1cSJack Steiner start_instruction(tfh); 184a24e5e1cSJack Steiner } 185a24e5e1cSJack Steiner 186a24e5e1cSJack Steiner void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) 187a24e5e1cSJack Steiner { 188a24e5e1cSJack Steiner tfh->opc = TFHOP_USER_POLLING_MODE; 189a24e5e1cSJack Steiner start_instruction(tfh); 190a24e5e1cSJack Steiner } 191a24e5e1cSJack Steiner 192a24e5e1cSJack Steiner void tfh_exception(struct gru_tlb_fault_handle *tfh) 193a24e5e1cSJack Steiner { 194a24e5e1cSJack Steiner tfh->opc = TFHOP_EXCEPTION; 195a24e5e1cSJack Steiner start_instruction(tfh); 196a24e5e1cSJack Steiner } 197a24e5e1cSJack Steiner 198