* [PATCH v2 1/3] powerpc/powernv: Add support for OPAL_SECVAR_GET
From: Nayna Jain @ 2019-04-08 22:52 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Mimi Zohar,
Matthew Garret, Paul Mackerras, Jeremy Kerr
In-Reply-To: <1554763954-11795-1-git-send-email-nayna@linux.ibm.com>
From: Claudio Carvalho <cclaudio@linux.ibm.com>
The X.509 certificates trusted by the platform and other information
required to secure boot the OS kernel are wrapped in secure variables,
which are controlled by OPAL.
This patch adds support to read OPAL secure variables through
OPAL_SECVAR_GET call. It returns the data for a given secure variable
and vendor GUID. It can be configured using CONFIG_OPAL_SECVAR.
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
---
This patch depends on a new OPAL call that is being added to skiboot.
The patch set that implements the new call has been posted to
https://patchwork.ozlabs.org/project/skiboot/list/?series=99805
---
arch/powerpc/include/asm/opal-api.h | 3 +-
arch/powerpc/include/asm/opal-secvar.h | 18 ++++
arch/powerpc/include/asm/opal.h | 2 +
arch/powerpc/platforms/powernv/Kconfig | 6 ++
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 1 +
arch/powerpc/platforms/powernv/opal-secvar.c | 107 +++++++++++++++++++
7 files changed, 137 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/opal-secvar.h
create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 870fb7b239ea..782eb20a08a7 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -210,7 +210,8 @@
#define OPAL_PCI_GET_PBCQ_TUNNEL_BAR 164
#define OPAL_PCI_SET_PBCQ_TUNNEL_BAR 165
#define OPAL_NX_COPROC_INIT 167
-#define OPAL_LAST 167
+#define OPAL_SECVAR_GET 170
+#define OPAL_LAST 171
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
diff --git a/arch/powerpc/include/asm/opal-secvar.h b/arch/powerpc/include/asm/opal-secvar.h
new file mode 100644
index 000000000000..e3d5e4cbf3bc
--- /dev/null
+++ b/arch/powerpc/include/asm/opal-secvar.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PowerNV definitions for secure variables OPAL API.
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho <cclaudio@linux.ibm.com>
+ *
+ */
+#ifndef OPAL_SECVAR_H
+#define OPAL_SECVAR_H
+
+#include <linux/efi.h>
+
+extern efi_status_t
+opal_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data);
+
+#endif
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index a55b01c90bb1..eb654baf8764 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -385,6 +385,8 @@ void opal_powercap_init(void);
void opal_psr_init(void);
void opal_sensor_groups_init(void);
+extern int opal_secvar_get(uint64_t name, uint64_t vendor, uint64_t attr,
+ uint64_t data_size, uint64_t data);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 850eee860cf2..65b060539b5c 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -47,3 +47,9 @@ config PPC_VAS
VAS adapters are found in POWER9 based systems.
If unsure, say N.
+
+config OPAL_SECVAR
+ bool "OPAL Secure Variables"
+ depends on PPC_POWERNV
+ help
+ This enables the kernel to access OPAL secure variables.
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index da2e99efbd04..1511d836fd19 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PERF_EVENTS) += opal-imc.o
obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
obj-$(CONFIG_OCXL_BASE) += ocxl.o
+obj-$(CONFIG_OPAL_SECVAR) += opal-secvar.o
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index daad8c45c8e7..eafd8f690b7a 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -282,3 +282,4 @@ OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64);
OPAL_CALL(opal_sensor_group_enable, OPAL_SENSOR_GROUP_ENABLE);
OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT);
+OPAL_CALL(opal_secvar_get, OPAL_SECVAR_GET);
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
new file mode 100644
index 000000000000..3ba02c9503f7
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PowerNV code for secure variables
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho <cclaudio@linux.ibm.com>
+ *
+ */
+
+/*
+ * The opal wrappers in this file treat the @name, @vendor, and @data
+ * parameters as little endian blobs.
+ * @name is a ucs2 string
+ * @vendor is the vendor GUID. It is converted to LE in the kernel
+ * @data variable data, which layout may be different for each variable
+ */
+
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/efi.h>
+#include <asm/machdep.h>
+#include <asm/opal.h>
+#include <asm/opal-secvar.h>
+
+static bool is_opal_secvar_supported(void)
+{
+ static bool opal_secvar_supported;
+ static bool initialized;
+
+ if (initialized)
+ return opal_secvar_supported;
+
+ if (opal_check_token(OPAL_SECVAR_GET))
+ opal_secvar_supported = true;
+ else
+ opal_secvar_supported = false;
+
+ initialized = true;
+
+ return opal_secvar_supported;
+}
+
+efi_status_t opal_to_efi_status_log(int rc, const char *func_name)
+{
+ efi_status_t status;
+
+ switch (rc) {
+ case OPAL_EMPTY:
+ status = EFI_NOT_FOUND;
+ break;
+ case OPAL_HARDWARE:
+ status = EFI_DEVICE_ERROR;
+ break;
+ case OPAL_NO_MEM:
+ pr_err("%s: No space in the volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_PARAMETER:
+ status = EFI_INVALID_PARAMETER;
+ break;
+ case OPAL_PARTIAL:
+ status = EFI_BUFFER_TOO_SMALL;
+ break;
+ case OPAL_PERMISSION:
+ status = EFI_WRITE_PROTECTED;
+ break;
+ case OPAL_RESOURCE:
+ pr_err("%s: No space in the non-volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_SUCCESS:
+ status = EFI_SUCCESS;
+ break;
+ default:
+ pr_err("%s: Unknown OPAL error %d\n", func_name, rc);
+ status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+#define opal_to_efi_status(rc) opal_to_efi_status_log(rc, __func__)
+
+efi_status_t
+opal_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data)
+{
+ int rc;
+
+ if (!is_opal_secvar_supported())
+ return EFI_UNSUPPORTED;
+
+ *data_size = cpu_to_be64(*data_size);
+
+ rc = opal_secvar_get(__pa(name), __pa(vendor), __pa(attr),
+ __pa(data_size), __pa(data));
+ /*
+ * The @attr is an optional output parameter. It is returned in
+ * big-endian.
+ */
+ if (attr)
+ *attr = be32_to_cpup(attr);
+ *data_size = be64_to_cpu(*data_size);
+
+ return opal_to_efi_status(rc);
+}
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/3] powerpc: Enabling secure boot on powernv systems - Part 1
From: Nayna Jain @ 2019-04-08 22:52 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Mimi Zohar,
Matthew Garret, Paul Mackerras, Jeremy Kerr
This patch set is part of a series that implements secure boot on PowerNV
systems.
In order to verify the OS kernel on PowerNV, secure boot requires X.509
certificates trusted by the platform, the secure boot modes, and several
other pieces of information. These are stored in secure variables
controlled by OPAL, also known as OPAL secure variables.
The IMA architecture specific policy support on Power is dependent on OPAL
runtime services to access secure variables. Instead of directly accessing
the OPAL runtime services, version 1[1] of this patch set relied upon the
EFI hooks. This version drops that dependency and calls the OPAL runtime
services directly.
Exposing the OPAL secure variables to userspace will be posted as a
separate patch set, allowing the IMA architecture specific policy on Power
to be upstreamed independently.
This patch set adds the following features:
1. Add support for OPAL Runtime API to access secure variables controlled
by OPAL.
2. Define IMA arch-specific policies based on the secure boot state and
mode of the system. On secure boot enabled powernv systems, the OS kernel
signature will be verified by IMA appraisal.
[1] https://patchwork.kernel.org/cover/10882149/
Changelog:
v2:
* Removed Patch 1: powerpc/include: Override unneeded early ioremap
functions
* Updated Subject line and patch description of the Patch 1 of this series
* Removed dependency of OPAL_SECVAR on EFI, CPU_BIG_ENDIAN and UCS2_STRING
* Changed OPAL APIs from static to non-static. Added opal-secvar.h for the
same
* Removed EFI hooks from opal_secvar.c
* Removed opal_secvar_get_next(), opal_secvar_enqueue() and
opal_query_variable_info() function
* get_powerpc_sb_mode() in secboot.c now directly calls OPAL Runtime API
rather than via EFI hooks.
* Fixed log messages in get_powerpc_sb_mode() function.
* Added dependency for PPC_SECURE_BOOT on configs PPC64 and OPAL_SECVAR
* Replaced obj-$(CONFIG_IMA) with obj-$(CONFIG_PPC_SECURE_BOOT) in
arch/powerpc/kernel/Makefile
Claudio Carvalho (1):
powerpc/powernv: Add support for OPAL_SECVAR_GET
Nayna Jain (2):
powerpc/powernv: detect the secure boot mode of the system
powerpc: Add support to initialize ima policy rules
arch/powerpc/Kconfig | 14 +++
arch/powerpc/include/asm/opal-api.h | 3 +-
arch/powerpc/include/asm/opal-secvar.h | 18 ++++
arch/powerpc/include/asm/opal.h | 2 +
arch/powerpc/include/asm/secboot.h | 21 ++++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/ima_arch.c | 54 ++++++++++
arch/powerpc/platforms/powernv/Kconfig | 6 ++
arch/powerpc/platforms/powernv/Makefile | 2 +
arch/powerpc/platforms/powernv/opal-call.c | 1 +
arch/powerpc/platforms/powernv/opal-secvar.c | 107 +++++++++++++++++++
arch/powerpc/platforms/powernv/secboot.c | 54 ++++++++++
include/linux/ima.h | 3 +-
13 files changed, 284 insertions(+), 2 deletions(-)
create mode 100644 arch/powerpc/include/asm/opal-secvar.h
create mode 100644 arch/powerpc/include/asm/secboot.h
create mode 100644 arch/powerpc/kernel/ima_arch.c
create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
create mode 100644 arch/powerpc/platforms/powernv/secboot.c
--
2.20.1
^ permalink raw reply
* Re: [PATCH v10 02/18] counter: Documentation: Add Generic Counter sysfs documentation
From: Pavel Machek @ 2019-04-08 21:55 UTC (permalink / raw)
To: William Breathitt Gray
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, linuxppc-dev, robh+dt,
Jonathan Cameron, tglx, fabrice.gasnier, esben, gregkh,
linux-kernel, leoyang.li, knaack.h, akpm, shawnguo, jic23
In-Reply-To: <bd8362f23b99af938c7bced2104eca29888253b3.1554184734.git.vilhelm.gray@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 4418 bytes --]
On Tue 2019-04-02 15:30:37, William Breathitt Gray wrote:
> This patch adds standard documentation for the userspace sysfs
> attributes of the Generic Counter interface.
>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
> ---
> Documentation/ABI/testing/sysfs-bus-counter | 230 ++++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 231 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-bus-counter
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-counter b/Documentation/ABI/testing/sysfs-bus-counter
> new file mode 100644
> index 000000000000..566bd99fe0a5
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-counter
> @@ -0,0 +1,230 @@
> +What: /sys/bus/counter/devices/counterX/countY/count
> +KernelVersion: 5.2
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Count data of Count Y represented as a string.
> +
> +What: /sys/bus/counter/devices/counterX/countY/ceiling
> +KernelVersion: 5.2
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Count value ceiling for Count Y. This is the upper limit for the
> + respective counter.
> +
> +What: /sys/bus/counter/devices/counterX/countY/floor
> +KernelVersion: 5.2
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Count value floor for Count Y. This is the lower limit for the
> + respective counter.
> +
> +What: /sys/bus/counter/devices/counterX/countY/count_mode
> +KernelVersion: 5.2
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Count mode for channel Y. The ceiling and floor values for
> + Count Y are used by the count mode where required. The following
> + count modes are available:
> +
> + normal:
> + Counting is continuous in either direction.
> +
> + range limit:
> + An upper or lower limit is set, mimicking limit switches
> + in the mechanical counterpart. The upper limit is set to
> + the Count Y ceiling value, while the lower limit is set
> + to the Count Y floor value. The counter freezes at
> + count = ceiling when counting up, and at count = floor
> + when counting down. At either of these limits, the
> + counting is resumed only when the count direction is
> + reversed.
> +
> + non-recycle:
> + The counter is disabled whenever a counter overflow or
> + underflow takes place. The counter is re-enabled when a
> + new count value is loaded to the counter via a preset
> + operation or direct write.
> +
> + modulo-n:
> + A count value boundary is set between the Count Y floor
> + value and the Count Y ceiling value. The counter is
> + reset to the Count Y floor value at count = ceiling when
> + counting up, while the counter is set to the Count Y
> + ceiling value at count = floor when counting down; the
> + counter does not freeze at the boundary points, but
> + counts continuously throughout.
> +
> +What: /sys/bus/counter/devices/counterX/countY/count_mode_available
> +What: /sys/bus/counter/devices/counterX/countY/error_noise_available
> +What: /sys/bus/counter/devices/counterX/countY/function_available
> +What: /sys/bus/counter/devices/counterX/countY/signalZ_action_available
> +KernelVersion: 5.2
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Discrete set of available values for the respective Count Y
> + configuration are listed in this file. Values are delimited by
> + newline characters.
Elsewhere in sysfs we do space-separated:
pavel@amd:~$ cat /sys/power/state
freeze mem disk
And we use [] to mark current selection:
pavel@amd:~$ cat /sys/class/leds/tpacpi\:\:thinkvantage/trigger
[none] bluetooth-power rfkill-any rfkill-none kbd-scrolllock
kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock
kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock
kbd-ctrlrlock AC-online BAT0-charging-or-full BAT0-charging BAT0-full
BAT0-charging-blink-full-solid rfkill0 phy0rx phy0tx phy0assoc
phy0radio phy0tpt mmc0 timer heartbeat audio-mute audio-micmute
rfkill1
Note this only works if you have less than PAGE_SIZE of entries... and
will never have more.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH v10 01/18] counter: Introduce the Generic Counter interface
From: Pavel Machek @ 2019-04-08 21:55 UTC (permalink / raw)
To: William Breathitt Gray
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, linuxppc-dev, robh+dt,
Jonathan Cameron, tglx, fabrice.gasnier, esben, gregkh,
linux-kernel, leoyang.li, knaack.h, akpm, shawnguo, jic23
In-Reply-To: <ad3a8c427a911848373eae1c08e89353ffb6cb6d.1554184734.git.vilhelm.gray@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 811 bytes --]
Hi!
> +const char *const counter_count_direction_str[2] = {
> + [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
> + [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
> +};
> +EXPORT_SYMBOL_GPL(counter_count_direction_str);
> +
> +const char *const counter_count_mode_str[4] = {
> + [COUNTER_COUNT_MODE_NORMAL] = "normal",
> + [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
> + [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
> + [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
> +};
> +EXPORT_SYMBOL_GPL(counter_count_mode_str);
Dunno. Exporting const tables saying "forward" and "backward". Can we
... somehow make it work without need to export this?
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* ppc64 4kB: MAX_PHYSMEM_BITS undefined
From: Hugh Dickins @ 2019-04-08 20:23 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Hugh Dickins, linuxppc-dev
Hi Ben,
5.1-rc's 8bc086899816 ("powerpc/mm: Only define MAX_PHYSMEM_BITS in
SPARSEMEM configurations") has sadly broken the build for my config
on the G5, which has (amongst a few other options):
CONFIG_PPC_BOOK3S_64=y
CONFIG_PPC_BOOK3S=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_64K_PAGES is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
Easily enough worked around for me by...
--- 5.1-rc4/arch/powerpc/include/asm/mmu.h 2019-03-24 15:40:26.833378215 -0700
+++ linux/arch/powerpc/include/asm/mmu.h 2019-04-07 19:51:11.419295089 -0700
@@ -352,7 +352,7 @@ static inline bool strict_kernel_rwx_ena
#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME) && \
defined (CONFIG_PPC_64K_PAGES)
#define MAX_PHYSMEM_BITS 51
-#elif defined(CONFIG_SPARSEMEM)
+#else
#define MAX_PHYSMEM_BITS 46
#endif
...but I don't suppose that's what you want to do.
I wonder if there was a momentary mixup between 64 bits and 64kB pages -
I'm a non-conformist using 4kB pages on ppc64.
Hugh
^ permalink raw reply
* Re: [PATCH RFC/RFT 1/6] clk: core: add support for generic big endian accesses
From: Stephen Boyd @ 2019-04-08 20:12 UTC (permalink / raw)
To: Jonas Gorski, linux-clk, linuxppc-dev
Cc: Michael Turquette, Anatolij Gustschin, Paul Mackerras
In-Reply-To: <20190408102039.6366-2-jonas.gorski@gmail.com>
Quoting Jonas Gorski (2019-04-08 03:20:34)
> Add a generic flag to mark a clock as big endian register based, and add
> accessors following these.
I like the idea of getting rid of clk_readl() and clk_writel(), but I'd
rather see that this flag is per-basic clk type instead of global to all
clks. Mostly because I don't see it as a clk property that's applicable
in general. So we would either have a flag for dividers and gates that
goes into the respective CLK_{GATE,DIVIDER}_* flag space, or some
wrapper functions like:
clk_gate_register_be()
clk_divider_register_be()
that passes this information through to the basic clk types somehow.
Then if there's no other user left of clk_readl() and clk_writel() I'd
just slam in a patch to all the files that use it to convert them to
readl() and writel(). After that, it would be great to drop the io.h
include from clk-provider.h and push that include out to any code that's
relying on it implicitly.
^ permalink raw reply
* [PATCH linux-next v9 5/7] powerpc: define syscall_get_error()
From: Dmitry V. Levin @ 2019-04-08 17:42 UTC (permalink / raw)
To: Michael Ellerman
Cc: Stephen Rothwell, Eugene Syromyatnikov, Oleg Nesterov,
Elvira Khabirova, Paul Mackerras, Andy Lutomirski, linuxppc-dev,
linux-kernel
In-Reply-To: <20190408174036.GA11889@altlinux.org>
syscall_get_error() is required to be implemented on this
architecture in addition to already implemented syscall_get_nr(),
syscall_get_arguments(), syscall_get_return_value(), and
syscall_get_arch() functions in order to extend the generic
ptrace API with PTRACE_GET_SYSCALL_INFO request.
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Elvira Khabirova <lineprinter@altlinux.org>
Cc: Eugene Syromyatnikov <esyr@redhat.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Dmitry V. Levin <ldv@altlinux.org>
---
Michael, this patch is waiting for ACK since early December.
Notes:
v9: unchanged
v8: unchanged
v7: unchanged
v6: unchanged
v5: initial revision
This change has been tested with
tools/testing/selftests/ptrace/get_syscall_info.c and strace,
so it's correct from PTRACE_GET_SYSCALL_INFO point of view.
This cast doubts on commit v4.3-rc1~86^2~81 that changed
syscall_set_return_value() in a way that doesn't quite match
syscall_get_error(), but syscall_set_return_value() is out
of scope of this series, so I'll just let you know my concerns.
arch/powerpc/include/asm/syscall.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index a048fed0722f..bd9663137d57 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -38,6 +38,16 @@ static inline void syscall_rollback(struct task_struct *task,
regs->gpr[3] = regs->orig_gpr3;
}
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /*
+ * If the system call failed,
+ * regs->gpr[3] contains a positive ERRORCODE.
+ */
+ return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
+}
+
static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
--
ldv
^ permalink raw reply related
* [PATCH linux-next v9 0/7] ptrace: add PTRACE_GET_SYSCALL_INFO request
From: Dmitry V. Levin @ 2019-04-08 17:40 UTC (permalink / raw)
To: Stephen Rothwell, Oleg Nesterov, Andy Lutomirski
Cc: James E.J. Bottomley, Paul Mackerras, linux-kselftest,
Vincent Chen, Shuah Khan, Helge Deller, Eugene Syromyatnikov,
Elvira Khabirova, James Hogan, strace-devel, Kees Cook,
linux-kernel, Greentime Hu, linux-parisc, linux-api, linux-mips,
Ralf Baechle, Richard Kuo, Paul Burton, linux-hexagon,
linuxppc-dev
[I suggest to stop waiting for more acks and merge this into linux-next as is.]
PTRACE_GET_SYSCALL_INFO is a generic ptrace API that lets ptracer obtain
details of the syscall the tracee is blocked in.
There are two reasons for a special syscall-related ptrace request.
Firstly, with the current ptrace API there are cases when ptracer cannot
retrieve necessary information about syscalls. Some examples include:
* The notorious int-0x80-from-64-bit-task issue. See [1] for details.
In short, if a 64-bit task performs a syscall through int 0x80, its tracer
has no reliable means to find out that the syscall was, in fact,
a compat syscall, and misidentifies it.
* Syscall-enter-stop and syscall-exit-stop look the same for the tracer.
Common practice is to keep track of the sequence of ptrace-stops in order
not to mix the two syscall-stops up. But it is not as simple as it looks;
for example, strace had a (just recently fixed) long-standing bug where
attaching strace to a tracee that is performing the execve system call
led to the tracer identifying the following syscall-exit-stop as
syscall-enter-stop, which messed up all the state tracking.
* Since the introduction of commit 84d77d3f06e7e8dea057d10e8ec77ad71f721be3
("ptrace: Don't allow accessing an undumpable mm"), both PTRACE_PEEKDATA
and process_vm_readv become unavailable when the process dumpable flag
is cleared. On such architectures as ia64 this results in all syscall
arguments being unavailable for the tracer.
Secondly, ptracers also have to support a lot of arch-specific code for
obtaining information about the tracee. For some architectures, this
requires a ptrace(PTRACE_PEEKUSER, ...) invocation for every syscall
argument and return value.
PTRACE_GET_SYSCALL_INFO returns the following structure:
struct ptrace_syscall_info {
__u8 op; /* PTRACE_SYSCALL_INFO_* */
__u32 arch __attribute__((__aligned__(sizeof(__u32))));
__u64 instruction_pointer;
__u64 stack_pointer;
union {
struct {
__u64 nr;
__u64 args[6];
} entry;
struct {
__s64 rval;
__u8 is_error;
} exit;
struct {
__u64 nr;
__u64 args[6];
__u32 ret_data;
} seccomp;
};
};
The structure was chosen according to [2], except for the following
changes:
* seccomp substructure was added as a superset of entry substructure;
* the type of nr field was changed from int to __u64 because syscall
numbers are, as a practical matter, 64 bits;
* stack_pointer field was added along with instruction_pointer field
since it is readily available and can save the tracer from extra
PTRACE_GETREGS/PTRACE_GETREGSET calls;
* arch is always initialized to aid with tracing system calls
* such as execve();
* instruction_pointer and stack_pointer are always initialized
so they could be easily obtained for non-syscall stops;
* a boolean is_error field was added along with rval field, this way
the tracer can more reliably distinguish a return value
from an error value.
strace has been ported to PTRACE_GET_SYSCALL_INFO.
Starting with release 4.26, strace uses PTRACE_GET_SYSCALL_INFO API
as the preferred mechanism of obtaining syscall information.
[1] https://lore.kernel.org/lkml/CA+55aFzcSVmdDj9Lh_gdbz1OzHyEm6ZrGPBDAJnywm2LF_eVyg@mail.gmail.com/
[2] https://lore.kernel.org/lkml/CAObL_7GM0n80N7J_DFw_eQyfLyzq+sf4y2AvsCCV88Tb3AwEHA@mail.gmail.com/
---
Notes:
v9:
* Rebased to linux-next again due to syscall_get_arguments() signature change.
v8:
* Moved syscall_get_arch() specific patches to a separate patchset
which is now merged into audit/next tree.
* Rebased to linux-next.
* Moved ptrace_get_syscall_info code under #ifdef CONFIG_HAVE_ARCH_TRACEHOOK,
narrowing down the set of architectures supported by this implementation
back to those 19 that enable CONFIG_HAVE_ARCH_TRACEHOOK because
I failed to get all syscall_get_*(), instruction_pointer(),
and user_stack_pointer() functions implemented on some niche
architectures. This leaves the following architectures out:
alpha, h8300, m68k, microblaze, and unicore32.
v7:
* Rebased to v5.0-rc1.
* 5 arch-specific preparatory patches out of 25 have been merged
into v5.0-rc1 via arch trees.
v6:
* Add syscall_get_arguments and syscall_set_arguments wrappers
to asm-generic/syscall.h, requested by Geert.
* Change PTRACE_GET_SYSCALL_INFO return code: do not take trailing paddings
into account, use the end of the last field of the structure being written.
* Change struct ptrace_syscall_info:
* remove .frame_pointer field, is is not needed and not portable;
* make .arch field explicitly aligned, remove no longer needed
padding before .arch field;
* remove trailing pads, they are no longer needed.
v5:
* Merge separate series and patches into the single series.
* Change PTRACE_EVENTMSG_SYSCALL_{ENTRY,EXIT} values as requested by Oleg.
* Change struct ptrace_syscall_info: generalize instruction_pointer,
stack_pointer, and frame_pointer fields by moving them from
ptrace_syscall_info.{entry,seccomp} substructures to ptrace_syscall_info
and initializing them for all stops.
* Add PTRACE_SYSCALL_INFO_NONE, set it when not in a syscall stop,
so e.g. "strace -i" could use PTRACE_SYSCALL_INFO_SECCOMP to obtain
instruction_pointer when the tracee is in a signal stop.
* Patch all remaining architectures to provide all necessary
syscall_get_* functions.
* Make available for all architectures: do not conditionalize on
CONFIG_HAVE_ARCH_TRACEHOOK since all syscall_get_* functions
are implemented on all architectures.
* Add a test for PTRACE_GET_SYSCALL_INFO to selftests/ptrace.
v4:
* Do not introduce task_struct.ptrace_event,
use child->last_siginfo->si_code instead.
* Implement PTRACE_SYSCALL_INFO_SECCOMP and ptrace_syscall_info.seccomp
support along with PTRACE_SYSCALL_INFO_{ENTRY,EXIT} and
ptrace_syscall_info.{entry,exit}.
v3:
* Change struct ptrace_syscall_info.
* Support PTRACE_EVENT_SECCOMP by adding ptrace_event to task_struct.
* Add proper defines for ptrace_syscall_info.op values.
* Rename PT_SYSCALL_IS_ENTERING and PT_SYSCALL_IS_EXITING to
PTRACE_EVENTMSG_SYSCALL_ENTRY and PTRACE_EVENTMSG_SYSCALL_EXIT
* and move them to uapi.
v2:
* Do not use task->ptrace.
* Replace entry_info.is_compat with entry_info.arch, use syscall_get_arch().
* Use addr argument of sys_ptrace to get expected size of the struct;
return full size of the struct.
Dmitry V. Levin (6):
nds32: fix asm/syscall.h # waiting for ack since early January
hexagon: define syscall_get_error() and syscall_get_return_value() # waiting for ack since November
mips: define syscall_get_error() # acked
parisc: define syscall_get_error() # acked
powerpc: define syscall_get_error() # waiting for ack since early December
selftests/ptrace: add a test case for PTRACE_GET_SYSCALL_INFO
Elvira Khabirova (1):
ptrace: add PTRACE_GET_SYSCALL_INFO request # reviewed
arch/hexagon/include/asm/syscall.h | 14 +
arch/mips/include/asm/syscall.h | 6 +
arch/nds32/include/asm/syscall.h | 27 +-
arch/parisc/include/asm/syscall.h | 7 +
arch/powerpc/include/asm/syscall.h | 10 +
include/linux/tracehook.h | 9 +-
include/uapi/linux/ptrace.h | 35 +++
kernel/ptrace.c | 103 ++++++-
tools/testing/selftests/ptrace/.gitignore | 1 +
tools/testing/selftests/ptrace/Makefile | 2 +-
.../selftests/ptrace/get_syscall_info.c | 271 ++++++++++++++++++
11 files changed, 470 insertions(+), 15 deletions(-)
create mode 100644 tools/testing/selftests/ptrace/get_syscall_info.c
--
ldv
^ permalink raw reply
* Re: [PATCH V1] ASoC: fsl_esai: replace fall-through with break
From: Gustavo A. R. Silva @ 2019-04-08 15:55 UTC (permalink / raw)
To: S.j. Wang, timur@kernel.org, nicoleotsuka@gmail.com,
Xiubo.Lee@gmail.com, festevam@gmail.com, broonie@kernel.org,
alsa-devel@alsa-project.org
Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <66c117128f300b0ec5f278f538412789c78b60a6.1554715589.git.shengjiu.wang@nxp.com>
On 4/8/19 4:28 AM, S.j. Wang wrote:
> case ESAI_HCKT_EXTAL and case ESAI_HCKR_EXTAL should be independent of
> each other, so replace fall-through with break.
>
If this is correct, then you should use the following "Fixes" tag instead,
which is the one that introduced the bug:
Fixes: 43d24e76b698 ("ASoC: fsl_esai: Add ESAI CPU DAI driver")
> Fixes: 16bbeb2b43c3 ("ASoC: fsl_esai: Mark expected switch fall-through")
>
^^^^
because this didn't change any functionality.
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> ---
> sound/soc/fsl/fsl_esai.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
> index c7410bbfd2af..bad0dfed6b68 100644
> --- a/sound/soc/fsl/fsl_esai.c
> +++ b/sound/soc/fsl/fsl_esai.c
> @@ -251,7 +251,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
> break;
> case ESAI_HCKT_EXTAL:
> ecr |= ESAI_ECR_ETI;
Also, you should use a simple assignment operator "=" instead of "|=" in both cases.
> - /* fall through */
> + break;
> case ESAI_HCKR_EXTAL:
> ecr |= esai_priv->synchronous ? ESAI_ECR_ETI : ESAI_ECR_ERI;
> break;
>
Thanks
--
Gustavo
^ permalink raw reply
* Re: [PATCH v2] fs/dax: deposit pagetable even when installing zero page
From: Dan Williams @ 2019-04-08 15:54 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Jan Kara, linux-nvdimm, Linux MM, Alexander Viro, Ross Zwisler,
linux-fsdevel, Andrew Morton, linuxppc-dev
In-Reply-To: <87r2acn8eq.fsf@linux.ibm.com>
On Mon, Apr 8, 2019 at 2:39 AM Aneesh Kumar K.V
<aneesh.kumar@linux.ibm.com> wrote:
>
>
> Hi Dan,
>
> Dan Williams <dan.j.williams@intel.com> writes:
>
> > On Wed, Mar 13, 2019 at 2:58 AM Jan Kara <jack@suse.cz> wrote:
> >>
> >> On Wed 13-03-19 10:17:17, Aneesh Kumar K.V wrote:
> >> >
> >> > Hi Dan/Andrew/Jan,
> >> >
> >> > "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com> writes:
> >> >
> >> > > Architectures like ppc64 use the deposited page table to store hardware
> >> > > page table slot information. Make sure we deposit a page table when
> >> > > using zero page at the pmd level for hash.
> >> > >
> >> > > Without this we hit
> >> > >
> >> > > Unable to handle kernel paging request for data at address 0x00000000
> >> > > Faulting instruction address: 0xc000000000082a74
> >> > > Oops: Kernel access of bad area, sig: 11 [#1]
> >> > > ....
> >> > >
> >> > > NIP [c000000000082a74] __hash_page_thp+0x224/0x5b0
> >> > > LR [c0000000000829a4] __hash_page_thp+0x154/0x5b0
> >> > > Call Trace:
> >> > > hash_page_mm+0x43c/0x740
> >> > > do_hash_page+0x2c/0x3c
> >> > > copy_from_iter_flushcache+0xa4/0x4a0
> >> > > pmem_copy_from_iter+0x2c/0x50 [nd_pmem]
> >> > > dax_copy_from_iter+0x40/0x70
> >> > > dax_iomap_actor+0x134/0x360
> >> > > iomap_apply+0xfc/0x1b0
> >> > > dax_iomap_rw+0xac/0x130
> >> > > ext4_file_write_iter+0x254/0x460 [ext4]
> >> > > __vfs_write+0x120/0x1e0
> >> > > vfs_write+0xd8/0x220
> >> > > SyS_write+0x6c/0x110
> >> > > system_call+0x3c/0x130
> >> > >
> >> > > Fixes: b5beae5e224f ("powerpc/pseries: Add driver for PAPR SCM regions")
> >> > > Reviewed-by: Jan Kara <jack@suse.cz>
> >> > > Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
> >> >
> >> > Any suggestion on which tree this patch should got to? Also since this
> >> > fix a kernel crash, we may want to get this to 5.1?
> >>
> >> I think this should go through Dan's tree...
> >
> > I'll merge this and let it soak in -next for a week and then submit for 5.1-rc2.
>
> Any update on this? Did you get to merge this?
Thanks for the reminder. Will send this week along with some other
libnvdimm related fixes.
^ permalink raw reply
* [PATCH RFC/RFT 4/6] clk: mux: make endian aware
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
Switch clk-mux to the endianness aware accessors to allow big endian
mux clocks on a per device level.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
drivers/clk/clk-mux.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 2ad2df2e8909..4a02db06eb29 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -73,7 +73,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
struct clk_mux *mux = to_clk_mux(hw);
u32 val;
- val = clk_readl(mux->reg) >> mux->shift;
+ val = clk_hw_readl(hw, mux->reg) >> mux->shift;
val &= mux->mask;
return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
@@ -94,12 +94,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->flags & CLK_MUX_HIWORD_MASK) {
reg = mux->mask << (mux->shift + 16);
} else {
- reg = clk_readl(mux->reg);
+ reg = clk_hw_readl(hw, mux->reg);
reg &= ~(mux->mask << mux->shift);
}
val = val << mux->shift;
reg |= val;
- clk_writel(reg, mux->reg);
+ clk_hw_writel(hw, reg, mux->reg);
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
--
2.13.2
^ permalink raw reply related
* [PATCH RFC/RFT 6/6] clk: core: remove powerpc special handling
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
Now that the powerpc clocks are properly marked as big endian, we can
remove the special handling for PowerPC.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
include/linux/clk-provider.h | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 2c7c17652d75..6755befb6cee 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -999,20 +999,6 @@ static inline int of_clk_detect_critical(struct device_node *np, int index,
* for improved portability across platforms
*/
-#if IS_ENABLED(CONFIG_PPC)
-
-static inline u32 clk_readl(u32 __iomem *reg)
-{
- return ioread32be(reg);
-}
-
-static inline void clk_writel(u32 val, u32 __iomem *reg)
-{
- iowrite32be(val, reg);
-}
-
-#else /* platform dependent I/O accessors */
-
static inline u32 clk_readl(u32 __iomem *reg)
{
return readl(reg);
@@ -1023,8 +1009,6 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
writel(val, reg);
}
-#endif /* platform dependent I/O accessors */
-
static inline u32 clk_readl_be(u32 __iomem *reg)
{
return ioread32be(reg);
--
2.13.2
^ permalink raw reply related
* [PATCH RFC/RFT 1/6] clk: core: add support for generic big endian accesses
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
Add a generic flag to mark a clock as big endian register based, and add
accessors following these.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
drivers/clk/clk.c | 1 +
include/linux/clk-provider.h | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 96053a96fe2f..b706022bb83d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2859,6 +2859,7 @@ static const struct {
ENTRY(CLK_IS_CRITICAL),
ENTRY(CLK_OPS_PARENT_ENABLE),
ENTRY(CLK_DUTY_CYCLE_PARENT),
+ ENTRY(CLK_IS_BIG_ENDIAN),
#undef ENTRY
};
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b7cf80a71293..2c7c17652d75 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -35,6 +35,7 @@
#define CLK_OPS_PARENT_ENABLE BIT(12)
/* duty cycle call may be forwarded to the parent clock */
#define CLK_DUTY_CYCLE_PARENT BIT(13)
+#define CLK_IS_BIG_ENDIAN BIT(14) /* clk registers are big endian */
struct clk;
struct clk_hw;
@@ -1024,6 +1025,32 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
#endif /* platform dependent I/O accessors */
+static inline u32 clk_readl_be(u32 __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
+static inline void clk_writel_be(u32 val, u32 __iomem *reg)
+{
+ iowrite32be(val, reg);
+}
+
+static inline u32 clk_hw_readl(struct clk_hw *clk, u32 __iomem *reg)
+{
+ if (clk_hw_get_flags(clk) & CLK_IS_BIG_ENDIAN)
+ return clk_readl_be(reg);
+ else
+ return clk_readl(reg);
+}
+
+static inline void clk_hw_writel(struct clk_hw *clk, u32 val, u32 __iomem *reg)
+{
+ if (clk_hw_get_flags(clk) & CLK_IS_BIG_ENDIAN)
+ clk_writel_be(val, reg);
+ else
+ clk_writel(val, reg);
+}
+
void clk_gate_restore_context(struct clk_hw *hw);
#endif /* CONFIG_COMMON_CLK */
--
2.13.2
^ permalink raw reply related
* [PATCH RFC/RFT 2/6] clk: gate: make endian-aware
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
Switch clk-gate to the endianness aware accessors to allow big endian
gated clocks on a per device level.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
drivers/clk/clk-gate.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index f05823cd9b21..0e585ac133c7 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -55,7 +55,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (set)
reg |= BIT(gate->bit_idx);
} else {
- reg = clk_readl(gate->reg);
+ reg = clk_hw_readl(hw, gate->reg);
if (set)
reg |= BIT(gate->bit_idx);
@@ -63,7 +63,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
reg &= ~BIT(gate->bit_idx);
}
- clk_writel(reg, gate->reg);
+ clk_hw_writel(hw, reg, gate->reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
@@ -88,7 +88,7 @@ int clk_gate_is_enabled(struct clk_hw *hw)
u32 reg;
struct clk_gate *gate = to_clk_gate(hw);
- reg = clk_readl(gate->reg);
+ reg = clk_hw_readl(hw, gate->reg);
/* if a set bit disables this clk, flip it before masking */
if (gate->flags & CLK_GATE_SET_TO_DISABLE)
--
2.13.2
^ permalink raw reply related
* [PATCH RFC/RFT 0/6] clk: make register endianness a run-time property
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
Currently the endianness for register accesses of basic clocks if fixed
based on the architecture (BE for PowerPC, LE for everyone else). This
is inconvenient for architectures that support both.
To avoid adding more rules to the #ifdef, this patchset adds a new
generic flag to tag the registers as BE and makes the basic clocks
follow it, then converts the only PowerPC user to use it.
That way we can drop the special casing for PowerPC, and allow other BE
platforms/drivers to make use of the basic clocks.
RFC because I am unsure if this should be common flag or a per-clock
flag.
Technically it's the wrong place for the former, but having a different
flag for each basic clock looks a bit messy IMHO. This could also lead
to easy mistakes by using the "wrong" basic clock's flag, then having no
or unexpected effects due to the next free flag bit different for each
basic clock. This might be avoidable by using a free bit common to all,
e.g. the highest bit of the flag fields.
I don't have any strong feelings one way or the other. I just used this
way because I needed to start somewhere ;-).
RFT because I don't have a PowerPC device to test, and especially not a
512x one. I did compile test it though!
I looked really hard, and this is the only place I could find where a
PowerPC platform (indirectly) used the clk accessors.
None of the regular drivers in clk/ were selected in any of the powerpc
defconfigs, and this was the only platform code that registered basic
clocks.
Jonas Gorski (6):
clk: core: add support for generic big endian accesses
clk: gate: make endian-aware
clk: divider: make endian aware
clk: mux: make endian aware
powerpc/512x: mark clocks as big endian
clk: core: remove powerpc special handling
arch/powerpc/platforms/512x/clock-commonclk.c | 13 ++++++-----
drivers/clk/clk-divider.c | 8 +++----
drivers/clk/clk-gate.c | 6 +++---
drivers/clk/clk-mux.c | 6 +++---
drivers/clk/clk.c | 1 +
include/linux/clk-provider.h | 31 ++++++++++++++++++---------
6 files changed, 40 insertions(+), 25 deletions(-)
--
2.13.2
^ permalink raw reply
* [PATCH RFC/RFT 3/6] clk: divider: make endian aware
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
Switch clk-divider to the endianness aware accessors to allow big endian
divider clocks on a per device level.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
drivers/clk/clk-divider.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index e5a17265cfaf..63cb8617a007 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -135,7 +135,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
unsigned int val;
- val = clk_readl(divider->reg) >> divider->shift;
+ val = clk_hw_readl(hw, divider->reg) >> divider->shift;
val &= clk_div_mask(divider->width);
return divider_recalc_rate(hw, parent_rate, val, divider->table,
@@ -370,7 +370,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
u32 val;
- val = clk_readl(divider->reg) >> divider->shift;
+ val = clk_hw_readl(hw, divider->reg) >> divider->shift;
val &= clk_div_mask(divider->width);
return divider_ro_round_rate(hw, rate, prate, divider->table,
@@ -420,11 +420,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = clk_div_mask(divider->width) << (divider->shift + 16);
} else {
- val = clk_readl(divider->reg);
+ val = clk_hw_readl(hw, divider->reg);
val &= ~(clk_div_mask(divider->width) << divider->shift);
}
val |= (u32)value << divider->shift;
- clk_writel(val, divider->reg);
+ clk_hw_writel(hw, val, divider->reg);
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
--
2.13.2
^ permalink raw reply related
* [PATCH RFC/RFT 5/6] powerpc/512x: mark clocks as big endian
From: Jonas Gorski @ 2019-04-08 10:20 UTC (permalink / raw)
To: linux-clk, linuxppc-dev
Cc: Stephen Boyd, Michael Turquette, Paul Mackerras,
Anatolij Gustschin
In-Reply-To: <20190408102039.6366-1-jonas.gorski@gmail.com>
These clocks' registers are accessed as big endian, so mark them as
such.
Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
arch/powerpc/platforms/512x/clock-commonclk.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
index b3097fe6441b..af86a65128f1 100644
--- a/arch/powerpc/platforms/512x/clock-commonclk.c
+++ b/arch/powerpc/platforms/512x/clock-commonclk.c
@@ -239,8 +239,9 @@ static inline struct clk *mpc512x_clk_divider(
const char *name, const char *parent_name, u8 clkflags,
u32 __iomem *reg, u8 pos, u8 len, int divflags)
{
- return clk_register_divider(NULL, name, parent_name, clkflags,
- reg, pos, len, divflags, &clklock);
+ return clk_register_divider(NULL, name, parent_name,
+ clkflags | CLK_IS_BIG_ENDIAN, reg, pos, len,
+ divflags, &clklock);
}
static inline struct clk *mpc512x_clk_divtable(
@@ -248,10 +249,12 @@ static inline struct clk *mpc512x_clk_divtable(
u32 __iomem *reg, u8 pos, u8 len,
const struct clk_div_table *divtab)
{
+ int clkflags;
u8 divflags;
+ clkflags = CLK_IS_BIG_ENDIAN;
divflags = 0;
- return clk_register_divider_table(NULL, name, parent_name, 0,
+ return clk_register_divider_table(NULL, name, parent_name, clkflags,
reg, pos, len, divflags,
divtab, &clklock);
}
@@ -262,7 +265,7 @@ static inline struct clk *mpc512x_clk_gated(
{
int clkflags;
- clkflags = CLK_SET_RATE_PARENT;
+ clkflags = CLK_SET_RATE_PARENT | CLK_IS_BIG_ENDIAN;
return clk_register_gate(NULL, name, parent_name, clkflags,
reg, pos, 0, &clklock);
}
@@ -274,7 +277,7 @@ static inline struct clk *mpc512x_clk_muxed(const char *name,
int clkflags;
u8 muxflags;
- clkflags = CLK_SET_RATE_PARENT;
+ clkflags = CLK_SET_RATE_PARENT | CLK_IS_BIG_ENDIAN;
muxflags = 0;
return clk_register_mux(NULL, name,
parent_names, parent_count, clkflags,
--
2.13.2
^ permalink raw reply related
* Re: [PATCH v2 1/2] cpuidle : auto-promotion for cpuidle states
From: Daniel Axtens @ 2019-04-08 14:25 UTC (permalink / raw)
To: Abhishek Goel, linux-kernel, linuxppc-dev, linux-pm
Cc: Abhishek Goel, daniel.lezcano, rjw, ego
In-Reply-To: <20190405091647.4169-2-huntbag@linux.vnet.ibm.com>
Hi,
Sorry, just realised another thing I wanted to ask:
> @@ -442,6 +442,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
> }
> }
>
>
> +#ifdef CPUIDLE_FLAG_AUTO_PROMOTION
Why is this based on CPUIDLE_FLAG_ rather than CONFIG_CPU_IDLE_? Won't
this always be true, given that the flag is defined regardless of the
config option in the header?
> + if (drv->states[idx].flags & CPUIDLE_FLAG_AUTO_PROMOTION) {
> + /*
> + * Timeout is intended to be defined as sum of target residency
> + * of next available state, entry latency and exit latency. If
> + * time interval equal to timeout is spent in current state,
> + * and if it is a shallow lite state, we may want to auto-
> + * promote from such state.
> + */
Regards,
Daniel
> + for (i = idx + 1; i < drv->state_count; i++) {
> + if (drv->states[i].disabled ||
> + dev->states_usage[i].disable)
> + continue;
> + *timeout = drv->states[i].target_residency +
> + 2 * drv->states[i].exit_latency;
> + break;
> + }
> + }
> +#endif
> +
> return idx;
> }
>
> diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
> index 3b3947232..84d76d1ec 100644
> --- a/include/linux/cpuidle.h
> +++ b/include/linux/cpuidle.h
> @@ -72,6 +72,13 @@ struct cpuidle_state {
> #define CPUIDLE_FLAG_POLLING BIT(0) /* polling state */
> #define CPUIDLE_FLAG_COUPLED BIT(1) /* state applies to multiple cpus */
> #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
> +/*
> + * State with only and only fast state bit set don't even lose user context.
> + * But such states prevent other sibling threads from thread folding benefits.
> + * And hence we don't want to stay for too long in such states and want to
> + * auto-promote from it.
> + */
> +#define CPUIDLE_FLAG_AUTO_PROMOTION BIT(3)
>
> struct cpuidle_device_kobj;
> struct cpuidle_state_kobj;
> @@ -243,7 +250,8 @@ struct cpuidle_governor {
>
> int (*select) (struct cpuidle_driver *drv,
> struct cpuidle_device *dev,
> - bool *stop_tick);
> + bool *stop_tick, unsigned long
> + *timeout);
> void (*reflect) (struct cpuidle_device *dev, int index);
> };
>
> --
> 2.17.1
^ permalink raw reply
* Re: [PATCH v2 2/2] cpuidle : Add auto-promotion flag to cpuidle flags
From: Daniel Axtens @ 2019-04-08 14:22 UTC (permalink / raw)
To: Abhishek Goel, linux-kernel, linuxppc-dev, linux-pm
Cc: Abhishek Goel, daniel.lezcano, rjw, ego
In-Reply-To: <20190405091647.4169-3-huntbag@linux.vnet.ibm.com>
Abhishek Goel <huntbag@linux.vnet.ibm.com> writes:
> This patch sets up flags for the state which needs to be auto-promoted. On
> POWERNV system, only lite states need to be autopromoted. We identify lite
> states by those which do not lose user context. That information has been
> used to set the flag for lite states.
>
> Signed-off-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/opal-api.h | 1 +
> drivers/cpuidle/Kconfig | 4 ++++
> drivers/cpuidle/cpuidle-powernv.c | 13 +++++++++++--
> 3 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
> index 870fb7b23..735dec731 100644
> --- a/arch/powerpc/include/asm/opal-api.h
> +++ b/arch/powerpc/include/asm/opal-api.h
> @@ -226,6 +226,7 @@
> */
>
> #define OPAL_PM_TIMEBASE_STOP 0x00000002
> +#define OPAL_PM_LOSE_USER_CONTEXT 0x00001000
Is the important thing that you don't lose user context, or that the
state prevents thread folding? From your description, it seems from a
power managment point of view that the important thing is that the state
prevents thread folding, and it seems almost coincidental that it
preserves user context.
If this is mirrored from the way hardware or opal describes it (which
looking at the other flags it looks like it might be), it would be worth
adding a comment that explains why we want to leave such a state.
> #define OPAL_PM_LOSE_HYP_CONTEXT 0x00002000
> #define OPAL_PM_LOSE_FULL_CONTEXT 0x00004000
> #define OPAL_PM_NAP_ENABLED 0x00010000
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index 8caccbbd7..9b8e9b96a 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -35,6 +35,10 @@ config CPU_IDLE_GOV_TEO
> config DT_IDLE_STATES
> bool
>
> +config CPU_IDLE_AUTO_PROMOTION
> + bool
> + default y if PPC_POWERNV
> +
As I mentioned in the previous patch, this is used in the previous
patch. It's also not used here.
Regards,
Daniel
> menu "ARM CPU Idle Drivers"
> depends on ARM || ARM64
> source "drivers/cpuidle/Kconfig.arm"
> diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
> index 84b1ebe21..0dd767270 100644
> --- a/drivers/cpuidle/cpuidle-powernv.c
> +++ b/drivers/cpuidle/cpuidle-powernv.c
> @@ -299,6 +299,7 @@ static int powernv_add_idle_states(void)
> for (i = 0; i < dt_idle_states; i++) {
> unsigned int exit_latency, target_residency;
> bool stops_timebase = false;
> + bool lose_user_context = false;
> struct pnv_idle_states_t *state = &pnv_idle_states[i];
>
> /*
> @@ -324,6 +325,9 @@ static int powernv_add_idle_states(void)
> if (has_stop_states && !(state->valid))
> continue;
>
> + if (state->flags & OPAL_PM_LOSE_USER_CONTEXT)
> + lose_user_context = true;
> +
> if (state->flags & OPAL_PM_TIMEBASE_STOP)
> stops_timebase = true;
>
> @@ -332,12 +336,17 @@ static int powernv_add_idle_states(void)
> add_powernv_state(nr_idle_states, "Nap",
> CPUIDLE_FLAG_NONE, nap_loop,
> target_residency, exit_latency, 0, 0);
> + } else if (has_stop_states && !lose_user_context) {
> + add_powernv_state(nr_idle_states, state->name,
> + CPUIDLE_FLAG_AUTO_PROMOTION,
> + stop_loop, target_residency,
> + exit_latency, state->psscr_val,
> + state->psscr_mask);
> } else if (has_stop_states && !stops_timebase) {
> add_powernv_state(nr_idle_states, state->name,
> CPUIDLE_FLAG_NONE, stop_loop,
> target_residency, exit_latency,
> - state->psscr_val,
> - state->psscr_mask);
> + state->psscr_val, state->psscr_mask);
> }
>
> /*
> --
> 2.17.1
^ permalink raw reply
* Re: [PATCH v2 1/2] cpuidle : auto-promotion for cpuidle states
From: Daniel Axtens @ 2019-04-08 14:12 UTC (permalink / raw)
To: Abhishek Goel, linux-kernel, linuxppc-dev, linux-pm
Cc: Abhishek Goel, daniel.lezcano, rjw, ego
In-Reply-To: <20190405091647.4169-2-huntbag@linux.vnet.ibm.com>
Hi Abhishek,
> Currently, the cpuidle governors (menu /ladder) determine what idle state
> an idling CPU should enter into based on heuristics that depend on the
> idle history on that CPU. Given that no predictive heuristic is perfect,
> there are cases where the governor predicts a shallow idle state, hoping
> that the CPU will be busy soon. However, if no new workload is scheduled
> on that CPU in the near future, the CPU will end up in the shallow state.
>
> In case of POWER, this is problematic, when the predicted state in the
> aforementioned scenario is a lite stop state, as such lite states will
> inhibit SMT folding, thereby depriving the other threads in the core from
> using the core resources.
>
> To address this, such lite states need to be autopromoted. The cpuidle-
> core can queue timer to correspond with the residency value of the next
> available state. Thus leading to auto-promotion to a deeper idle state as
> soon as possible.
>
This sounds sensible to me, although I'm not really qualified to offer a
full power-management opinion on it. I have some general code questions
and comments, however, which are below:
> Signed-off-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
> ---
>
> v1->v2 : Removed timeout_needed and rebased to current upstream kernel
>
> drivers/cpuidle/cpuidle.c | 68 +++++++++++++++++++++++++++++-
> drivers/cpuidle/governors/ladder.c | 3 +-
> drivers/cpuidle/governors/menu.c | 22 +++++++++-
> include/linux/cpuidle.h | 10 ++++-
> 4 files changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
> index 7f108309e..11ce43f19 100644
> --- a/drivers/cpuidle/cpuidle.c
> +++ b/drivers/cpuidle/cpuidle.c
> @@ -36,6 +36,11 @@ static int enabled_devices;
> static int off __read_mostly;
> static int initialized __read_mostly;
>
> +struct auto_promotion {
> + struct hrtimer hrtimer;
> + unsigned long timeout_us;
> +};
> +
> int cpuidle_disabled(void)
> {
> return off;
> @@ -188,6 +193,54 @@ int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev)
> }
> #endif /* CONFIG_SUSPEND */
>
> +enum hrtimer_restart auto_promotion_hrtimer_callback(struct hrtimer *hrtimer)
> +{
> + return HRTIMER_NORESTART;
> +}
> +
> +#ifdef CONFIG_CPU_IDLE_AUTO_PROMOTION
As far as I can tell, this config flag isn't defined until the next
patch, making this dead code for now. Is this intentional?
> +DEFINE_PER_CPU(struct auto_promotion, ap);
A quick grep suggests that most per-cpu variable have more descriptive
names, perhaps this one should too.
> +
> +static void cpuidle_auto_promotion_start(int cpu, struct cpuidle_state *state)
> +{
> + struct auto_promotion *this_ap = &per_cpu(ap, cpu);
> +
> + if (state->flags & CPUIDLE_FLAG_AUTO_PROMOTION)
> + hrtimer_start(&this_ap->hrtimer, ns_to_ktime(this_ap->timeout_us
> + * 1000), HRTIMER_MODE_REL_PINNED);
Would it be clearer to have both sides of the multiplication on the same
line? i.e.
+ hrtimer_start(&this_ap->hrtimer,
+ ns_to_ktime(this_ap->timeout_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
> +}
> +
> +static void cpuidle_auto_promotion_cancel(int cpu)
> +{
> + struct hrtimer *hrtimer;
> +
> + hrtimer = &per_cpu(ap, cpu).hrtimer;
> + if (hrtimer_is_queued(hrtimer))
> + hrtimer_cancel(hrtimer);
> +}
> +
> +static void cpuidle_auto_promotion_update(int cpu, unsigned long timeout)
> +{
> + per_cpu(ap, cpu).timeout_us = timeout;
> +}
> +
> +static void cpuidle_auto_promotion_init(int cpu, struct cpuidle_driver *drv)
> +{
> + struct auto_promotion *this_ap = &per_cpu(ap, cpu);
> +
> + hrtimer_init(&this_ap->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + this_ap->hrtimer.function = auto_promotion_hrtimer_callback;
> +}
> +#else
> +static inline void cpuidle_auto_promotion_start(int cpu, struct cpuidle_state
> + *state) { }
> +static inline void cpuidle_auto_promotion_cancel(int cpu) { }
> +static inline void cpuidle_auto_promotion_update(int cpu, unsigned long
> + timeout) { }
> +static inline void cpuidle_auto_promotion_init(int cpu, struct cpuidle_driver
> + *drv) { }
Several of these have the type, then a line break, and then the name
(unsigned long\n timeout). This is a bit harder to read, they should
probably all be on the same line.
> +#endif
> +
> /**
> * cpuidle_enter_state - enter the state and update stats
> * @dev: cpuidle device for this cpu
> @@ -225,12 +278,17 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
> trace_cpu_idle_rcuidle(index, dev->cpu);
> time_start = ns_to_ktime(local_clock());
>
> + cpuidle_auto_promotion_start(dev->cpu, target_state);
> +
> stop_critical_timings();
> entered_state = target_state->enter(dev, drv, index);
> start_critical_timings();
>
> sched_clock_idle_wakeup_event();
> time_end = ns_to_ktime(local_clock());
> +
> + cpuidle_auto_promotion_cancel(dev->cpu);
> +
> trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
>
> /* The cpu is no longer idle or about to enter idle. */
> @@ -312,7 +370,13 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
> int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
> bool *stop_tick)
> {
> - return cpuidle_curr_governor->select(drv, dev, stop_tick);
> + unsigned long timeout_us, ret;
> +
> + timeout_us = UINT_MAX;
> + ret = cpuidle_curr_governor->select(drv, dev, stop_tick, &timeout_us);
> + cpuidle_auto_promotion_update(dev->cpu, timeout_us);
> +
> + return ret;
> }
>
> /**
> @@ -658,6 +722,8 @@ int cpuidle_register(struct cpuidle_driver *drv,
> device = &per_cpu(cpuidle_dev, cpu);
> device->cpu = cpu;
>
> + cpuidle_auto_promotion_init(cpu, drv);
> +
> #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
> /*
> * On multiplatform for ARM, the coupled idle states could be
> diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
> index f0dddc66a..65b518dd7 100644
> --- a/drivers/cpuidle/governors/ladder.c
> +++ b/drivers/cpuidle/governors/ladder.c
> @@ -64,7 +64,8 @@ static inline void ladder_do_selection(struct ladder_device *ldev,
> * @dummy: not used
I think you need an addition to the docstring for your new variable.
> */
> static int ladder_select_state(struct cpuidle_driver *drv,
> - struct cpuidle_device *dev, bool *dummy)
> + struct cpuidle_device *dev, bool *dummy,
> + unsigned long *unused)
> {
> struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
> struct ladder_device_state *last_state;
> diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
> index 5951604e7..835e337de 100644
> --- a/drivers/cpuidle/governors/menu.c
> +++ b/drivers/cpuidle/governors/menu.c
> @@ -276,7 +276,7 @@ static unsigned int get_typical_interval(struct menu_device *data,
> * @stop_tick: indication on whether or not to stop the tick
Likewise here.
> */
> static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
> - bool *stop_tick)
> + bool *stop_tick, unsigned long *timeout)
> {
> struct menu_device *data = this_cpu_ptr(&menu_devices);
> int latency_req = cpuidle_governor_latency_req(dev->cpu);
> @@ -442,6 +442,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
> }
> }
>
> +#ifdef CPUIDLE_FLAG_AUTO_PROMOTION
> + if (drv->states[idx].flags & CPUIDLE_FLAG_AUTO_PROMOTION) {
> + /*
> + * Timeout is intended to be defined as sum of target residency
> + * of next available state, entry latency and exit latency. If
> + * time interval equal to timeout is spent in current state,
> + * and if it is a shallow lite state, we may want to auto-
> + * promote from such state.
This comment makes sense if you already understand auto-promotion. That's
fair enough - you wrote it and you presumably understand what your code
does :) But for me it's a bit confusing! I think you want to start with
a sentence about what autopromotion is (preferably not using
power-specific terminology) and then explain the calculation of the
timeouts.
> + */
> + for (i = idx + 1; i < drv->state_count; i++) {
> + if (drv->states[i].disabled ||
> + dev->states_usage[i].disable)
> + continue;
> + *timeout = drv->states[i].target_residency +
> + 2 * drv->states[i].exit_latency;
> + break;
> + }
> + }
> +#endif
> +
> return idx;
> }
>
> diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
> index 3b3947232..84d76d1ec 100644
> --- a/include/linux/cpuidle.h
> +++ b/include/linux/cpuidle.h
> @@ -72,6 +72,13 @@ struct cpuidle_state {
> #define CPUIDLE_FLAG_POLLING BIT(0) /* polling state */
> #define CPUIDLE_FLAG_COUPLED BIT(1) /* state applies to multiple cpus */
> #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
> +/*
> + * State with only and only fast state bit set don't even lose user context.
"only and only"?
> + * But such states prevent other sibling threads from thread folding benefits.
> + * And hence we don't want to stay for too long in such states and want to
> + * auto-promote from it.
I think this comment mixes Power-specific and generic concepts. (But I'm
not a PM expert so tell me if I'm wrong here.) I think, if I've
understood correctly: in the generic code, the bit represents a state
that we do not want to linger in, which we want to definitely leave
after some time. On Power, we have a state that doesn't lose user
context but which prevents thread folding, so this is an example of a
state where we want to auto-promote.
> + */
> +#define CPUIDLE_FLAG_AUTO_PROMOTION BIT(3)
>
> struct cpuidle_device_kobj;
> struct cpuidle_state_kobj;
> @@ -243,7 +250,8 @@ struct cpuidle_governor {
>
> int (*select) (struct cpuidle_driver *drv,
> struct cpuidle_device *dev,
> - bool *stop_tick);
> + bool *stop_tick, unsigned long
> + *timeout);
> void (*reflect) (struct cpuidle_device *dev, int index);
> };
>
> --
> 2.17.1
^ permalink raw reply
* [PATCH v2 3/3] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Aneesh Kumar K.V @ 2019-04-08 13:19 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe, Christophe Leroy
Cc: Aneesh Kumar K.V, linuxppc-dev
In-Reply-To: <20190408131934.27959-1-aneesh.kumar@linux.ibm.com>
Currently, our mm_context_t on book3s64 include all hash specific
context details like slice mask and subpage protection details. We
can skip allocating these with radix translation. This will help us to save
8K per mm_context with radix translation.
With the patch applied we have
sizeof(mm_context_t) = 136
sizeof(struct hash_mm_context) = 8288
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 33 ++++++++++++-
arch/powerpc/include/asm/book3s/64/mmu.h | 49 +++++--------------
arch/powerpc/kernel/setup-common.c | 6 +++
arch/powerpc/mm/hash_utils_64.c | 4 +-
arch/powerpc/mm/mmu_context_book3s64.c | 16 +++++-
5 files changed, 68 insertions(+), 40 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index eb36fbfe4ef5..4481bedbb5be 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -658,7 +658,7 @@ extern void slb_set_size(u16 size);
/* 4 bits per slice and we have one slice per 1TB */
#define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
#define LOW_SLICE_ARRAY_SZ (BITS_PER_LONG / BITS_PER_BYTE)
-#define TASK_SLICE_ARRAY_SZ(x) ((x)->slb_addr_limit >> 41)
+#define TASK_SLICE_ARRAY_SZ(x) ((x)->hash_context->slb_addr_limit >> 41)
#ifndef __ASSEMBLY__
#ifdef CONFIG_PPC_SUBPAGE_PROT
@@ -693,6 +693,37 @@ static inline void subpage_prot_free(struct mm_struct *mm) {}
static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
#endif /* CONFIG_PPC_SUBPAGE_PROT */
+/*
+ * One bit per slice. We have lower slices which cover 256MB segments
+ * upto 4G range. That gets us 16 low slices. For the rest we track slices
+ * in 1TB size.
+ */
+struct slice_mask {
+ u64 low_slices;
+ DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
+};
+
+struct hash_mm_context {
+ u16 user_psize; /* page size index */
+
+ /* SLB page size encodings*/
+ unsigned char low_slices_psize[LOW_SLICE_ARRAY_SZ];
+ unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
+ unsigned long slb_addr_limit;
+#ifdef CONFIG_PPC_64K_PAGES
+ struct slice_mask mask_64k;
+#endif
+ struct slice_mask mask_4k;
+#ifdef CONFIG_HUGETLB_PAGE
+ struct slice_mask mask_16m;
+ struct slice_mask mask_16g;
+#endif
+
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+ struct subpage_prot_table spt;
+#endif /* CONFIG_PPC_SUBPAGE_PROT */
+};
+
#if 0
/*
* The code below is equivalent to this function for arguments
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index c9f317090620..e510e46b07ce 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -104,16 +104,6 @@ struct spinlock;
/* Maximum possible number of NPUs in a system. */
#define NV_MAX_NPUS 8
-/*
- * One bit per slice. We have lower slices which cover 256MB segments
- * upto 4G range. That gets us 16 low slices. For the rest we track slices
- * in 1TB size.
- */
-struct slice_mask {
- u64 low_slices;
- DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
-};
-
typedef struct {
union {
/*
@@ -127,7 +117,6 @@ typedef struct {
mm_context_id_t id;
mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE];
};
- u16 user_psize; /* page size index */
/* Number of bits in the mm_cpumask */
atomic_t active_cpus;
@@ -137,23 +126,9 @@ typedef struct {
/* NPU NMMU context */
struct npu_context *npu_context;
+ struct hash_mm_context *hash_context;
- /* SLB page size encodings*/
- unsigned char low_slices_psize[LOW_SLICE_ARRAY_SZ];
- unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
- unsigned long slb_addr_limit;
-# ifdef CONFIG_PPC_64K_PAGES
- struct slice_mask mask_64k;
-# endif
- struct slice_mask mask_4k;
-# ifdef CONFIG_HUGETLB_PAGE
- struct slice_mask mask_16m;
- struct slice_mask mask_16g;
-# endif
unsigned long vdso_base;
-#ifdef CONFIG_PPC_SUBPAGE_PROT
- struct subpage_prot_table spt;
-#endif /* CONFIG_PPC_SUBPAGE_PROT */
/*
* pagetable fragment support
*/
@@ -176,62 +151,62 @@ typedef struct {
static inline u16 mm_ctx_user_psize(mm_context_t *ctx)
{
- return ctx->user_psize;
+ return ctx->hash_context->user_psize;
}
static inline void mm_ctx_set_user_psize(mm_context_t *ctx, u16 user_psize)
{
- ctx->user_psize = user_psize;
+ ctx->hash_context->user_psize = user_psize;
}
static inline unsigned char *mm_ctx_low_slices(mm_context_t *ctx)
{
- return ctx->low_slices_psize;
+ return ctx->hash_context->low_slices_psize;
}
static inline unsigned char *mm_ctx_high_slices(mm_context_t *ctx)
{
- return ctx->high_slices_psize;
+ return ctx->hash_context->high_slices_psize;
}
static inline unsigned long mm_ctx_slb_addr_limit(mm_context_t *ctx)
{
- return ctx->slb_addr_limit;
+ return ctx->hash_context->slb_addr_limit;
}
static inline void mm_ctx_set_slb_addr_limit(mm_context_t *ctx, unsigned long limit)
{
- ctx->slb_addr_limit = limit;
+ ctx->hash_context->slb_addr_limit = limit;
}
#ifdef CONFIG_PPC_64K_PAGES
static inline struct slice_mask *mm_ctx_slice_mask_64k(mm_context_t *ctx)
{
- return &ctx->mask_64k;
+ return &ctx->hash_context->mask_64k;
}
#endif
static inline struct slice_mask *mm_ctx_slice_mask_4k(mm_context_t *ctx)
{
- return &ctx->mask_4k;
+ return &ctx->hash_context->mask_4k;
}
#ifdef CONFIG_HUGETLB_PAGE
static inline struct slice_mask *mm_ctx_slice_mask_16m(mm_context_t *ctx)
{
- return &ctx->mask_16m;
+ return &ctx->hash_context->mask_16m;
}
static inline struct slice_mask *mm_ctx_slice_mask_16g(mm_context_t *ctx)
{
- return &ctx->mask_16g;
+ return &ctx->hash_context->mask_16g;
}
#endif
#ifdef CONFIG_PPC_SUBPAGE_PROT
static inline struct subpage_prot_table *mm_ctx_subpage_prot(mm_context_t *ctx)
{
- return &ctx->spt;
+ return &ctx->hash_context->spt;
}
#endif
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index a07de8608484..21b1ce200b22 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -947,6 +947,12 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = klimit;
+#ifdef CONFIG_PPC_MM_SLICES
+#if defined(CONFIG_PPC_8xx)
+ init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
+#endif
+#endif
+
#ifdef CONFIG_SPAPR_TCE_IOMMU
mm_iommu_init(&init_mm);
#endif
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 2cb3a456f5b5..04ac7c36d380 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -968,6 +968,7 @@ void __init hash__early_init_devtree(void)
htab_scan_page_sizes();
}
+struct hash_mm_context init_hash_mm_context;
void __init hash__early_init_mmu(void)
{
#ifndef CONFIG_PPC_64K_PAGES
@@ -1041,7 +1042,8 @@ void __init hash__early_init_mmu(void)
*/
htab_initialize();
- init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+ init_mm.context.hash_context = &init_hash_mm_context;
+ init_mm.context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
pr_info("Initializing hash mmu with SLB\n");
/* Initialize SLB management */
diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
index f720c5cc0b5e..6eef5a36b2e9 100644
--- a/arch/powerpc/mm/mmu_context_book3s64.c
+++ b/arch/powerpc/mm/mmu_context_book3s64.c
@@ -63,6 +63,12 @@ static int hash__init_new_context(struct mm_struct *mm)
if (index < 0)
return index;
+ mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context), GFP_KERNEL);
+ if (!mm->context.hash_context) {
+ ida_free(&mmu_context_ida, index);
+ return -ENOMEM;
+ }
+
/*
* The old code would re-promote on fork, we don't do that when using
* slices as it could cause problem promoting slices that have been
@@ -77,8 +83,14 @@ static int hash__init_new_context(struct mm_struct *mm)
* We should not be calling init_new_context() on init_mm. Hence a
* check against 0 is OK.
*/
- if (mm->context.id == 0)
+ if (mm->context.id == 0) {
+ memset(mm->context.hash_context, 0, sizeof(struct hash_mm_context));
slice_init_new_context_exec(mm);
+ } else {
+ /* This is fork. Copy hash_context details from current->mm */
+ memcpy(mm->context.hash_context, current->mm->context.hash_context, sizeof(struct hash_mm_context));
+
+ }
subpage_prot_init_new_context(mm);
@@ -118,6 +130,7 @@ static int radix__init_new_context(struct mm_struct *mm)
asm volatile("ptesync;isync" : : : "memory");
mm->context.npu_context = NULL;
+ mm->context.hash_context = NULL;
return index;
}
@@ -162,6 +175,7 @@ static void destroy_contexts(mm_context_t *ctx)
if (context_id)
ida_free(&mmu_context_ida, context_id);
}
+ kfree(ctx->hash_context);
}
static void pmd_frag_destroy(void *pmd_frag)
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/3] powerpc/mm: Move slb_addr_linit to early_init_mmu
From: Aneesh Kumar K.V @ 2019-04-08 13:19 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe, Christophe Leroy
Cc: Aneesh Kumar K.V, linuxppc-dev
In-Reply-To: <20190408131934.27959-1-aneesh.kumar@linux.ibm.com>
Avoid #ifdef in generic code. Also enables us to do this specific to
MMU translation mode on book3s64
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/kernel/setup-common.c | 11 -----------
arch/powerpc/mm/hash_utils_64.c | 2 ++
arch/powerpc/mm/tlb_nohash.c | 6 ++++++
3 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 2e5dfb6e0823..a07de8608484 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -947,17 +947,6 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = klimit;
-#ifdef CONFIG_PPC_MM_SLICES
-#ifdef CONFIG_PPC64
- if (!radix_enabled())
- init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
-#elif defined(CONFIG_PPC_8xx)
- init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
-#else
-#error "context.addr_limit not initialized."
-#endif
-#endif
-
#ifdef CONFIG_SPAPR_TCE_IOMMU
mm_iommu_init(&init_mm);
#endif
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 5a2bd132f92e..2cb3a456f5b5 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1041,6 +1041,8 @@ void __init hash__early_init_mmu(void)
*/
htab_initialize();
+ init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+
pr_info("Initializing hash mmu with SLB\n");
/* Initialize SLB management */
slb_initialize();
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index ac23dc1c6535..088e0a6b5ade 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -800,5 +800,11 @@ void __init early_init_mmu(void)
#ifdef CONFIG_PPC_47x
early_init_mmu_47x();
#endif
+
+#ifdef CONFIG_PPC_MM_SLICES
+#if defined(CONFIG_PPC_8xx)
+ init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
+#endif
+#endif
}
#endif /* CONFIG_PPC64 */
--
2.20.1
^ permalink raw reply related
* [PATCH v2 1/3] powerpc/mm: Add helpers for accessing hash translation related variables
From: Aneesh Kumar K.V @ 2019-04-08 13:19 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe, Christophe Leroy
Cc: Aneesh Kumar K.V, linuxppc-dev
In-Reply-To: <20190408131934.27959-1-aneesh.kumar@linux.ibm.com>
We want to switch to allocating them runtime only when hash translation is
enabled. Add helpers so that both book3s and nohash can be adapted to
upcoming change easily.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 4 +-
arch/powerpc/include/asm/book3s/64/mmu.h | 63 ++++++++++++++++++-
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 50 +++++++++++++++
arch/powerpc/kernel/paca.c | 12 ++--
arch/powerpc/mm/hash_utils_64.c | 10 +--
arch/powerpc/mm/slb.c | 2 +-
arch/powerpc/mm/slice.c | 49 +++++++--------
arch/powerpc/mm/subpage-prot.c | 8 +--
8 files changed, 154 insertions(+), 44 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index a28a28079edb..eb36fbfe4ef5 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -657,8 +657,8 @@ extern void slb_set_size(u16 size);
/* 4 bits per slice and we have one slice per 1TB */
#define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
-#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.slb_addr_limit >> 41)
-
+#define LOW_SLICE_ARRAY_SZ (BITS_PER_LONG / BITS_PER_BYTE)
+#define TASK_SLICE_ARRAY_SZ(x) ((x)->slb_addr_limit >> 41)
#ifndef __ASSEMBLY__
#ifdef CONFIG_PPC_SUBPAGE_PROT
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index afe10dd11c68..c9f317090620 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -139,7 +139,7 @@ typedef struct {
struct npu_context *npu_context;
/* SLB page size encodings*/
- unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
+ unsigned char low_slices_psize[LOW_SLICE_ARRAY_SZ];
unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
unsigned long slb_addr_limit;
# ifdef CONFIG_PPC_64K_PAGES
@@ -174,6 +174,67 @@ typedef struct {
#endif
} mm_context_t;
+static inline u16 mm_ctx_user_psize(mm_context_t *ctx)
+{
+ return ctx->user_psize;
+}
+
+static inline void mm_ctx_set_user_psize(mm_context_t *ctx, u16 user_psize)
+{
+ ctx->user_psize = user_psize;
+}
+
+static inline unsigned char *mm_ctx_low_slices(mm_context_t *ctx)
+{
+ return ctx->low_slices_psize;
+}
+
+static inline unsigned char *mm_ctx_high_slices(mm_context_t *ctx)
+{
+ return ctx->high_slices_psize;
+}
+
+static inline unsigned long mm_ctx_slb_addr_limit(mm_context_t *ctx)
+{
+ return ctx->slb_addr_limit;
+}
+
+static inline void mm_ctx_set_slb_addr_limit(mm_context_t *ctx, unsigned long limit)
+{
+ ctx->slb_addr_limit = limit;
+}
+
+#ifdef CONFIG_PPC_64K_PAGES
+static inline struct slice_mask *mm_ctx_slice_mask_64k(mm_context_t *ctx)
+{
+ return &ctx->mask_64k;
+}
+#endif
+
+static inline struct slice_mask *mm_ctx_slice_mask_4k(mm_context_t *ctx)
+{
+ return &ctx->mask_4k;
+}
+
+#ifdef CONFIG_HUGETLB_PAGE
+static inline struct slice_mask *mm_ctx_slice_mask_16m(mm_context_t *ctx)
+{
+ return &ctx->mask_16m;
+}
+
+static inline struct slice_mask *mm_ctx_slice_mask_16g(mm_context_t *ctx)
+{
+ return &ctx->mask_16g;
+}
+#endif
+
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+static inline struct subpage_prot_table *mm_ctx_subpage_prot(mm_context_t *ctx)
+{
+ return &ctx->spt;
+}
+#endif
+
/*
* The current system page and segment sizes
*/
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index 0a1a3fc54e54..0f4b0b50e5ad 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -167,6 +167,7 @@
#ifdef CONFIG_PPC_MM_SLICES
#include <asm/nohash/32/slice.h>
#define SLICE_ARRAY_SIZE (1 << (32 - SLICE_LOW_SHIFT - 1))
+#define LOW_SLICE_ARRAY_SZ SLICE_ARRAY_SIZE
#endif
#ifndef __ASSEMBLY__
@@ -193,6 +194,55 @@ typedef struct {
void *pte_frag;
} mm_context_t;
+#ifdef CONFIG_PPC_MM_SLICES
+static inline u16 mm_ctx_user_psize(mm_context_t *ctx)
+{
+ return ctx->user_psize;
+}
+
+static inline void mm_ctx_set_user_psize(mm_context_t *ctx, u16 user_psize)
+{
+ ctx->user_psize = user_psize;
+}
+
+static inline unsigned char *mm_ctx_low_slices(mm_context_t *ctx)
+{
+ return ctx->low_slices_psize;
+}
+
+static inline unsigned char *mm_ctx_high_slices(mm_context_t *ctx)
+{
+ return ctx->high_slices_psize;
+}
+
+static inline unsigned long mm_ctx_slb_addr_limit(mm_context_t *ctx)
+{
+ return ctx->slb_addr_limit;
+}
+
+static inline void mm_ctx_set_slb_addr_limit(mm_context_t *ctx, unsigned long limit)
+{
+ ctx->slb_addr_limit = limit;
+}
+
+static inline struct slice_mask *mm_ctx_slice_mask_base(mm_context_t *ctx)
+{
+ return &ctx->mask_base_psize;
+}
+
+#ifdef CONFIG_HUGETLB_PAGE
+static inline struct slice_mask *mm_ctx_slice_mask_512k(mm_context_t *ctx)
+{
+ return &ctx->mask_512k;
+}
+
+static inline struct slice_mask *mm_ctx_slice_mask_8m(mm_context_t *ctx)
+{
+ return &ctx->mask_8m;
+}
+#endif
+#endif /* CONFIG_PPC_MM_SLICE */
+
#define PHYS_IMMR_BASE (mfspr(SPRN_IMMR) & 0xfff80000)
#define VIRT_IMMR_BASE (__fix_to_virt(FIX_IMMR_BASE))
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index e7382abee868..9cc91d03ab62 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -267,12 +267,12 @@ void copy_mm_to_paca(struct mm_struct *mm)
get_paca()->mm_ctx_id = context->id;
#ifdef CONFIG_PPC_MM_SLICES
- VM_BUG_ON(!mm->context.slb_addr_limit);
- get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit;
- memcpy(&get_paca()->mm_ctx_low_slices_psize,
- &context->low_slices_psize, sizeof(context->low_slices_psize));
- memcpy(&get_paca()->mm_ctx_high_slices_psize,
- &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
+ VM_BUG_ON(!mm_ctx_slb_addr_limit(context));
+ get_paca()->mm_ctx_slb_addr_limit = mm_ctx_slb_addr_limit(context);
+ memcpy(&get_paca()->mm_ctx_low_slices_psize, mm_ctx_low_slices(context),
+ LOW_SLICE_ARRAY_SZ);
+ memcpy(&get_paca()->mm_ctx_high_slices_psize, mm_ctx_high_slices(context),
+ TASK_SLICE_ARRAY_SZ(context));
#else /* CONFIG_PPC_MM_SLICES */
get_paca()->mm_ctx_user_psize = context->user_psize;
get_paca()->mm_ctx_sllp = context->sllp;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 0a4f939a8161..5a2bd132f92e 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1147,7 +1147,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
*/
static int subpage_protection(struct mm_struct *mm, unsigned long ea)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
u32 spp = 0;
u32 **sbpm, *sbpp;
@@ -1470,7 +1470,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
int psize = get_slice_psize(mm, ea);
/* We only prefault standard pages for now */
- if (unlikely(psize != mm->context.user_psize))
+ if (unlikely(psize != mm_ctx_user_psize(&mm->context)))
return false;
/*
@@ -1549,7 +1549,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
/* Hash it in */
#ifdef CONFIG_PPC_64K_PAGES
- if (mm->context.user_psize == MMU_PAGE_64K)
+ if (mm_ctx_user_psize(&mm->context) == MMU_PAGE_64K)
rc = __hash_page_64K(ea, access, vsid, ptep, trap,
update_flags, ssize);
else
@@ -1562,8 +1562,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
*/
if (rc == -1)
hash_failure_debug(ea, access, vsid, trap, ssize,
- mm->context.user_psize,
- mm->context.user_psize,
+ mm_ctx_user_psize(&mm->context),
+ mm_ctx_user_psize(&mm->context),
pte_val(*ptep));
out_exit:
local_irq_restore(flags);
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 5986df48359b..78c0c0a0e355 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -739,7 +739,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea)
* consider this as bad access if we take a SLB miss
* on an address above addr limit.
*/
- if (ea >= mm->context.slb_addr_limit)
+ if (ea >= mm_ctx_slb_addr_limit(&mm->context))
return -EFAULT;
context = get_user_context(&mm->context, ea);
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
index aec91dbcdc0b..35b278082391 100644
--- a/arch/powerpc/mm/slice.c
+++ b/arch/powerpc/mm/slice.c
@@ -101,7 +101,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
{
struct vm_area_struct *vma;
- if ((mm->context.slb_addr_limit - len) < addr)
+ if ((mm_ctx_slb_addr_limit(&mm->context) - len) < addr)
return 0;
vma = find_vma(mm, addr);
return (!vma || (addr + len) <= vm_start_gap(vma));
@@ -155,15 +155,15 @@ static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize)
{
#ifdef CONFIG_PPC_64K_PAGES
if (psize == MMU_PAGE_64K)
- return &mm->context.mask_64k;
+ return mm_ctx_slice_mask_64k(&mm->context);
#endif
if (psize == MMU_PAGE_4K)
- return &mm->context.mask_4k;
+ return mm_ctx_slice_mask_4k(&mm->context);
#ifdef CONFIG_HUGETLB_PAGE
if (psize == MMU_PAGE_16M)
- return &mm->context.mask_16m;
+ return mm_ctx_slice_mask_16m(&mm->context);
if (psize == MMU_PAGE_16G)
- return &mm->context.mask_16g;
+ return mm_ctx_slice_mask_16g(&mm->context);
#endif
BUG();
}
@@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
*/
spin_lock_irqsave(&slice_convert_lock, flags);
- lpsizes = mm->context.low_slices_psize;
+ lpsizes = mm_ctx_low_slices(&mm->context);
for (i = 0; i < SLICE_NUM_LOW; i++) {
if (!(mask->low_slices & (1u << i)))
continue;
@@ -272,8 +272,8 @@ static void slice_convert(struct mm_struct *mm,
(((unsigned long)psize) << (mask_index * 4));
}
- hpsizes = mm->context.high_slices_psize;
- for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) {
+ hpsizes = mm_ctx_high_slices(&mm->context);
+ for (i = 0; i < GET_HIGH_SLICE_INDEX(mm_ctx_slb_addr_limit(&mm->context)); i++) {
if (!test_bit(i, mask->high_slices))
continue;
@@ -292,8 +292,8 @@ static void slice_convert(struct mm_struct *mm,
}
slice_dbg(" lsps=%lx, hsps=%lx\n",
- (unsigned long)mm->context.low_slices_psize,
- (unsigned long)mm->context.high_slices_psize);
+ (unsigned long)mm_ctx_low_slices(&mm->context),
+ (unsigned long)mm_ctx_high_slices(&mm->context));
spin_unlock_irqrestore(&slice_convert_lock, flags);
@@ -393,7 +393,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm,
* DEFAULT_MAP_WINDOW we should apply this.
*/
if (high_limit > DEFAULT_MAP_WINDOW)
- addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW;
+ addr += mm_ctx_slb_addr_limit(&mm->context) - DEFAULT_MAP_WINDOW;
while (addr > min_addr) {
info.high_limit = addr;
@@ -505,20 +505,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
return -ENOMEM;
}
- if (high_limit > mm->context.slb_addr_limit) {
+ if (high_limit > mm_ctx_slb_addr_limit(&mm->context)) {
/*
* Increasing the slb_addr_limit does not require
* slice mask cache to be recalculated because it should
* be already initialised beyond the old address limit.
*/
- mm->context.slb_addr_limit = high_limit;
+ mm_ctx_set_slb_addr_limit(&mm->context, high_limit);
on_each_cpu(slice_flush_segments, mm, 1);
}
/* Sanity checks */
BUG_ON(mm->task_size == 0);
- BUG_ON(mm->context.slb_addr_limit == 0);
+ BUG_ON(mm_ctx_slb_addr_limit(&mm->context) == 0);
VM_BUG_ON(radix_enabled());
slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
@@ -696,7 +696,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
unsigned long flags)
{
return slice_get_unmapped_area(addr, len, flags,
- current->mm->context.user_psize, 0);
+ mm_ctx_user_psize(¤t->mm->context), 0);
}
unsigned long arch_get_unmapped_area_topdown(struct file *filp,
@@ -706,7 +706,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
const unsigned long flags)
{
return slice_get_unmapped_area(addr0, len, flags,
- current->mm->context.user_psize, 1);
+ mm_ctx_user_psize(¤t->mm->context), 1);
}
unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
@@ -717,10 +717,10 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
VM_BUG_ON(radix_enabled());
if (slice_addr_is_low(addr)) {
- psizes = mm->context.low_slices_psize;
+ psizes = mm_ctx_low_slices(&mm->context);
index = GET_LOW_SLICE_INDEX(addr);
} else {
- psizes = mm->context.high_slices_psize;
+ psizes = mm_ctx_high_slices(&mm->context);
index = GET_HIGH_SLICE_INDEX(addr);
}
mask_index = index & 0x1;
@@ -742,20 +742,19 @@ void slice_init_new_context_exec(struct mm_struct *mm)
* duplicated.
*/
#ifdef CONFIG_PPC64
- mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+ mm_ctx_set_slb_addr_limit(&mm->context, DEFAULT_MAP_WINDOW_USER64);
#else
mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
#endif
-
- mm->context.user_psize = psize;
+ mm_ctx_set_user_psize(&mm->context, psize);
/*
* Set all slice psizes to the default.
*/
- lpsizes = mm->context.low_slices_psize;
+ lpsizes = mm_ctx_low_slices(&mm->context);
memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1);
- hpsizes = mm->context.high_slices_psize;
+ hpsizes = mm_ctx_high_slices(&mm->context);
memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1);
/*
@@ -777,7 +776,7 @@ void slice_setup_new_exec(void)
if (!is_32bit_task())
return;
- mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
+ mm_ctx_set_slb_addr_limit(&mm->context, DEFAULT_MAP_WINDOW);
}
#endif
@@ -816,7 +815,7 @@ int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
unsigned long len)
{
const struct slice_mask *maskp;
- unsigned int psize = mm->context.user_psize;
+ unsigned int psize = mm_ctx_user_psize(&mm->context);
VM_BUG_ON(radix_enabled());
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index 5e4178790dee..c72252542210 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -25,7 +25,7 @@
*/
void subpage_prot_free(struct mm_struct *mm)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
unsigned long i, j, addr;
u32 **p;
@@ -52,7 +52,7 @@ void subpage_prot_free(struct mm_struct *mm)
void subpage_prot_init_new_context(struct mm_struct *mm)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
memset(spt, 0, sizeof(*spt));
}
@@ -93,7 +93,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
static void subpage_prot_clear(unsigned long addr, unsigned long len)
{
struct mm_struct *mm = current->mm;
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
u32 **spm, *spp;
unsigned long i;
size_t nw;
@@ -189,7 +189,7 @@ SYSCALL_DEFINE3(subpage_prot, unsigned long, addr,
unsigned long, len, u32 __user *, map)
{
struct mm_struct *mm = current->mm;
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = mm_ctx_subpage_prot(&mm->context);
u32 **spm, *spp;
unsigned long i;
size_t nw;
--
2.20.1
^ permalink raw reply related
* [PATCH v2 0/3] Reduce memory usage for mm_context_t
From: Aneesh Kumar K.V @ 2019-04-08 13:19 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe, Christophe Leroy
Cc: Aneesh Kumar K.V, linuxppc-dev
This patch moves hash translation related context variables to another structure
and runtime allocate that based on translation mode.
Aneesh Kumar K.V (3):
powerpc/mm: Add helpers for accessing hash translation related
variables
powerpc/mm: Move slb_addr_linit to early_init_mmu
powerpc/mm: Reduce memory usage for mm_context_t for radix
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 35 +++++++-
arch/powerpc/include/asm/book3s/64/mmu.h | 88 +++++++++++++------
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 50 +++++++++++
arch/powerpc/kernel/paca.c | 12 +--
arch/powerpc/kernel/setup-common.c | 7 +-
arch/powerpc/mm/hash_utils_64.c | 14 +--
arch/powerpc/mm/mmu_context_book3s64.c | 16 +++-
arch/powerpc/mm/slb.c | 2 +-
arch/powerpc/mm/slice.c | 49 +++++------
arch/powerpc/mm/subpage-prot.c | 8 +-
arch/powerpc/mm/tlb_nohash.c | 6 ++
11 files changed, 211 insertions(+), 76 deletions(-)
--
2.20.1
^ permalink raw reply
* Re: powerpc/vdso32: fix CLOCK_MONOTONIC on PPC64
From: Michael Ellerman @ 2019-04-08 13:03 UTC (permalink / raw)
To: Christophe Leroy, Benjamin Herrenschmidt, Paul Mackerras,
Christian Zigotzky
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <0d8c9cb7fb43bde8663333bb6a69d16380a219a5.1554380255.git.christophe.leroy@c-s.fr>
On Thu, 2019-04-04 at 12:20:05 UTC, Christophe Leroy wrote:
> Commit b5b4453e7912 ("powerpc/vdso64: Fix CLOCK_MONOTONIC
> inconsistencies across Y2038") changed the type of wtom_clock_sec
> to s64 on PPC64. Therefore, VDSO32 needs to read it with a 4 bytes
> shift in order to retrieve the lower part of it.
>
> Fixes: b5b4453e7912 ("powerpc/vdso64: Fix CLOCK_MONOTONIC inconsistencies across Y2038")
> Reported-by: Christian Zigotzky <chzigotzky@xenosoft.de>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Applied to powerpc fixes, thanks.
https://git.kernel.org/powerpc/c/dd9a994fc68d196a052b73747e3366c5
cheers
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox