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 * Wrapper for bte_copy().
  88 *
  89 *      dst_pa - physical address of the destination of the transfer.
  90 *      src_pa - physical address of the source of the transfer.
  91 *      len - number of bytes to transfer from source to destination.
  92 *
  93 * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock.
  94 */
  95static enum xp_retval
  96xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa,
  97                     size_t len)
  98{
  99        bte_result_t ret;
 100
 101        ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
 102        if (ret == BTE_SUCCESS)
 103                return xpSuccess;
 104
 105        if (is_shub2()) {
 106                dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa="
 107                        "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa,
 108                        src_pa, len);
 109        } else {
 110                dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx "
 111                        "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len);
 112        }
 113
 114        return xpBteCopyError;
 115}
 116
 117static int
 118xp_cpu_to_nasid_sn2(int cpuid)
 119{
 120        return cpuid_to_nasid(cpuid);
 121}
 122
 123static enum xp_retval
 124xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size)
 125{
 126        u64 nasid_array = 0;
 127        int ret;
 128
 129        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
 130                                   &nasid_array);
 131        if (ret != 0) {
 132                dev_err(xp, "sn_change_memprotect(,, "
 133                        "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
 134                return xpSalError;
 135        }
 136        return xpSuccess;
 137}
 138
 139static enum xp_retval
 140xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size)
 141{
 142        u64 nasid_array = 0;
 143        int ret;
 144
 145        ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
 146                                   &nasid_array);
 147        if (ret != 0) {
 148                dev_err(xp, "sn_change_memprotect(,, "
 149                        "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
 150                return xpSalError;
 151        }
 152        return xpSuccess;
 153}
 154
 155enum xp_retval
 156xp_init_sn2(void)
 157{
 158        BUG_ON(!is_shub());
 159
 160        xp_max_npartitions = XP_MAX_NPARTITIONS_SN2;
 161        xp_partition_id = sn_partition_id;
 162        xp_region_size = sn_region_size;
 163
 164        xp_pa = xp_pa_sn2;
 165        xp_remote_memcpy = xp_remote_memcpy_sn2;
 166        xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;
 167        xp_expand_memprotect = xp_expand_memprotect_sn2;
 168        xp_restrict_memprotect = xp_restrict_memprotect_sn2;
 169
 170        return xp_register_nofault_code_sn2();
 171}
 172
 173void
 174xp_exit_sn2(void)
 175{
 176        BUG_ON(!is_shub());
 177
 178        xp_unregister_nofault_code_sn2();
 179}
 180
 181