linux/drivers/misc/sgi-xp/xp_sn2.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
   7 */
   8
   9/*
  10 * Cross Partition (XP) sn2-based functions.
  11 *
  12 *      Architecture specific implementation of common functions.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/device.h>
  17#include <asm/sn/bte.h>
  18#include <asm/sn/sn_sal.h>
  19#include "xp.h"
  20
  21/*
  22 * The export of xp_nofault_PIOR needs to happen here since it is defined
  23 * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is
  24 * defined here.
  25 */
  26EXPORT_SYMBOL_GPL(xp_nofault_PIOR);
  27
  28u64 xp_nofault_PIOR_target;
  29EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target);
  30
  31/*
  32 * Register a nofault code region which performs a cross-partition PIO read.
  33 * If the PIO read times out, the MCA handler will consume the error and
  34 * return to a kernel-provided instruction to indicate an error. This PIO read
  35 * exists because it is guaranteed to timeout if the destination is down
  36 * (amo operations do not timeout on at least some CPUs on Shubs <= v1.2,
  37 * which unfortunately we have to work around).
  38 */
  39static enum xp_retval
  40xp_register_nofault_code_sn2(void)
  41{
  42        int ret;
  43        u64 func_addr;
  44        u64 err_func_addr;
  45
  46        func_addr = *(u64 *)xp_nofault_PIOR;
  47        err_func_addr = *(u64 *)xp_error_PIOR;
  48        ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr,
  49                                       1, 1);
  50        if (ret != 0) {
  51                dev_err(xp, "can't register nofault code, error=%d\n", ret);
  52                return xpSalError;
  53        }
  54        /*
  55         * Setup the nofault PIO read target. (There is no special reason why
  56         * SH_IPI_ACCESS was selected.)
  57         */
  58        if (is_shub1())
  59                xp_nofault_PIOR_target = SH1_IPI_ACCESS;
  60        else if (is_shub2())
  61                xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
  62
  63        return xpSuccess;
  64}
  65
  66static void
  67xp_unregister_nofault_code_sn2(void)
  68{
  69        u64 func_addr = *(u64 *)xp_nofault_PIOR;
  70        u64 err_func_addr = *(u64 *)xp_error_PIOR;
  71
  72        /* unregister the PIO read nofault code region */
  73        (void)sn_register_nofault_code(func_addr, err_func_addr,
  74                                       err_func_addr, 1, 0);
  75}
  76
  77/*
  78 * Convert a virtual memory address to a physical memory address.
  79 */
  80static unsigned long
  81xp_pa_sn2(void *addr)
  82{
  83        return __pa(addr);
  84}
  85
  86/*
  87 * Convert a global physical to a socket physical address.
  88 */
  89static unsigned long
  90xp_socket_pa_sn2(unsigned long gpa)
  91{
  92        return gpa;
  93}
  94
  95/*
  96 * Wrapper for bte_copy().
  97 *
  98 *      dst_pa - physical address of the destination of the transfer.
  99 *      src_pa - physical address of the source of the transfer.
 100 *      len - number of bytes to transfer from source to destination.
 101 *
 102 * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock.
 103 */
 104static enum xp_retval
 105xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa,
 106                     size_t len)
 107{
 108        bte_result_t ret;
 109
 110        ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
 111        if (ret == BTE_SUCCESS)
 112                return xpSuccess;
 113
 114        if (is_shub2()) {
 115                dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa="
 116                        "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa,
 117                        src_pa, len);
 118        } else {
 119                dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx "
 120                        "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len);
 121        }
 122
 123        return xpBteCopyError;
 124}
 125
 126static int
 127xp_cpu_to_nasid_sn2(int cpuid)
 128{
 129        return cpuid_to_nasid(cpuid);
 130}
 131
 132static enum xp_retval
 133xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size)
 134{
 135        u64 nasid_array = 0;
 136        int ret;
 137
 138        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
 139                                   &nasid_array);
 140        if (ret != 0) {
 141                dev_err(xp, "sn_change_memprotect(,, "
 142                        "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
 143                return xpSalError;
 144        }
 145        return xpSuccess;
 146}
 147
 148static enum xp_retval
 149xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size)
 150{
 151        u64 nasid_array = 0;
 152        int ret;
 153
 154        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
 155                                   &nasid_array);
 156        if (ret != 0) {
 157                dev_err(xp, "sn_change_memprotect(,, "
 158                        "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
 159                return xpSalError;
 160        }
 161        return xpSuccess;
 162}
 163
 164enum xp_retval
 165xp_init_sn2(void)
 166{
 167        BUG_ON(!is_shub());
 168
 169        xp_max_npartitions = XP_MAX_NPARTITIONS_SN2;
 170        xp_partition_id = sn_partition_id;
 171        xp_region_size = sn_region_size;
 172
 173        xp_pa = xp_pa_sn2;
 174        xp_socket_pa = xp_socket_pa_sn2;
 175        xp_remote_memcpy = xp_remote_memcpy_sn2;
 176        xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;
 177        xp_expand_memprotect = xp_expand_memprotect_sn2;
 178        xp_restrict_memprotect = xp_restrict_memprotect_sn2;
 179
 180        return xp_register_nofault_code_sn2();
 181}
 182
 183void
 184xp_exit_sn2(void)
 185{
 186        BUG_ON(!is_shub());
 187
 188        xp_unregister_nofault_code_sn2();
 189}
 190
 191