1 /* 2 * BIOS run time interface routines. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * Copyright (c) 2008-2009 Silicon Graphics, Inc. All Rights Reserved. 19 * Copyright (c) Russ Anderson <rja@sgi.com> 20 */ 21 22 #include <linux/efi.h> 23 #include <linux/export.h> 24 #include <linux/slab.h> 25 #include <asm/efi.h> 26 #include <linux/io.h> 27 #include <asm/uv/bios.h> 28 #include <asm/uv/uv_hub.h> 29 30 struct uv_systab *uv_systab; 31 32 static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, 33 u64 a4, u64 a5) 34 { 35 struct uv_systab *tab = uv_systab; 36 s64 ret; 37 38 if (!tab || !tab->function) 39 /* 40 * BIOS does not support UV systab 41 */ 42 return BIOS_STATUS_UNIMPLEMENTED; 43 44 /* 45 * If EFI_OLD_MEMMAP is set, we need to fall back to using our old EFI 46 * callback method, which uses efi_call() directly, with the kernel page tables: 47 */ 48 if (unlikely(efi_enabled(EFI_OLD_MEMMAP))) 49 ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5); 50 else 51 ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5); 52 53 return ret; 54 } 55 56 s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) 57 { 58 s64 ret; 59 60 if (down_interruptible(&__efi_uv_runtime_lock)) 61 return BIOS_STATUS_ABORT; 62 63 ret = __uv_bios_call(which, a1, a2, a3, a4, a5); 64 up(&__efi_uv_runtime_lock); 65 66 return ret; 67 } 68 EXPORT_SYMBOL_GPL(uv_bios_call); 69 70 s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, 71 u64 a4, u64 a5) 72 { 73 unsigned long bios_flags; 74 s64 ret; 75 76 if (down_interruptible(&__efi_uv_runtime_lock)) 77 return BIOS_STATUS_ABORT; 78 79 local_irq_save(bios_flags); 80 ret = __uv_bios_call(which, a1, a2, a3, a4, a5); 81 local_irq_restore(bios_flags); 82 83 up(&__efi_uv_runtime_lock); 84 85 return ret; 86 } 87 88 89 long sn_partition_id; 90 EXPORT_SYMBOL_GPL(sn_partition_id); 91 long sn_coherency_id; 92 EXPORT_SYMBOL_GPL(sn_coherency_id); 93 long sn_region_size; 94 EXPORT_SYMBOL_GPL(sn_region_size); 95 long system_serial_number; 96 EXPORT_SYMBOL_GPL(system_serial_number); 97 int uv_type; 98 EXPORT_SYMBOL_GPL(uv_type); 99 100 101 s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, 102 long *region, long *ssn) 103 { 104 s64 ret; 105 u64 v0, v1; 106 union partition_info_u part; 107 108 ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc, 109 (u64)(&v0), (u64)(&v1), 0, 0); 110 if (ret != BIOS_STATUS_SUCCESS) 111 return ret; 112 113 part.val = v0; 114 if (uvtype) 115 *uvtype = part.hub_version; 116 if (partid) 117 *partid = part.partition_id; 118 if (coher) 119 *coher = part.coherence_id; 120 if (region) 121 *region = part.region_size; 122 if (ssn) 123 *ssn = v1; 124 return ret; 125 } 126 EXPORT_SYMBOL_GPL(uv_bios_get_sn_info); 127 128 int 129 uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size, 130 unsigned long *intr_mmr_offset) 131 { 132 u64 watchlist; 133 s64 ret; 134 135 /* 136 * bios returns watchlist number or negative error number. 137 */ 138 ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr, 139 mq_size, (u64)intr_mmr_offset, 140 (u64)&watchlist, 0); 141 if (ret < BIOS_STATUS_SUCCESS) 142 return ret; 143 144 return watchlist; 145 } 146 EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc); 147 148 int 149 uv_bios_mq_watchlist_free(int blade, int watchlist_num) 150 { 151 return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE, 152 blade, watchlist_num, 0, 0, 0); 153 } 154 EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free); 155 156 s64 157 uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms) 158 { 159 return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len, 160 perms, 0, 0); 161 } 162 EXPORT_SYMBOL_GPL(uv_bios_change_memprotect); 163 164 s64 165 uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len) 166 { 167 return uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie, 168 (u64)addr, buf, (u64)len, 0); 169 } 170 EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa); 171 172 s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second) 173 { 174 return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type, 175 (u64)ticks_per_second, 0, 0, 0); 176 } 177 EXPORT_SYMBOL_GPL(uv_bios_freq_base); 178 179 /* 180 * uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target 181 * @decode: true to enable target, false to disable target 182 * @domain: PCI domain number 183 * @bus: PCI bus number 184 * 185 * Returns: 186 * 0: Success 187 * -EINVAL: Invalid domain or bus number 188 * -ENOSYS: Capability not available 189 * -EBUSY: Legacy VGA I/O cannot be retargeted at this time 190 */ 191 int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus) 192 { 193 return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET, 194 (u64)decode, (u64)domain, (u64)bus, 0, 0); 195 } 196 EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target); 197 198 void uv_bios_init(void) 199 { 200 uv_systab = NULL; 201 if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || 202 !efi.uv_systab || efi_runtime_disabled()) { 203 pr_crit("UV: UVsystab: missing\n"); 204 return; 205 } 206 207 uv_systab = ioremap(efi.uv_systab, sizeof(struct uv_systab)); 208 if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) { 209 pr_err("UV: UVsystab: bad signature!\n"); 210 iounmap(uv_systab); 211 return; 212 } 213 214 /* Starting with UV4 the UV systab size is variable */ 215 if (uv_systab->revision >= UV_SYSTAB_VERSION_UV4) { 216 int size = uv_systab->size; 217 218 iounmap(uv_systab); 219 uv_systab = ioremap(efi.uv_systab, size); 220 if (!uv_systab) { 221 pr_err("UV: UVsystab: ioremap(%d) failed!\n", size); 222 return; 223 } 224 } 225 pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision); 226 } 227