2008-07-09 20:27:19 +00:00
|
|
|
/*
|
|
|
|
* BIOS run time interface routines.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2008-10-03 16:59:15 +00:00
|
|
|
*
|
2009-12-17 16:53:25 +00:00
|
|
|
* Copyright (c) 2008-2009 Silicon Graphics, Inc. All Rights Reserved.
|
|
|
|
* Copyright (c) Russ Anderson <rja@sgi.com>
|
2008-07-09 20:27:19 +00:00
|
|
|
*/
|
|
|
|
|
2008-10-03 16:59:15 +00:00
|
|
|
#include <linux/efi.h>
|
2011-05-26 16:22:53 +00:00
|
|
|
#include <linux/export.h>
|
2016-04-29 21:54:18 +00:00
|
|
|
#include <linux/slab.h>
|
2008-10-03 16:59:15 +00:00
|
|
|
#include <asm/efi.h>
|
|
|
|
#include <linux/io.h>
|
2008-07-09 20:27:19 +00:00
|
|
|
#include <asm/uv/bios.h>
|
2008-10-03 16:59:33 +00:00
|
|
|
#include <asm/uv/uv_hub.h>
|
2008-07-09 20:27:19 +00:00
|
|
|
|
2016-04-29 21:54:18 +00:00
|
|
|
struct uv_systab *uv_systab;
|
2008-10-03 16:59:15 +00:00
|
|
|
|
|
|
|
s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
|
2008-07-09 20:27:19 +00:00
|
|
|
{
|
2016-04-29 21:54:18 +00:00
|
|
|
struct uv_systab *tab = uv_systab;
|
2009-12-17 16:53:25 +00:00
|
|
|
s64 ret;
|
2008-10-03 16:59:15 +00:00
|
|
|
|
2016-04-29 21:54:18 +00:00
|
|
|
if (!tab || !tab->function)
|
2008-10-03 16:59:15 +00:00
|
|
|
/*
|
|
|
|
* BIOS does not support UV systab
|
|
|
|
*/
|
|
|
|
return BIOS_STATUS_UNIMPLEMENTED;
|
|
|
|
|
x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()
Now that the efi_call_virt() macro has been generalized to be able to
use EFI system tables besides efi.systab, we are able to convert our
uv_bios_call() wrapper to use this standard EFI callback mechanism.
This simple change is part of a much larger effort to recover from some
issues with the way we were mapping in some of our MMRs, and the way
that we were doing our BIOS callbacks, which were uncovered by commit
67a9108ed431 ("x86/efi: Build our own page table structures").
The first issue that this uncovered was that we were relying on the EFI
memory mapping mechanism to map in our MMR space for us, which, while
reliable, was technically a bug, as it relied on "undefined" behavior in
the mapping code.
The reason we were able to piggyback on the EFI memory mapping code to
map in our MMRs was because, previously, EFI code used the
trampoline_pgd, which shares a few entries with the main kernel pgd. It
just so happened, that the memory range containing our MMRs was inside
one of those shared regions, which kept our code working without issue
for quite a while.
Anyways, once we discovered this problem, we brought back our original
code to map in the MMRs with commit:
08914f436bdd ("x86/platform/UV: Bring back the call to map_low_mmrs in uv_system_init")
This got our systems a little further along, but we were still running
into trouble with our EFI callbacks, which prevented us from booting
all the way up.
Our first step towards fixing the BIOS callbacks was to get our
uv_bios_call() wrapper updated to use efi_call_virt() instead of the plain
efi_call(). The previous patch took care of the effort needed to make
that possible. Along the way, we hit a major issue with some confusion
about how to properly pull arguments higher than number 6 off the stack
in the efi_call() code, which resulted in the following commit from Linus:
683ad8092cd2 ("x86/efi: Fix 7-parameter efi_call()s")
Now that all of those issues are out of the way, we're able to make this
simple change to use the new efi_call_virt_pointer() in uv_bios_call()
which gets our machines booting, running properly, and able to execute our
callbacks with 6+ arguments.
Note that, since we are now using the EFI page table when we make our
function call, we are no longer able to make the call using the __va()
of our function pointer, since the memory range containing that address
isn't mapped into the EFI page table. For now, we will use the physical
address of the function directly, since that is mapped into the EFI page
table. In the near future, we're going to get some code added in to
properly update our function pointer to its virtual address during
SetVirtualAddressMap.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roy Franz <roy.franz@linaro.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1466839230-12781-6-git-send-email-matt@codeblueprint.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-06-25 07:20:28 +00:00
|
|
|
ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
|
2009-12-17 16:53:25 +00:00
|
|
|
return ret;
|
2008-07-09 20:27:19 +00:00
|
|
|
}
|
2009-12-17 16:53:25 +00:00
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_call);
|
2008-07-09 20:27:19 +00:00
|
|
|
|
2008-10-03 16:59:15 +00:00
|
|
|
s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
|
|
|
|
u64 a4, u64 a5)
|
2008-07-09 20:27:19 +00:00
|
|
|
{
|
2008-10-03 16:59:15 +00:00
|
|
|
unsigned long bios_flags;
|
|
|
|
s64 ret;
|
|
|
|
|
|
|
|
local_irq_save(bios_flags);
|
|
|
|
ret = uv_bios_call(which, a1, a2, a3, a4, a5);
|
|
|
|
local_irq_restore(bios_flags);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
|
|
|
|
u64 a4, u64 a5)
|
|
|
|
{
|
|
|
|
s64 ret;
|
|
|
|
|
|
|
|
preempt_disable();
|
|
|
|
ret = uv_bios_call(which, a1, a2, a3, a4, a5);
|
|
|
|
preempt_enable();
|
2008-07-09 20:27:19 +00:00
|
|
|
|
2008-10-03 16:59:15 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-10-03 16:59:33 +00:00
|
|
|
|
|
|
|
long sn_partition_id;
|
|
|
|
EXPORT_SYMBOL_GPL(sn_partition_id);
|
2008-10-21 19:09:51 +00:00
|
|
|
long sn_coherency_id;
|
|
|
|
EXPORT_SYMBOL_GPL(sn_coherency_id);
|
|
|
|
long sn_region_size;
|
|
|
|
EXPORT_SYMBOL_GPL(sn_region_size);
|
2009-12-17 16:53:25 +00:00
|
|
|
long system_serial_number;
|
|
|
|
EXPORT_SYMBOL_GPL(system_serial_number);
|
2008-10-03 16:59:33 +00:00
|
|
|
int uv_type;
|
2009-12-17 16:53:25 +00:00
|
|
|
EXPORT_SYMBOL_GPL(uv_type);
|
2008-10-03 16:59:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
|
2009-12-17 16:53:25 +00:00
|
|
|
long *region, long *ssn)
|
2008-10-03 16:59:33 +00:00
|
|
|
{
|
|
|
|
s64 ret;
|
|
|
|
u64 v0, v1;
|
|
|
|
union partition_info_u part;
|
|
|
|
|
|
|
|
ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc,
|
|
|
|
(u64)(&v0), (u64)(&v1), 0, 0);
|
|
|
|
if (ret != BIOS_STATUS_SUCCESS)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
part.val = v0;
|
|
|
|
if (uvtype)
|
|
|
|
*uvtype = part.hub_version;
|
|
|
|
if (partid)
|
|
|
|
*partid = part.partition_id;
|
|
|
|
if (coher)
|
|
|
|
*coher = part.coherence_id;
|
|
|
|
if (region)
|
|
|
|
*region = part.region_size;
|
2009-12-17 16:53:25 +00:00
|
|
|
if (ssn)
|
|
|
|
*ssn = v1;
|
2008-10-03 16:59:33 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2009-12-17 16:53:25 +00:00
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_get_sn_info);
|
2008-10-03 16:59:33 +00:00
|
|
|
|
2008-11-06 04:11:56 +00:00
|
|
|
int
|
2009-12-16 00:47:56 +00:00
|
|
|
uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
|
2008-11-06 04:11:56 +00:00
|
|
|
unsigned long *intr_mmr_offset)
|
|
|
|
{
|
|
|
|
u64 watchlist;
|
|
|
|
s64 ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bios returns watchlist number or negative error number.
|
|
|
|
*/
|
|
|
|
ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
|
2009-12-16 00:47:56 +00:00
|
|
|
mq_size, (u64)intr_mmr_offset,
|
2008-11-06 04:11:56 +00:00
|
|
|
(u64)&watchlist, 0);
|
|
|
|
if (ret < BIOS_STATUS_SUCCESS)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return watchlist;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
|
|
|
|
|
|
|
|
int
|
|
|
|
uv_bios_mq_watchlist_free(int blade, int watchlist_num)
|
|
|
|
{
|
|
|
|
return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
|
|
|
|
blade, watchlist_num, 0, 0, 0);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
|
2008-10-03 16:59:33 +00:00
|
|
|
|
2008-11-06 04:13:44 +00:00
|
|
|
s64
|
|
|
|
uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
|
|
|
|
{
|
|
|
|
return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
|
|
|
|
perms, 0, 0);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
|
|
|
|
|
2008-11-06 04:15:13 +00:00
|
|
|
s64
|
|
|
|
uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
|
|
|
|
{
|
|
|
|
s64 ret;
|
|
|
|
|
|
|
|
ret = uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
|
|
|
|
(u64)addr, buf, (u64)len, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
|
|
|
|
|
2008-10-03 16:59:33 +00:00
|
|
|
s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
|
2008-10-03 16:59:15 +00:00
|
|
|
{
|
|
|
|
return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
|
2008-10-03 16:59:33 +00:00
|
|
|
(u64)ticks_per_second, 0, 0, 0);
|
2008-07-09 20:27:19 +00:00
|
|
|
}
|
2008-10-03 16:59:33 +00:00
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_freq_base);
|
2008-10-03 16:59:15 +00:00
|
|
|
|
2010-02-02 22:38:14 +00:00
|
|
|
/*
|
|
|
|
* uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target
|
|
|
|
* @decode: true to enable target, false to disable target
|
|
|
|
* @domain: PCI domain number
|
|
|
|
* @bus: PCI bus number
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0: Success
|
|
|
|
* -EINVAL: Invalid domain or bus number
|
|
|
|
* -ENOSYS: Capability not available
|
|
|
|
* -EBUSY: Legacy VGA I/O cannot be retargeted at this time
|
|
|
|
*/
|
|
|
|
int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
|
|
|
|
{
|
|
|
|
return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
|
|
|
|
(u64)decode, (u64)domain, (u64)bus, 0, 0);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
|
|
|
|
|
2008-10-03 16:59:15 +00:00
|
|
|
#ifdef CONFIG_EFI
|
|
|
|
void uv_bios_init(void)
|
|
|
|
{
|
2016-04-29 21:54:18 +00:00
|
|
|
uv_systab = NULL;
|
2016-08-11 10:41:59 +00:00
|
|
|
if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) ||
|
|
|
|
!efi.uv_systab || efi_runtime_disabled()) {
|
2016-04-29 21:54:18 +00:00
|
|
|
pr_crit("UV: UVsystab: missing\n");
|
2008-10-03 16:59:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-29 21:54:18 +00:00
|
|
|
uv_systab = ioremap(efi.uv_systab, sizeof(struct uv_systab));
|
|
|
|
if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
|
|
|
|
pr_err("UV: UVsystab: bad signature!\n");
|
|
|
|
iounmap(uv_systab);
|
|
|
|
return;
|
|
|
|
}
|
2008-10-03 16:59:15 +00:00
|
|
|
|
2016-08-01 18:40:51 +00:00
|
|
|
/* Starting with UV4 the UV systab size is variable */
|
2016-04-29 21:54:18 +00:00
|
|
|
if (uv_systab->revision >= UV_SYSTAB_VERSION_UV4) {
|
2016-08-01 18:40:51 +00:00
|
|
|
int size = uv_systab->size;
|
|
|
|
|
2016-04-29 21:54:18 +00:00
|
|
|
iounmap(uv_systab);
|
2016-08-01 18:40:51 +00:00
|
|
|
uv_systab = ioremap(efi.uv_systab, size);
|
2016-04-29 21:54:18 +00:00
|
|
|
if (!uv_systab) {
|
2016-08-01 18:40:51 +00:00
|
|
|
pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
|
2016-04-29 21:54:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
|
2008-10-03 16:59:15 +00:00
|
|
|
}
|
|
|
|
#endif
|