11a59d1b8SThomas 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 19*9998a983SRicardo Neri #include <linux/sync_core.h> 20a24e5e1cSJack Steiner #include <asm/tsc.h> 21a24e5e1cSJack Steiner #define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) 22563447d7SJack Steiner #define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz) 23a24e5e1cSJack Steiner #endif 24a24e5e1cSJack Steiner 25a24e5e1cSJack Steiner /* Extract the status field from a kernel handle */ 26a24e5e1cSJack Steiner #define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) 27a24e5e1cSJack Steiner 28e56484daSJack Steiner struct mcs_op_statistic mcs_op_statistics[mcsop_last]; 29e56484daSJack Steiner 30e56484daSJack Steiner static void update_mcs_stats(enum mcs_op op, unsigned long clks) 31e56484daSJack Steiner { 32563447d7SJack Steiner unsigned long nsec; 33563447d7SJack Steiner 34563447d7SJack Steiner nsec = CLKS2NSEC(clks); 35e56484daSJack Steiner atomic_long_inc(&mcs_op_statistics[op].count); 36563447d7SJack Steiner atomic_long_add(nsec, &mcs_op_statistics[op].total); 37563447d7SJack Steiner if (mcs_op_statistics[op].max < nsec) 38563447d7SJack Steiner mcs_op_statistics[op].max = nsec; 39e56484daSJack Steiner } 40e56484daSJack Steiner 41a24e5e1cSJack Steiner static void start_instruction(void *h) 42a24e5e1cSJack Steiner { 43a24e5e1cSJack Steiner unsigned long *w0 = h; 44a24e5e1cSJack Steiner 4557ebb034SJack Steiner wmb(); /* setting CMD/STATUS bits must be last */ 4657ebb034SJack Steiner *w0 = *w0 | 0x20001; 47a24e5e1cSJack Steiner gru_flush_cache(h); 48a24e5e1cSJack Steiner } 49a24e5e1cSJack Steiner 50648eb8e5SJack Steiner static void report_instruction_timeout(void *h) 51648eb8e5SJack Steiner { 52648eb8e5SJack Steiner unsigned long goff = GSEGPOFF((unsigned long)h); 53648eb8e5SJack Steiner char *id = "???"; 54648eb8e5SJack Steiner 55648eb8e5SJack Steiner if (TYPE_IS(CCH, goff)) 56648eb8e5SJack Steiner id = "CCH"; 57648eb8e5SJack Steiner else if (TYPE_IS(TGH, goff)) 58648eb8e5SJack Steiner id = "TGH"; 59648eb8e5SJack Steiner else if (TYPE_IS(TFH, goff)) 60648eb8e5SJack Steiner id = "TFH"; 61648eb8e5SJack Steiner 62648eb8e5SJack Steiner panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id); 63648eb8e5SJack Steiner } 64648eb8e5SJack Steiner 65a24e5e1cSJack Steiner static int wait_instruction_complete(void *h, enum mcs_op opc) 66a24e5e1cSJack Steiner { 67a24e5e1cSJack Steiner int status; 68836ce679SJack Steiner unsigned long start_time = get_cycles(); 69a24e5e1cSJack Steiner 70a24e5e1cSJack Steiner while (1) { 71a24e5e1cSJack Steiner cpu_relax(); 72a24e5e1cSJack Steiner status = GET_MSEG_HANDLE_STATUS(h); 73a24e5e1cSJack Steiner if (status != CCHSTATUS_ACTIVE) 74a24e5e1cSJack Steiner break; 75648eb8e5SJack Steiner if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) { 76648eb8e5SJack Steiner report_instruction_timeout(h); 77648eb8e5SJack Steiner start_time = get_cycles(); 78648eb8e5SJack Steiner } 79a24e5e1cSJack Steiner } 80e56484daSJack Steiner if (gru_options & OPT_STATS) 81e56484daSJack Steiner update_mcs_stats(opc, get_cycles() - start_time); 82a24e5e1cSJack Steiner return status; 83a24e5e1cSJack Steiner } 84a24e5e1cSJack Steiner 856e910074SJack Steiner int cch_allocate(struct gru_context_configuration_handle *cch) 86a24e5e1cSJack Steiner { 8767bf04a5SJack Steiner int ret; 8867bf04a5SJack Steiner 89a24e5e1cSJack Steiner cch->opc = CCHOP_ALLOCATE; 90a24e5e1cSJack Steiner start_instruction(cch); 9167bf04a5SJack Steiner ret = wait_instruction_complete(cch, cchop_allocate); 9267bf04a5SJack Steiner 9367bf04a5SJack Steiner /* 9467bf04a5SJack Steiner * Stop speculation into the GSEG being mapped by the previous ALLOCATE. 9567bf04a5SJack Steiner * The GSEG memory does not exist until the ALLOCATE completes. 9667bf04a5SJack Steiner */ 9767bf04a5SJack Steiner sync_core(); 9867bf04a5SJack Steiner return ret; 99a24e5e1cSJack Steiner } 100a24e5e1cSJack Steiner 101a24e5e1cSJack Steiner int cch_start(struct gru_context_configuration_handle *cch) 102a24e5e1cSJack Steiner { 103a24e5e1cSJack Steiner cch->opc = CCHOP_START; 104a24e5e1cSJack Steiner start_instruction(cch); 105a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_start); 106a24e5e1cSJack Steiner } 107a24e5e1cSJack Steiner 108a24e5e1cSJack Steiner int cch_interrupt(struct gru_context_configuration_handle *cch) 109a24e5e1cSJack Steiner { 110a24e5e1cSJack Steiner cch->opc = CCHOP_INTERRUPT; 111a24e5e1cSJack Steiner start_instruction(cch); 112a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_interrupt); 113a24e5e1cSJack Steiner } 114a24e5e1cSJack Steiner 115a24e5e1cSJack Steiner int cch_deallocate(struct gru_context_configuration_handle *cch) 116a24e5e1cSJack Steiner { 11767bf04a5SJack Steiner int ret; 11867bf04a5SJack Steiner 119a24e5e1cSJack Steiner cch->opc = CCHOP_DEALLOCATE; 120a24e5e1cSJack Steiner start_instruction(cch); 12167bf04a5SJack Steiner ret = wait_instruction_complete(cch, cchop_deallocate); 12267bf04a5SJack Steiner 12367bf04a5SJack Steiner /* 12467bf04a5SJack Steiner * Stop speculation into the GSEG being unmapped by the previous 12567bf04a5SJack Steiner * DEALLOCATE. 12667bf04a5SJack Steiner */ 12767bf04a5SJack Steiner sync_core(); 12867bf04a5SJack Steiner return ret; 129a24e5e1cSJack Steiner } 130a24e5e1cSJack Steiner 131a24e5e1cSJack Steiner int cch_interrupt_sync(struct gru_context_configuration_handle 132a24e5e1cSJack Steiner *cch) 133a24e5e1cSJack Steiner { 134a24e5e1cSJack Steiner cch->opc = CCHOP_INTERRUPT_SYNC; 135a24e5e1cSJack Steiner start_instruction(cch); 136a24e5e1cSJack Steiner return wait_instruction_complete(cch, cchop_interrupt_sync); 137a24e5e1cSJack Steiner } 138a24e5e1cSJack Steiner 139a24e5e1cSJack Steiner int tgh_invalidate(struct gru_tlb_global_handle *tgh, 140a24e5e1cSJack Steiner unsigned long vaddr, unsigned long vaddrmask, 141a24e5e1cSJack Steiner int asid, int pagesize, int global, int n, 142a24e5e1cSJack Steiner unsigned short ctxbitmap) 143a24e5e1cSJack Steiner { 144a24e5e1cSJack Steiner tgh->vaddr = vaddr; 145a24e5e1cSJack Steiner tgh->asid = asid; 146a24e5e1cSJack Steiner tgh->pagesize = pagesize; 147a24e5e1cSJack Steiner tgh->n = n; 148a24e5e1cSJack Steiner tgh->global = global; 149a24e5e1cSJack Steiner tgh->vaddrmask = vaddrmask; 150a24e5e1cSJack Steiner tgh->ctxbitmap = ctxbitmap; 151a24e5e1cSJack Steiner tgh->opc = TGHOP_TLBINV; 152a24e5e1cSJack Steiner start_instruction(tgh); 153a24e5e1cSJack Steiner return wait_instruction_complete(tgh, tghop_invalidate); 154a24e5e1cSJack Steiner } 155a24e5e1cSJack Steiner 156c550222fSJack Steiner int tfh_write_only(struct gru_tlb_fault_handle *tfh, 157c550222fSJack Steiner unsigned long paddr, int gaa, 158c550222fSJack Steiner unsigned long vaddr, int asid, int dirty, 159c550222fSJack Steiner int pagesize) 160a24e5e1cSJack Steiner { 161a24e5e1cSJack Steiner tfh->fillasid = asid; 162a24e5e1cSJack Steiner tfh->fillvaddr = vaddr; 163c550222fSJack Steiner tfh->pfn = paddr >> GRU_PADDR_SHIFT; 164c550222fSJack Steiner tfh->gaa = gaa; 165a24e5e1cSJack Steiner tfh->dirty = dirty; 166a24e5e1cSJack Steiner tfh->pagesize = pagesize; 167a24e5e1cSJack Steiner tfh->opc = TFHOP_WRITE_ONLY; 168a24e5e1cSJack Steiner start_instruction(tfh); 169c550222fSJack Steiner return wait_instruction_complete(tfh, tfhop_write_only); 170a24e5e1cSJack Steiner } 171a24e5e1cSJack Steiner 172a24e5e1cSJack Steiner void tfh_write_restart(struct gru_tlb_fault_handle *tfh, 173a24e5e1cSJack Steiner unsigned long paddr, int gaa, 174a24e5e1cSJack Steiner unsigned long vaddr, int asid, int dirty, 175a24e5e1cSJack Steiner int pagesize) 176a24e5e1cSJack Steiner { 177a24e5e1cSJack Steiner tfh->fillasid = asid; 178a24e5e1cSJack Steiner tfh->fillvaddr = vaddr; 179a24e5e1cSJack Steiner tfh->pfn = paddr >> GRU_PADDR_SHIFT; 180a24e5e1cSJack Steiner tfh->gaa = gaa; 181a24e5e1cSJack Steiner tfh->dirty = dirty; 182a24e5e1cSJack Steiner tfh->pagesize = pagesize; 183a24e5e1cSJack Steiner tfh->opc = TFHOP_WRITE_RESTART; 184a24e5e1cSJack Steiner start_instruction(tfh); 185a24e5e1cSJack Steiner } 186a24e5e1cSJack Steiner 187a24e5e1cSJack Steiner void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) 188a24e5e1cSJack Steiner { 189a24e5e1cSJack Steiner tfh->opc = TFHOP_USER_POLLING_MODE; 190a24e5e1cSJack Steiner start_instruction(tfh); 191a24e5e1cSJack Steiner } 192a24e5e1cSJack Steiner 193a24e5e1cSJack Steiner void tfh_exception(struct gru_tlb_fault_handle *tfh) 194a24e5e1cSJack Steiner { 195a24e5e1cSJack Steiner tfh->opc = TFHOP_EXCEPTION; 196a24e5e1cSJack Steiner start_instruction(tfh); 197a24e5e1cSJack Steiner } 198a24e5e1cSJack Steiner 199