2019-05-27 06:55:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2008-07-09 20:27:19 +00:00
|
|
|
/*
|
|
|
|
* BIOS run time interface routines.
|
|
|
|
*
|
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
|
|
|
|
2019-06-25 13:48:35 +00:00
|
|
|
unsigned long uv_systab_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
|
|
|
|
|
2016-04-29 21:54:18 +00:00
|
|
|
struct uv_systab *uv_systab;
|
2008-10-03 16:59:15 +00:00
|
|
|
|
2019-02-13 19:34:13 +00:00
|
|
|
static 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/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates
Some time ago, we brought our UV BIOS callback code up to speed with the
new EFI memory mapping scheme, in commit:
d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()")
By leveraging some changes that I made to a few of the EFI runtime
callback mechanisms, in commit:
80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()")
This got everything running smoothly on UV, with the new EFI mapping
code. However, this left one, small loose end, in that EFI_OLD_MEMMAP
(a.k.a. efi=old_map) will no longer work on UV, on kernels that include
the aforementioned changes.
At the time this was not a major issue (in fact, it still really isn't),
but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our
systems. This commit adds a check into uv_bios_call(), to see if we have
the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to
using our old callback method, which uses efi_call() directly on the __va()
of our function pointer.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: <stable@vger.kernel.org> # v4.7 and later
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Travis <travis@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-10-20 01:48:51 +00:00
|
|
|
/*
|
efi/x86: Limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older
method of mapping the EFI runtime services memory regions, because
it was deemed risky at the time to implement a new method without
providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1
machines, and so these are the only ones for which the fallback gets
enabled automatically (via a DMI quirk). The fallback can be enabled
manually as well, by passing efi=old_map, but there is very little
evidence that suggests that this is something that is being relied
upon in the field.
Given that UV1 support is not enabled by default by the distros
(Ubuntu, Fedora), there is no point in carrying this fallback code
all the time if there are no other users. So let's move it into the
UV support code, and document that efi=old_map now requires this
support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV
machines to work around kernel regressions in production, so we
keep the option to enable it by hand, but only if the kernel was
built with UV support.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200113172245.27925-8-ardb@kernel.org
2020-01-13 17:22:39 +00:00
|
|
|
* If EFI_UV1_MEMMAP is set, we need to fall back to using our old EFI
|
x86/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates
Some time ago, we brought our UV BIOS callback code up to speed with the
new EFI memory mapping scheme, in commit:
d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()")
By leveraging some changes that I made to a few of the EFI runtime
callback mechanisms, in commit:
80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()")
This got everything running smoothly on UV, with the new EFI mapping
code. However, this left one, small loose end, in that EFI_OLD_MEMMAP
(a.k.a. efi=old_map) will no longer work on UV, on kernels that include
the aforementioned changes.
At the time this was not a major issue (in fact, it still really isn't),
but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our
systems. This commit adds a check into uv_bios_call(), to see if we have
the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to
using our old callback method, which uses efi_call() directly on the __va()
of our function pointer.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: <stable@vger.kernel.org> # v4.7 and later
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Travis <travis@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-10-20 01:48:51 +00:00
|
|
|
* callback method, which uses efi_call() directly, with the kernel page tables:
|
|
|
|
*/
|
efi/x86: Limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older
method of mapping the EFI runtime services memory regions, because
it was deemed risky at the time to implement a new method without
providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1
machines, and so these are the only ones for which the fallback gets
enabled automatically (via a DMI quirk). The fallback can be enabled
manually as well, by passing efi=old_map, but there is very little
evidence that suggests that this is something that is being relied
upon in the field.
Given that UV1 support is not enabled by default by the distros
(Ubuntu, Fedora), there is no point in carrying this fallback code
all the time if there are no other users. So let's move it into the
UV support code, and document that efi=old_map now requires this
support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV
machines to work around kernel regressions in production, so we
keep the option to enable it by hand, but only if the kernel was
built with UV support.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200113172245.27925-8-ardb@kernel.org
2020-01-13 17:22:39 +00:00
|
|
|
if (unlikely(efi_enabled(EFI_UV1_MEMMAP))) {
|
2020-01-03 11:39:42 +00:00
|
|
|
kernel_fpu_begin();
|
x86/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates
Some time ago, we brought our UV BIOS callback code up to speed with the
new EFI memory mapping scheme, in commit:
d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()")
By leveraging some changes that I made to a few of the EFI runtime
callback mechanisms, in commit:
80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()")
This got everything running smoothly on UV, with the new EFI mapping
code. However, this left one, small loose end, in that EFI_OLD_MEMMAP
(a.k.a. efi=old_map) will no longer work on UV, on kernels that include
the aforementioned changes.
At the time this was not a major issue (in fact, it still really isn't),
but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our
systems. This commit adds a check into uv_bios_call(), to see if we have
the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to
using our old callback method, which uses efi_call() directly on the __va()
of our function pointer.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: <stable@vger.kernel.org> # v4.7 and later
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Travis <travis@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-10-20 01:48:51 +00:00
|
|
|
ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5);
|
2020-01-03 11:39:42 +00:00
|
|
|
kernel_fpu_end();
|
|
|
|
} else {
|
x86/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates
Some time ago, we brought our UV BIOS callback code up to speed with the
new EFI memory mapping scheme, in commit:
d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()")
By leveraging some changes that I made to a few of the EFI runtime
callback mechanisms, in commit:
80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()")
This got everything running smoothly on UV, with the new EFI mapping
code. However, this left one, small loose end, in that EFI_OLD_MEMMAP
(a.k.a. efi=old_map) will no longer work on UV, on kernels that include
the aforementioned changes.
At the time this was not a major issue (in fact, it still really isn't),
but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our
systems. This commit adds a check into uv_bios_call(), to see if we have
the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to
using our old callback method, which uses efi_call() directly on the __va()
of our function pointer.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: <stable@vger.kernel.org> # v4.7 and later
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Travis <travis@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-10-20 01:48:51 +00:00
|
|
|
ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
|
2020-01-03 11:39:42 +00:00
|
|
|
}
|
x86/platform/UV: Fix support for EFI_OLD_MEMMAP after BIOS callback updates
Some time ago, we brought our UV BIOS callback code up to speed with the
new EFI memory mapping scheme, in commit:
d1be84a232e3 ("x86/uv: Update uv_bios_call() to use efi_call_virt_pointer()")
By leveraging some changes that I made to a few of the EFI runtime
callback mechanisms, in commit:
80e75596079f ("efi: Convert efi_call_virt() to efi_call_virt_pointer()")
This got everything running smoothly on UV, with the new EFI mapping
code. However, this left one, small loose end, in that EFI_OLD_MEMMAP
(a.k.a. efi=old_map) will no longer work on UV, on kernels that include
the aforementioned changes.
At the time this was not a major issue (in fact, it still really isn't),
but there's no reason that EFI_OLD_MEMMAP *shouldn't* work on our
systems. This commit adds a check into uv_bios_call(), to see if we have
the EFI_OLD_MEMMAP bit set in efi.flags. If it is set, we fall back to
using our old callback method, which uses efi_call() directly on the __va()
of our function pointer.
Signed-off-by: Alex Thorlton <athorlton@sgi.com>
Acked-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: <stable@vger.kernel.org> # v4.7 and later
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Travis <travis@sgi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1476928131-170101-1-git-send-email-athorlton@sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-10-20 01:48:51 +00:00
|
|
|
|
2009-12-17 16:53:25 +00:00
|
|
|
return ret;
|
2008-07-09 20:27:19 +00:00
|
|
|
}
|
2019-02-13 19:34:13 +00:00
|
|
|
|
|
|
|
s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
|
|
|
|
{
|
|
|
|
s64 ret;
|
|
|
|
|
|
|
|
if (down_interruptible(&__efi_uv_runtime_lock))
|
|
|
|
return BIOS_STATUS_ABORT;
|
|
|
|
|
|
|
|
ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
|
|
|
|
up(&__efi_uv_runtime_lock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
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;
|
|
|
|
|
2019-02-13 19:34:13 +00:00
|
|
|
if (down_interruptible(&__efi_uv_runtime_lock))
|
|
|
|
return BIOS_STATUS_ABORT;
|
|
|
|
|
2008-10-03 16:59:15 +00:00
|
|
|
local_irq_save(bios_flags);
|
2019-02-13 19:34:13 +00:00
|
|
|
ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
|
2008-10-03 16:59:15 +00:00
|
|
|
local_irq_restore(bios_flags);
|
|
|
|
|
2019-02-13 19:34:13 +00:00
|
|
|
up(&__efi_uv_runtime_lock);
|
|
|
|
|
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)
|
|
|
|
{
|
2016-09-11 05:58:21 +00:00
|
|
|
return uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
|
|
|
|
(u64)addr, buf, (u64)len, 0);
|
2008-11-06 04:15:13 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
|
2019-09-10 14:58:42 +00:00
|
|
|
int uv_bios_init(void)
|
2008-10-03 16:59:15 +00:00
|
|
|
{
|
2016-04-29 21:54:18 +00:00
|
|
|
uv_systab = NULL;
|
2019-06-25 13:48:35 +00:00
|
|
|
if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
|
|
|
|
!uv_systab_phys || efi_runtime_disabled()) {
|
2016-04-29 21:54:18 +00:00
|
|
|
pr_crit("UV: UVsystab: missing\n");
|
2019-09-10 14:58:42 +00:00
|
|
|
return -EEXIST;
|
2008-10-03 16:59:15 +00:00
|
|
|
}
|
|
|
|
|
2019-06-25 13:48:35 +00:00
|
|
|
uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
|
2016-04-29 21:54:18 +00:00
|
|
|
if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
|
|
|
|
pr_err("UV: UVsystab: bad signature!\n");
|
|
|
|
iounmap(uv_systab);
|
2019-09-10 14:58:42 +00:00
|
|
|
return -EINVAL;
|
2016-04-29 21:54:18 +00:00
|
|
|
}
|
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);
|
2019-06-25 13:48:35 +00:00
|
|
|
uv_systab = ioremap(uv_systab_phys, 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);
|
2019-09-10 14:58:42 +00:00
|
|
|
return -EFAULT;
|
2016-04-29 21:54:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
|
2019-09-10 14:58:42 +00:00
|
|
|
return 0;
|
2008-10-03 16:59:15 +00:00
|
|
|
}
|
efi/x86: Limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older
method of mapping the EFI runtime services memory regions, because
it was deemed risky at the time to implement a new method without
providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1
machines, and so these are the only ones for which the fallback gets
enabled automatically (via a DMI quirk). The fallback can be enabled
manually as well, by passing efi=old_map, but there is very little
evidence that suggests that this is something that is being relied
upon in the field.
Given that UV1 support is not enabled by default by the distros
(Ubuntu, Fedora), there is no point in carrying this fallback code
all the time if there are no other users. So let's move it into the
UV support code, and document that efi=old_map now requires this
support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV
machines to work around kernel regressions in production, so we
keep the option to enable it by hand, but only if the kernel was
built with UV support.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200113172245.27925-8-ardb@kernel.org
2020-01-13 17:22:39 +00:00
|
|
|
|
|
|
|
static void __init early_code_mapping_set_exec(int executable)
|
|
|
|
{
|
|
|
|
efi_memory_desc_t *md;
|
|
|
|
|
|
|
|
if (!(__supported_pte_mask & _PAGE_NX))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Make EFI service code area executable */
|
|
|
|
for_each_efi_memory_desc(md) {
|
|
|
|
if (md->type == EFI_RUNTIME_SERVICES_CODE ||
|
|
|
|
md->type == EFI_BOOT_SERVICES_CODE)
|
|
|
|
efi_set_executable(md, executable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* After the lock is released, the original page table is restored.
|
|
|
|
*/
|
|
|
|
int pgd_idx, i;
|
|
|
|
int nr_pgds;
|
|
|
|
pgd_t *pgd;
|
|
|
|
p4d_t *p4d;
|
|
|
|
pud_t *pud;
|
|
|
|
|
|
|
|
nr_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
|
|
|
|
|
|
|
|
for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++) {
|
|
|
|
pgd = pgd_offset_k(pgd_idx * PGDIR_SIZE);
|
|
|
|
set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]);
|
|
|
|
|
|
|
|
if (!pgd_present(*pgd))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < PTRS_PER_P4D; i++) {
|
|
|
|
p4d = p4d_offset(pgd,
|
|
|
|
pgd_idx * PGDIR_SIZE + i * P4D_SIZE);
|
|
|
|
|
|
|
|
if (!p4d_present(*p4d))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pud = (pud_t *)p4d_page_vaddr(*p4d);
|
|
|
|
pud_free(&init_mm, pud);
|
|
|
|
}
|
|
|
|
|
|
|
|
p4d = (p4d_t *)pgd_page_vaddr(*pgd);
|
|
|
|
p4d_free(&init_mm, p4d);
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(save_pgd);
|
|
|
|
|
|
|
|
__flush_tlb_all();
|
|
|
|
early_code_mapping_set_exec(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
pgd_t * __init efi_uv1_memmap_phys_prolog(void)
|
|
|
|
{
|
|
|
|
unsigned long vaddr, addr_pgd, addr_p4d, addr_pud;
|
|
|
|
pgd_t *save_pgd, *pgd_k, *pgd_efi;
|
|
|
|
p4d_t *p4d, *p4d_k, *p4d_efi;
|
|
|
|
pud_t *pud;
|
|
|
|
|
|
|
|
int pgd;
|
|
|
|
int n_pgds, i, j;
|
|
|
|
|
|
|
|
early_code_mapping_set_exec(1);
|
|
|
|
|
|
|
|
n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
|
|
|
|
save_pgd = kmalloc_array(n_pgds, sizeof(*save_pgd), GFP_KERNEL);
|
|
|
|
if (!save_pgd)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build 1:1 identity mapping for UV1 memmap usage. Note that
|
|
|
|
* PAGE_OFFSET is PGDIR_SIZE aligned when KASLR is disabled, while
|
|
|
|
* it is PUD_SIZE ALIGNED with KASLR enabled. So for a given physical
|
|
|
|
* address X, the pud_index(X) != pud_index(__va(X)), we can only copy
|
|
|
|
* PUD entry of __va(X) to fill in pud entry of X to build 1:1 mapping.
|
|
|
|
* This means here we can only reuse the PMD tables of the direct mapping.
|
|
|
|
*/
|
|
|
|
for (pgd = 0; pgd < n_pgds; pgd++) {
|
|
|
|
addr_pgd = (unsigned long)(pgd * PGDIR_SIZE);
|
|
|
|
vaddr = (unsigned long)__va(pgd * PGDIR_SIZE);
|
|
|
|
pgd_efi = pgd_offset_k(addr_pgd);
|
|
|
|
save_pgd[pgd] = *pgd_efi;
|
|
|
|
|
|
|
|
p4d = p4d_alloc(&init_mm, pgd_efi, addr_pgd);
|
|
|
|
if (!p4d) {
|
|
|
|
pr_err("Failed to allocate p4d table!\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < PTRS_PER_P4D; i++) {
|
|
|
|
addr_p4d = addr_pgd + i * P4D_SIZE;
|
|
|
|
p4d_efi = p4d + p4d_index(addr_p4d);
|
|
|
|
|
|
|
|
pud = pud_alloc(&init_mm, p4d_efi, addr_p4d);
|
|
|
|
if (!pud) {
|
|
|
|
pr_err("Failed to allocate pud table!\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < PTRS_PER_PUD; j++) {
|
|
|
|
addr_pud = addr_p4d + j * PUD_SIZE;
|
|
|
|
|
|
|
|
if (addr_pud > (max_pfn << PAGE_SHIFT))
|
|
|
|
break;
|
|
|
|
|
|
|
|
vaddr = (unsigned long)__va(addr_pud);
|
|
|
|
|
|
|
|
pgd_k = pgd_offset_k(vaddr);
|
|
|
|
p4d_k = p4d_offset(pgd_k, vaddr);
|
|
|
|
pud[j] = *pud_offset(p4d_k, vaddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pgd_offset_k(pgd * PGDIR_SIZE)->pgd &= ~_PAGE_NX;
|
|
|
|
}
|
|
|
|
|
|
|
|
__flush_tlb_all();
|
|
|
|
return save_pgd;
|
|
|
|
out:
|
|
|
|
efi_uv1_memmap_phys_epilog(save_pgd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
|
|
|
|
u32 type, u64 attribute)
|
|
|
|
{
|
|
|
|
unsigned long last_map_pfn;
|
|
|
|
|
|
|
|
if (type == EFI_MEMORY_MAPPED_IO)
|
|
|
|
return ioremap(phys_addr, size);
|
|
|
|
|
2020-04-10 21:33:24 +00:00
|
|
|
last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size,
|
|
|
|
PAGE_KERNEL);
|
efi/x86: Limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older
method of mapping the EFI runtime services memory regions, because
it was deemed risky at the time to implement a new method without
providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1
machines, and so these are the only ones for which the fallback gets
enabled automatically (via a DMI quirk). The fallback can be enabled
manually as well, by passing efi=old_map, but there is very little
evidence that suggests that this is something that is being relied
upon in the field.
Given that UV1 support is not enabled by default by the distros
(Ubuntu, Fedora), there is no point in carrying this fallback code
all the time if there are no other users. So let's move it into the
UV support code, and document that efi=old_map now requires this
support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV
machines to work around kernel regressions in production, so we
keep the option to enable it by hand, but only if the kernel was
built with UV support.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200113172245.27925-8-ardb@kernel.org
2020-01-13 17:22:39 +00:00
|
|
|
if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
|
|
|
|
unsigned long top = last_map_pfn << PAGE_SHIFT;
|
|
|
|
efi_ioremap(top, size - (top - phys_addr), type, attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(attribute & EFI_MEMORY_WB))
|
|
|
|
efi_memory_uc((u64)(unsigned long)__va(phys_addr), size);
|
|
|
|
|
|
|
|
return (void __iomem *)__va(phys_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init arch_parse_efi_cmdline(char *str)
|
|
|
|
{
|
|
|
|
if (!str) {
|
|
|
|
pr_warn("need at least one option\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-01-18 16:57:05 +00:00
|
|
|
if (!efi_is_mixed() && parse_option_str(str, "old_map"))
|
efi/x86: Limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older
method of mapping the EFI runtime services memory regions, because
it was deemed risky at the time to implement a new method without
providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1
machines, and so these are the only ones for which the fallback gets
enabled automatically (via a DMI quirk). The fallback can be enabled
manually as well, by passing efi=old_map, but there is very little
evidence that suggests that this is something that is being relied
upon in the field.
Given that UV1 support is not enabled by default by the distros
(Ubuntu, Fedora), there is no point in carrying this fallback code
all the time if there are no other users. So let's move it into the
UV support code, and document that efi=old_map now requires this
support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV
machines to work around kernel regressions in production, so we
keep the option to enable it by hand, but only if the kernel was
built with UV support.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200113172245.27925-8-ardb@kernel.org
2020-01-13 17:22:39 +00:00
|
|
|
set_bit(EFI_UV1_MEMMAP, &efi.flags);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
early_param("efi", arch_parse_efi_cmdline);
|