0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/efi.h>
0011 #include <linux/export.h>
0012 #include <linux/slab.h>
0013 #include <asm/efi.h>
0014 #include <linux/io.h>
0015 #include <asm/pgalloc.h>
0016 #include <asm/uv/bios.h>
0017 #include <asm/uv/uv_hub.h>
0018
0019 unsigned long uv_systab_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
0020
0021 struct uv_systab *uv_systab;
0022
0023 static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
0024 u64 a4, u64 a5)
0025 {
0026 struct uv_systab *tab = uv_systab;
0027 s64 ret;
0028
0029 if (!tab || !tab->function)
0030
0031
0032
0033 return BIOS_STATUS_UNIMPLEMENTED;
0034
0035 ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
0036
0037 return ret;
0038 }
0039
0040 static s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4,
0041 u64 a5)
0042 {
0043 s64 ret;
0044
0045 if (down_interruptible(&__efi_uv_runtime_lock))
0046 return BIOS_STATUS_ABORT;
0047
0048 ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
0049 up(&__efi_uv_runtime_lock);
0050
0051 return ret;
0052 }
0053
0054 static s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
0055 u64 a4, u64 a5)
0056 {
0057 unsigned long bios_flags;
0058 s64 ret;
0059
0060 if (down_interruptible(&__efi_uv_runtime_lock))
0061 return BIOS_STATUS_ABORT;
0062
0063 local_irq_save(bios_flags);
0064 ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
0065 local_irq_restore(bios_flags);
0066
0067 up(&__efi_uv_runtime_lock);
0068
0069 return ret;
0070 }
0071
0072 long sn_partition_id;
0073 EXPORT_SYMBOL_GPL(sn_partition_id);
0074 long sn_coherency_id;
0075 EXPORT_SYMBOL_GPL(sn_coherency_id);
0076 long sn_region_size;
0077 EXPORT_SYMBOL_GPL(sn_region_size);
0078 long system_serial_number;
0079 int uv_type;
0080
0081 s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
0082 long *region, long *ssn)
0083 {
0084 s64 ret;
0085 u64 v0, v1;
0086 union partition_info_u part;
0087
0088 ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc,
0089 (u64)(&v0), (u64)(&v1), 0, 0);
0090 if (ret != BIOS_STATUS_SUCCESS)
0091 return ret;
0092
0093 part.val = v0;
0094 if (uvtype)
0095 *uvtype = part.hub_version;
0096 if (partid)
0097 *partid = part.partition_id;
0098 if (coher)
0099 *coher = part.coherence_id;
0100 if (region)
0101 *region = part.region_size;
0102 if (ssn)
0103 *ssn = v1;
0104 return ret;
0105 }
0106
0107 int
0108 uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
0109 unsigned long *intr_mmr_offset)
0110 {
0111 u64 watchlist;
0112 s64 ret;
0113
0114
0115
0116
0117 ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
0118 mq_size, (u64)intr_mmr_offset,
0119 (u64)&watchlist, 0);
0120 if (ret < BIOS_STATUS_SUCCESS)
0121 return ret;
0122
0123 return watchlist;
0124 }
0125 EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
0126
0127 int
0128 uv_bios_mq_watchlist_free(int blade, int watchlist_num)
0129 {
0130 return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
0131 blade, watchlist_num, 0, 0, 0);
0132 }
0133 EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
0134
0135 s64
0136 uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
0137 {
0138 return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
0139 perms, 0, 0);
0140 }
0141 EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
0142
0143 s64
0144 uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
0145 {
0146 return uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
0147 (u64)addr, buf, (u64)len, 0);
0148 }
0149 EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
0150
0151 s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
0152 {
0153 return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
0154 (u64)ticks_per_second, 0, 0, 0);
0155 }
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169 int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
0170 {
0171 return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
0172 (u64)decode, (u64)domain, (u64)bus, 0, 0);
0173 }
0174
0175 extern s64 uv_bios_get_master_nasid(u64 size, u64 *master_nasid)
0176 {
0177 return uv_bios_call(UV_BIOS_EXTRA, 0, UV_BIOS_EXTRA_MASTER_NASID, 0,
0178 size, (u64)master_nasid);
0179 }
0180 EXPORT_SYMBOL_GPL(uv_bios_get_master_nasid);
0181
0182 extern s64 uv_bios_get_heapsize(u64 nasid, u64 size, u64 *heap_size)
0183 {
0184 return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_GET_HEAPSIZE,
0185 0, size, (u64)heap_size);
0186 }
0187 EXPORT_SYMBOL_GPL(uv_bios_get_heapsize);
0188
0189 extern s64 uv_bios_install_heap(u64 nasid, u64 heap_size, u64 *bios_heap)
0190 {
0191 return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_INSTALL_HEAP,
0192 0, heap_size, (u64)bios_heap);
0193 }
0194 EXPORT_SYMBOL_GPL(uv_bios_install_heap);
0195
0196 extern s64 uv_bios_obj_count(u64 nasid, u64 size, u64 *objcnt)
0197 {
0198 return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_OBJECT_COUNT,
0199 0, size, (u64)objcnt);
0200 }
0201 EXPORT_SYMBOL_GPL(uv_bios_obj_count);
0202
0203 extern s64 uv_bios_enum_objs(u64 nasid, u64 size, u64 *objbuf)
0204 {
0205 return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_ENUM_OBJECTS,
0206 0, size, (u64)objbuf);
0207 }
0208 EXPORT_SYMBOL_GPL(uv_bios_enum_objs);
0209
0210 extern s64 uv_bios_enum_ports(u64 nasid, u64 obj_id, u64 size, u64 *portbuf)
0211 {
0212 return uv_bios_call(UV_BIOS_EXTRA, nasid, UV_BIOS_EXTRA_ENUM_PORTS,
0213 obj_id, size, (u64)portbuf);
0214 }
0215 EXPORT_SYMBOL_GPL(uv_bios_enum_ports);
0216
0217 extern s64 uv_bios_get_geoinfo(u64 nasid, u64 size, u64 *buf)
0218 {
0219 return uv_bios_call(UV_BIOS_GET_GEOINFO, nasid, (u64)buf, size, 0, 0);
0220 }
0221 EXPORT_SYMBOL_GPL(uv_bios_get_geoinfo);
0222
0223 extern s64 uv_bios_get_pci_topology(u64 size, u64 *buf)
0224 {
0225 return uv_bios_call(UV_BIOS_GET_PCI_TOPOLOGY, (u64)buf, size, 0, 0, 0);
0226 }
0227 EXPORT_SYMBOL_GPL(uv_bios_get_pci_topology);
0228
0229 unsigned long get_uv_systab_phys(bool msg)
0230 {
0231 if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
0232 !uv_systab_phys || efi_runtime_disabled()) {
0233 if (msg)
0234 pr_crit("UV: UVsystab: missing\n");
0235 return 0;
0236 }
0237 return uv_systab_phys;
0238 }
0239
0240 int uv_bios_init(void)
0241 {
0242 unsigned long uv_systab_phys_addr;
0243
0244 uv_systab = NULL;
0245 uv_systab_phys_addr = get_uv_systab_phys(1);
0246 if (!uv_systab_phys_addr)
0247 return -EEXIST;
0248
0249 uv_systab = ioremap(uv_systab_phys_addr, sizeof(struct uv_systab));
0250 if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
0251 pr_err("UV: UVsystab: bad signature!\n");
0252 iounmap(uv_systab);
0253 return -EINVAL;
0254 }
0255
0256
0257 if (uv_systab->revision >= UV_SYSTAB_VERSION_UV4) {
0258 int size = uv_systab->size;
0259
0260 iounmap(uv_systab);
0261 uv_systab = ioremap(uv_systab_phys_addr, size);
0262 if (!uv_systab) {
0263 pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
0264 return -EFAULT;
0265 }
0266 }
0267 pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
0268 return 0;
0269 }