Path: blob/master/drivers/misc/sgi-gru/gruhandles.c
15111 views
/*1* GRU KERNEL MCS INSTRUCTIONS2*3* Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#include <linux/kernel.h>21#include "gru.h"22#include "grulib.h"23#include "grutables.h"2425/* 10 sec */26#ifdef CONFIG_IA6427#include <asm/processor.h>28#define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10)29#define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq)30#else31#include <asm/tsc.h>32#define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)33#define CLKS2NSEC(c) ((c) * 1000000 / tsc_khz)34#endif3536/* Extract the status field from a kernel handle */37#define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3)3839struct mcs_op_statistic mcs_op_statistics[mcsop_last];4041static void update_mcs_stats(enum mcs_op op, unsigned long clks)42{43unsigned long nsec;4445nsec = CLKS2NSEC(clks);46atomic_long_inc(&mcs_op_statistics[op].count);47atomic_long_add(nsec, &mcs_op_statistics[op].total);48if (mcs_op_statistics[op].max < nsec)49mcs_op_statistics[op].max = nsec;50}5152static void start_instruction(void *h)53{54unsigned long *w0 = h;5556wmb(); /* setting CMD/STATUS bits must be last */57*w0 = *w0 | 0x20001;58gru_flush_cache(h);59}6061static void report_instruction_timeout(void *h)62{63unsigned long goff = GSEGPOFF((unsigned long)h);64char *id = "???";6566if (TYPE_IS(CCH, goff))67id = "CCH";68else if (TYPE_IS(TGH, goff))69id = "TGH";70else if (TYPE_IS(TFH, goff))71id = "TFH";7273panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id);74}7576static int wait_instruction_complete(void *h, enum mcs_op opc)77{78int status;79unsigned long start_time = get_cycles();8081while (1) {82cpu_relax();83status = GET_MSEG_HANDLE_STATUS(h);84if (status != CCHSTATUS_ACTIVE)85break;86if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {87report_instruction_timeout(h);88start_time = get_cycles();89}90}91if (gru_options & OPT_STATS)92update_mcs_stats(opc, get_cycles() - start_time);93return status;94}9596int cch_allocate(struct gru_context_configuration_handle *cch)97{98int ret;99100cch->opc = CCHOP_ALLOCATE;101start_instruction(cch);102ret = wait_instruction_complete(cch, cchop_allocate);103104/*105* Stop speculation into the GSEG being mapped by the previous ALLOCATE.106* The GSEG memory does not exist until the ALLOCATE completes.107*/108sync_core();109return ret;110}111112int cch_start(struct gru_context_configuration_handle *cch)113{114cch->opc = CCHOP_START;115start_instruction(cch);116return wait_instruction_complete(cch, cchop_start);117}118119int cch_interrupt(struct gru_context_configuration_handle *cch)120{121cch->opc = CCHOP_INTERRUPT;122start_instruction(cch);123return wait_instruction_complete(cch, cchop_interrupt);124}125126int cch_deallocate(struct gru_context_configuration_handle *cch)127{128int ret;129130cch->opc = CCHOP_DEALLOCATE;131start_instruction(cch);132ret = wait_instruction_complete(cch, cchop_deallocate);133134/*135* Stop speculation into the GSEG being unmapped by the previous136* DEALLOCATE.137*/138sync_core();139return ret;140}141142int cch_interrupt_sync(struct gru_context_configuration_handle143*cch)144{145cch->opc = CCHOP_INTERRUPT_SYNC;146start_instruction(cch);147return wait_instruction_complete(cch, cchop_interrupt_sync);148}149150int tgh_invalidate(struct gru_tlb_global_handle *tgh,151unsigned long vaddr, unsigned long vaddrmask,152int asid, int pagesize, int global, int n,153unsigned short ctxbitmap)154{155tgh->vaddr = vaddr;156tgh->asid = asid;157tgh->pagesize = pagesize;158tgh->n = n;159tgh->global = global;160tgh->vaddrmask = vaddrmask;161tgh->ctxbitmap = ctxbitmap;162tgh->opc = TGHOP_TLBINV;163start_instruction(tgh);164return wait_instruction_complete(tgh, tghop_invalidate);165}166167int tfh_write_only(struct gru_tlb_fault_handle *tfh,168unsigned long paddr, int gaa,169unsigned long vaddr, int asid, int dirty,170int pagesize)171{172tfh->fillasid = asid;173tfh->fillvaddr = vaddr;174tfh->pfn = paddr >> GRU_PADDR_SHIFT;175tfh->gaa = gaa;176tfh->dirty = dirty;177tfh->pagesize = pagesize;178tfh->opc = TFHOP_WRITE_ONLY;179start_instruction(tfh);180return wait_instruction_complete(tfh, tfhop_write_only);181}182183void tfh_write_restart(struct gru_tlb_fault_handle *tfh,184unsigned long paddr, int gaa,185unsigned long vaddr, int asid, int dirty,186int pagesize)187{188tfh->fillasid = asid;189tfh->fillvaddr = vaddr;190tfh->pfn = paddr >> GRU_PADDR_SHIFT;191tfh->gaa = gaa;192tfh->dirty = dirty;193tfh->pagesize = pagesize;194tfh->opc = TFHOP_WRITE_RESTART;195start_instruction(tfh);196}197198void tfh_restart(struct gru_tlb_fault_handle *tfh)199{200tfh->opc = TFHOP_RESTART;201start_instruction(tfh);202}203204void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh)205{206tfh->opc = TFHOP_USER_POLLING_MODE;207start_instruction(tfh);208}209210void tfh_exception(struct gru_tlb_fault_handle *tfh)211{212tfh->opc = TFHOP_EXCEPTION;213start_instruction(tfh);214}215216217218