* Re: [PATCH] usb: gadget: Mark USB_FSL_QE broken on 64-bit
From: Li Yang @ 2021-10-27 14:37 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Felipe Balbi, Arnd Bergmann, Greg Kroah-Hartman, linux-usb, lkml,
linuxppc-dev
In-Reply-To: <20211027080849.3276289-1-geert@linux-m68k.org>
On Wed, Oct 27, 2021 at 5:25 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> On 64-bit:
>
> drivers/usb/gadget/udc/fsl_qe_udc.c: In function ‘qe_ep0_rx’:
> drivers/usb/gadget/udc/fsl_qe_udc.c:842:13: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
> 842 | vaddr = (u32)phys_to_virt(in_be32(&bd->buf));
> | ^
> In file included from drivers/usb/gadget/udc/fsl_qe_udc.c:41:
> drivers/usb/gadget/udc/fsl_qe_udc.c:843:28: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> 843 | frame_set_data(pframe, (u8 *)vaddr);
> | ^
>
> The driver assumes physical and virtual addresses are 32-bit, hence it
> cannot work on 64-bit platforms.
The device is truly only used in legacy 32-bit PowerPC chips and never
tested with 64-bit. Thanks.
>
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Li Yang <leoyang.li@nxp.com>
> ---
> One more casualty of CONFIG_WERROR=y.
> http://kisskb.ellerman.id.au/kisskb/buildresult/14652936/
> ---
> drivers/usb/gadget/udc/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
> index 8c614bb86c665c77..69394dc1cdfb6436 100644
> --- a/drivers/usb/gadget/udc/Kconfig
> +++ b/drivers/usb/gadget/udc/Kconfig
> @@ -330,6 +330,7 @@ config USB_AMD5536UDC
> config USB_FSL_QE
> tristate "Freescale QE/CPM USB Device Controller"
> depends on FSL_SOC && (QUICC_ENGINE || CPM)
> + depends on !64BIT || BROKEN
> help
> Some of Freescale PowerPC processors have a Full Speed
> QE/CPM2 USB controller, which support device mode with 4
> --
> 2.25.1
>
^ permalink raw reply
* Re: [PATCH 09/12] sh: Use of_get_cpu_hwid()
From: Rich Felker @ 2021-10-27 14:26 UTC (permalink / raw)
To: Rob Herring
Cc: Rafael J. Wysocki, linux-kernel, Guo Ren, H. Peter Anvin,
linux-riscv, Will Deacon, Stafford Horne, Jonas Bonn,
Florian Fainelli, Yoshinori Sato, linux-sh, x86, Russell King,
linux-csky, Ingo Molnar, bcm-kernel-feedback-list,
Catalin Marinas, Palmer Dabbelt, devicetree, Albert Ou, Ray Jui,
Stefan Kristiansson, openrisc, Borislav Petkov, Paul Walmsley,
Thomas Gleixner, linux-arm-kernel, Scott Branden,
Greg Kroah-Hartman, Frank Rowand, James Morse, Paul Mackerras,
linuxppc-dev
In-Reply-To: <20211006164332.1981454-10-robh@kernel.org>
On Wed, Oct 06, 2021 at 11:43:29AM -0500, Rob Herring wrote:
> Replace open coded parsing of CPU nodes' 'reg' property with
> of_get_cpu_hwid().
>
> Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
> Cc: Rich Felker <dalias@libc.org>
> Cc: linux-sh@vger.kernel.org
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> arch/sh/boards/of-generic.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c
> index 921d76fc3358..f7f3e618e85b 100644
> --- a/arch/sh/boards/of-generic.c
> +++ b/arch/sh/boards/of-generic.c
> @@ -62,9 +62,8 @@ static void sh_of_smp_probe(void)
> init_cpu_possible(cpumask_of(0));
>
> for_each_of_cpu_node(np) {
> - const __be32 *cell = of_get_property(np, "reg", NULL);
> - u64 id = -1;
> - if (cell) id = of_read_number(cell, of_n_addr_cells(np));
> + u64 id = of_get_cpu_hwid(np, 0);
> +
> if (id < NR_CPUS) {
> if (!method)
> of_property_read_string(np, "enable-method", &method);
> --
> 2.30.2
Acked-by: Rich Felker <dalias@libc.org>
^ permalink raw reply
* [PATCH v1 1/1] soc: fsl: Replace kernel.h with the necessary inclusions
From: Andy Shevchenko @ 2021-10-27 15:33 UTC (permalink / raw)
To: Andy Shevchenko, linux-kernel, linuxppc-dev; +Cc: Paul Mackerras
When kernel.h is used in the headers it adds a lot into dependency hell,
especially when there are circular dependencies are involved.
Replace kernel.h inclusion with the list of what is really being used.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
include/soc/fsl/dpaa2-fd.h | 3 ++-
include/soc/fsl/qe/immap_qe.h | 3 ++-
include/soc/fsl/qe/qe_tdm.h | 4 +++-
include/soc/fsl/qe/ucc_fast.h | 2 +-
include/soc/fsl/qe/ucc_slow.h | 2 +-
5 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/soc/fsl/dpaa2-fd.h b/include/soc/fsl/dpaa2-fd.h
index 90ae8d191f1a..bae490cac0aa 100644
--- a/include/soc/fsl/dpaa2-fd.h
+++ b/include/soc/fsl/dpaa2-fd.h
@@ -7,7 +7,8 @@
#ifndef __FSL_DPAA2_FD_H
#define __FSL_DPAA2_FD_H
-#include <linux/kernel.h>
+#include <linux/byteorder/generic.h>
+#include <linux/types.h>
/**
* DOC: DPAA2 FD - Frame Descriptor APIs for DPAA2
diff --git a/include/soc/fsl/qe/immap_qe.h b/include/soc/fsl/qe/immap_qe.h
index 7614fee532f1..edd601f53f5d 100644
--- a/include/soc/fsl/qe/immap_qe.h
+++ b/include/soc/fsl/qe/immap_qe.h
@@ -13,7 +13,8 @@
#define _ASM_POWERPC_IMMAP_QE_H
#ifdef __KERNEL__
-#include <linux/kernel.h>
+#include <linux/types.h>
+
#include <asm/io.h>
#define QE_IMMAP_SIZE (1024 * 1024) /* 1MB from 1MB+IMMR */
diff --git a/include/soc/fsl/qe/qe_tdm.h b/include/soc/fsl/qe/qe_tdm.h
index b6febe225071..43ea830cfe1f 100644
--- a/include/soc/fsl/qe/qe_tdm.h
+++ b/include/soc/fsl/qe/qe_tdm.h
@@ -10,8 +10,8 @@
#ifndef _QE_TDM_H_
#define _QE_TDM_H_
-#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/types.h>
#include <soc/fsl/qe/immap_qe.h>
#include <soc/fsl/qe/qe.h>
@@ -19,6 +19,8 @@
#include <soc/fsl/qe/ucc.h>
#include <soc/fsl/qe/ucc_fast.h>
+struct device_node;
+
/* SI RAM entries */
#define SIR_LAST 0x0001
#define SIR_BYTE 0x0002
diff --git a/include/soc/fsl/qe/ucc_fast.h b/include/soc/fsl/qe/ucc_fast.h
index 9696a5b9b5d1..ad60b87a3c69 100644
--- a/include/soc/fsl/qe/ucc_fast.h
+++ b/include/soc/fsl/qe/ucc_fast.h
@@ -10,7 +10,7 @@
#ifndef __UCC_FAST_H__
#define __UCC_FAST_H__
-#include <linux/kernel.h>
+#include <linux/types.h>
#include <soc/fsl/qe/immap_qe.h>
#include <soc/fsl/qe/qe.h>
diff --git a/include/soc/fsl/qe/ucc_slow.h b/include/soc/fsl/qe/ucc_slow.h
index 11a216e4e919..7548ce8a202d 100644
--- a/include/soc/fsl/qe/ucc_slow.h
+++ b/include/soc/fsl/qe/ucc_slow.h
@@ -11,7 +11,7 @@
#ifndef __UCC_SLOW_H__
#define __UCC_SLOW_H__
-#include <linux/kernel.h>
+#include <linux/types.h>
#include <soc/fsl/qe/immap_qe.h>
#include <soc/fsl/qe/qe.h>
--
2.33.0
^ permalink raw reply related
* Re: [PATCH 2/3] fbdev: rework backlight dependencies
From: Randy Dunlap @ 2021-10-27 19:25 UTC (permalink / raw)
To: Arnd Bergmann, dri-devel
Cc: linux-fbdev, Arnd Bergmann, Jens Frederich, intel-gfx,
linux-staging, Lars Poeschel, linux-kernel, Jani Nikula,
Daniel Vetter, Andy Shevchenko, Geert Uytterhoeven,
Thomas Zimmermann, Greg Kroah-Hartman, Miguel Ojeda,
Robin van der Gracht, linuxppc-dev, Jon Nettleton
In-Reply-To: <20211027132732.3993279-2-arnd@kernel.org>
On 10/27/21 6:27 AM, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Rather than having CONFIG_FB_BACKLIGHT select CONFIG_BACKLIGHT_CLASS_DEVICE,
> make any driver that needs it have a dependency on the class device
> being available, to prevent circular dependencies.
>
> This is the same way that the backlight is already treated for the DRM
> subsystem.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/auxdisplay/Kconfig | 1 +
> drivers/macintosh/Kconfig | 1 +
> drivers/staging/fbtft/Kconfig | 1 +
> drivers/staging/olpc_dcon/Kconfig | 2 +-
> drivers/video/fbdev/Kconfig | 14 +++++++++++---
> 5 files changed, 15 insertions(+), 4 deletions(-)
Acked-by: Randy Dunlap <rdunlap@infraded.org>
Thanks.
--
~Randy
^ permalink raw reply
* Re: [PATCH] powerpc: Enhance pmem DMA bypass handling
From: Brian King @ 2021-10-27 21:30 UTC (permalink / raw)
To: Alexey Kardashevskiy, linuxppc-dev
In-Reply-To: <a2537ac0-cee3-31d3-73da-7d9de860f602@ozlabs.ru>
On 10/26/21 12:39 AM, Alexey Kardashevskiy wrote:
>
>
> On 10/26/21 01:40, Brian King wrote:
>> On 10/23/21 7:18 AM, Alexey Kardashevskiy wrote:
>>>
>>>
>>> On 23/10/2021 07:18, Brian King wrote:
>>>> On 10/22/21 7:24 AM, Alexey Kardashevskiy wrote:
>>>>>
>>>>>
>>>>> On 22/10/2021 04:44, Brian King wrote:
>>>>>> If ibm,pmemory is installed in the system, it can appear anywhere
>>>>>> in the address space. This patch enhances how we handle DMA for devices when
>>>>>> ibm,pmemory is present. In the case where we have enough DMA space to
>>>>>> direct map all of RAM, but not ibm,pmemory, we use direct DMA for
>>>>>> I/O to RAM and use the default window to dynamically map ibm,pmemory.
>>>>>> In the case where we only have a single DMA window, this won't work, > so if the window is not big enough to map the entire address range,
>>>>>> we cannot direct map.
>>>>>
>>>>> but we want the pmem range to be mapped into the huge DMA window too if we can, why skip it?
>>>>
>>>> This patch should simply do what the comment in this commit mentioned below suggests, which says that
>>>> ibm,pmemory can appear anywhere in the address space. If the DMA window is large enough
>>>> to map all of MAX_PHYSMEM_BITS, we will indeed simply do direct DMA for everything,
>>>> including the pmem. If we do not have a big enough window to do that, we will do
>>>> direct DMA for DRAM and dynamic mapping for pmem.
>>>
>>>
>>> Right, and this is what we do already, do not we? I missing something here.
>>
>> The upstream code does not work correctly that I can see. If I boot an upstream kernel
>> with an nvme device and vpmem assigned to the LPAR, and enable dev_dbg in arch/powerpc/platforms/pseries/iommu.c,
>> I see the following in the logs:
>>
>> [ 2.157549] nvme 0121:50:00.0: ibm,query-pe-dma-windows(53) 500000 8000000 20000121 returned 0
>> [ 2.157561] nvme 0121:50:00.0: Skipping ibm,pmemory
>> [ 2.157567] nvme 0121:50:00.0: can't map partition max 0x8000000000000 with 16777216 65536-sized pages
>> [ 2.170150] nvme 0121:50:00.0: ibm,create-pe-dma-window(54) 500000 8000000 20000121 10 28 returned 0 (liobn = 0x70000121 starting addr = 8000000 0)
>> [ 2.170170] nvme 0121:50:00.0: created tce table LIOBN 0x70000121 for /pci@800000020000121/pci1014,683@0
>> [ 2.356260] nvme 0121:50:00.0: node is /pci@800000020000121/pci1014,683@0
>>
>> This means we are heading down the leg in enable_ddw where we do not set direct_mapping to true. We use
>> create the DDW window, but don't do any direct DMA. This is because the window is not large enough to
>> map 2PB of memory, which is what ddw_memory_hotplug_max returns without my patch.
>>
>> With my patch applied, I get this in the logs:
>>
>> [ 2.204866] nvme 0121:50:00.0: ibm,query-pe-dma-windows(53) 500000 8000000 20000121 returned 0
>> [ 2.204875] nvme 0121:50:00.0: Skipping ibm,pmemory
>> [ 2.205058] nvme 0121:50:00.0: ibm,create-pe-dma-window(54) 500000 8000000 20000121 10 21 returned 0 (liobn = 0x70000121 starting addr = 8000000 0)
>> [ 2.205068] nvme 0121:50:00.0: created tce table LIOBN 0x70000121 for /pci@800000020000121/pci1014,683@0
>> [ 2.215898] nvme 0121:50:00.0: iommu: 64-bit OK but direct DMA is limited by 800000200000000
>>
>
>
> ah I see. then...
>
>
>>
>> Thanks,
>>
>> Brian
>>
>>
>>>
>>>>
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/arch/powerpc/platforms/pseries/iommu.c?id=bf6e2d562bbc4d115cf322b0bca57fe5bbd26f48
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Brian
>>>>
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
>>>>>> ---
>>>>>> arch/powerpc/platforms/pseries/iommu.c | 19 ++++++++++---------
>>>>>> 1 file changed, 10 insertions(+), 9 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
>>>>>> index 269f61d519c2..d9ae985d10a4 100644
>>>>>> --- a/arch/powerpc/platforms/pseries/iommu.c
>>>>>> +++ b/arch/powerpc/platforms/pseries/iommu.c
>>>>>> @@ -1092,15 +1092,6 @@ static phys_addr_t ddw_memory_hotplug_max(void)
>>>>>> phys_addr_t max_addr = memory_hotplug_max();
>>>>>> struct device_node *memory;
>>>>>> - /*
>>>>>> - * The "ibm,pmemory" can appear anywhere in the address space.
>>>>>> - * Assuming it is still backed by page structs, set the upper limit
>>>>>> - * for the huge DMA window as MAX_PHYSMEM_BITS.
>>>>>> - */
>>>>>> - if (of_find_node_by_type(NULL, "ibm,pmemory"))
>>>>>> - return (sizeof(phys_addr_t) * 8 <= MAX_PHYSMEM_BITS) ?
>>>>>> - (phys_addr_t) -1 : (1ULL << MAX_PHYSMEM_BITS);
>>>>>> -
>>>>>> for_each_node_by_type(memory, "memory") {
>>>>>> unsigned long start, size;
>>>>>> int n_mem_addr_cells, n_mem_size_cells, len;
>>>>>> @@ -1341,6 +1332,16 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
>>>>>> */
>>>>>> len = max_ram_len;
>>>>>> if (pmem_present) {
>>>>>> + if (default_win_removed) {
>>>>>> + /*
>>>>>> + * If we only have one DMA window and have pmem present,
>>>>>> + * then we need to be able to map the entire address
>>>>>> + * range in order to be able to do direct DMA to RAM.
>>>>>> + */
>>>>>> + len = order_base_2((sizeof(phys_addr_t) * 8 <= MAX_PHYSMEM_BITS) ?
>>>>>> + (phys_addr_t) -1 : (1ULL << MAX_PHYSMEM_BITS));
>
>
> ... len = (sizeof(phys_addr_t) * 8 <= MAX_PHYSMEM_BITS) ? 31 :
> MAX_PHYSMEM_BITS ?
>
> Or actually simply drop this hunk and only leave the first one and add
> this instead:
>
>
> diff --git a/arch/powerpc/platforms/pseries/iommu.c
> b/arch/powerpc/platforms/pseries/iommu.c
> index 591ec9e94edb..68bfcd2227d9 100644
> --- a/arch/powerpc/platforms/pseries/iommu.c
> +++ b/arch/powerpc/platforms/pseries/iommu.c
> @@ -1518,7 +1518,7 @@ static bool enable_ddw(struct pci_dev *dev, struct
> device_node *pdn)
> * as RAM, then we failed to create a window to cover persistent
> * memory and need to set the DMA limit.
> */
> - if (pmem_present && ddw_enabled && direct_mapping && len ==
> max_ram_len)
> + if (pmem_present && ddw_enabled && direct_mapping)
>
> ?
So, this would change the handling of devices that have a single window when pmem
is present. With your proposed change, we would then direct map for DRAM
and attempt to use whatever TCE space is left to do the dynamic mapping
when DMA'ing to the pmem, all from a single window. We don't account for this
in the code from what I can see, so we could get into the scenario where we have
a DMA window just large enough to map all of DRAM, we direct map that, and then
have nothing left over for the pmem.
I would actually like to get this working, as it would be helpful for the performance
of SR-IOV devices when pmem is present. However, I think we'd need to ensure we
have at least a certain amount of reserved DMA space for the dynamic mapping
before we do. There might be other things to consider as well...
Should we handle that as a further enhancement in a future patch, and move forward with this
as a bug fix?
Thanks,
Brian
>
> Thanks,
>
>
>
>>>>>> + }
>>>>>> +
>>>>>> if (query.largest_available_block >=
>>>>>> (1ULL << (MAX_PHYSMEM_BITS - page_shift)))
>>>>>> len = MAX_PHYSMEM_BITS;
>>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>>
>
--
Brian King
Power Linux I/O
IBM Linux Technology Center
^ permalink raw reply
* [PATCH v2 0/5] rtc: nintendo: Add a RTC driver for the GameCube, Wii and Wii U
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211014220524.9988-1-linkmauve@linkmauve.fr>
These three consoles share a device, the MX23L4005, which contains a
clock and 64 bytes of SRAM storage, and is exposed on the EXI bus
(similar to SPI) on channel 0, device 1. This driver allows it to be
used as a Linux RTC device, where time can be read and set.
The hardware also exposes two timers, one which shuts down the console
and one which powers it on, but these aren’t supported currently.
On the Wii U, the counter bias is stored in a XML file, /config/rtc.xml,
encrypted in the SLC (eMMC storage), using a proprietary filesystem. In
order to avoid having to implement all that, this driver assumes a
bootloader will parse this XML file and write the bias into the SRAM, at
the same location the other two consoles have it.
Changes since v1:
- Rename the driver to rtc-gamecube.
- Switch to the regmap API for debugfs support.
- Report low battery and unstable power as invalid data.
- Remove Wii U support in Kconfig, nothing specific to this console
needs to be changed in the code.
- Don’t attempt to change HW_SRNPROT on the GameCube, this register
doesn’t exist so we can use SRAM just fine without doing anything.
- Add needed changes to the wii device tree.
- Enable this driver on the gamecube and wii platforms.
Emmanuel Gil Peyrot (5):
rtc: gamecube: Add a RTC driver for the GameCube, Wii and Wii U
rtc: gamecube: Report low battery as invalid data
powerpc: wii.dts: Expose HW_SRNPROT on this platform
powerpc: gamecube_defconfig: Enable the RTC driver
powerpc: wii_defconfig: Enable the RTC driver
arch/powerpc/boot/dts/wii.dts | 5 +
arch/powerpc/configs/gamecube_defconfig | 2 +-
arch/powerpc/configs/wii_defconfig | 2 +-
drivers/rtc/Kconfig | 11 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-gamecube.c | 377 ++++++++++++++++++++++++
6 files changed, 396 insertions(+), 2 deletions(-)
create mode 100644 drivers/rtc/rtc-gamecube.c
--
2.33.1
^ permalink raw reply
* [PATCH v2 5/5] powerpc: wii_defconfig: Enable the RTC driver
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211027223516.2031-1-linkmauve@linkmauve.fr>
This selects the rtc-gamecube driver, which provides a real-time clock
on this platform.
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
arch/powerpc/configs/wii_defconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig
index 752e081d28d0..ad4302a12fd7 100644
--- a/arch/powerpc/configs/wii_defconfig
+++ b/arch/powerpc/configs/wii_defconfig
@@ -98,7 +98,7 @@ CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_GENERIC=y
+CONFIG_RTC_DRV_GAMECUBE=y
CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y
CONFIG_FUSE_FS=m
--
2.33.1
^ permalink raw reply related
* [PATCH v2 3/5] powerpc: wii.dts: Expose HW_SRNPROT on this platform
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211027223516.2031-1-linkmauve@linkmauve.fr>
This Hollywood register isn’t properly understood, but can allow or
reject access to the SRAM, which we need to set for RTC usage if it
isn’t previously set correctly beforehand.
See https://wiibrew.org/wiki/Hardware/Hollywood_Registers#HW_SRNPROT
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
arch/powerpc/boot/dts/wii.dts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/powerpc/boot/dts/wii.dts b/arch/powerpc/boot/dts/wii.dts
index c5720fdd0686..34d9732d5910 100644
--- a/arch/powerpc/boot/dts/wii.dts
+++ b/arch/powerpc/boot/dts/wii.dts
@@ -175,6 +175,11 @@ PIC1: pic1@d800030 {
interrupts = <14>;
};
+ srnprot@d800060 {
+ compatible = "nintendo,hollywood-srnprot";
+ reg = <0x0d800060 0x4>;
+ };
+
GPIO: gpio@d8000c0 {
#gpio-cells = <2>;
compatible = "nintendo,hollywood-gpio";
--
2.33.1
^ permalink raw reply related
* [PATCH v2 2/5] rtc: gamecube: Report low battery as invalid data
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211027223516.2031-1-linkmauve@linkmauve.fr>
I haven’t been able to test this patch as all of my consoles have a
working RTC battery, but according to the documentation it should work
like that.
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
drivers/rtc/rtc-gamecube.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c
index e8260c82c07d..1932c6fe1301 100644
--- a/drivers/rtc/rtc-gamecube.c
+++ b/drivers/rtc/rtc-gamecube.c
@@ -83,6 +83,10 @@
#define RTC_CONTROL0 0x21000c
#define RTC_CONTROL1 0x21000d
+/* RTC flags */
+#define RTC_CONTROL0_UNSTABLE_POWER 0x00000800
+#define RTC_CONTROL0_LOW_BATTERY 0x00000200
+
struct priv {
struct regmap *regmap;
void __iomem *iob;
@@ -182,9 +186,35 @@ static int gamecube_rtc_set_time(struct device *dev, struct rtc_time *t)
return regmap_write(d->regmap, RTC_COUNTER, timestamp - d->rtc_bias);
}
+static int gamecube_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct priv *d = dev_get_drvdata(dev);
+ int value;
+ int control0;
+ int ret;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ ret = regmap_read(d->regmap, RTC_CONTROL0, &control0);
+ if (ret)
+ return ret;
+
+ value = 0;
+ if (control0 & RTC_CONTROL0_UNSTABLE_POWER)
+ value |= RTC_VL_DATA_INVALID;
+ if (control0 & RTC_CONTROL0_LOW_BATTERY)
+ value |= RTC_VL_DATA_INVALID;
+ return put_user(value, (unsigned int __user *)arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
static const struct rtc_class_ops gamecube_rtc_ops = {
.read_time = gamecube_rtc_read_time,
.set_time = gamecube_rtc_set_time,
+ .ioctl = gamecube_rtc_ioctl,
};
static int gamecube_rtc_read_offset_from_sram(struct priv *d)
--
2.33.1
^ permalink raw reply related
* [PATCH v2 1/5] rtc: gamecube: Add a RTC driver for the GameCube, Wii and Wii U
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211027223516.2031-1-linkmauve@linkmauve.fr>
These three consoles share a device, the MX23L4005, which contains a
clock and 64 bytes of SRAM storage, and is exposed on the EXI bus
(similar to SPI) on channel 0, device 1. This driver allows it to be
used as a Linux RTC device, where time can be read and set.
The hardware also exposes two timers, one which shuts down the console
and one which powers it on, but these aren’t supported currently.
On the Wii U, the counter bias is stored in a XML file, /config/rtc.xml,
encrypted in the SLC (eMMC storage), using a proprietary filesystem. In
order to avoid having to implement all that, this driver assumes a
bootloader will parse this XML file and write the bias into the SRAM, at
the same location the other two consoles have it.
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
drivers/rtc/Kconfig | 11 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-gamecube.c | 347 +++++++++++++++++++++++++++++++++++++
3 files changed, 359 insertions(+)
create mode 100644 drivers/rtc/rtc-gamecube.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 914497abeef9..503089ca370d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1214,6 +1214,17 @@ config RTC_DRV_V3020
This driver can also be built as a module. If so, the module
will be called rtc-v3020.
+config RTC_DRV_GAMECUBE
+ tristate "Nintendo GameCube, Wii and Wii U RTC"
+ depends on GAMECUBE || WII || COMPILE_TEST
+ select REGMAP
+ help
+ If you say yes here you will get support for the RTC subsystem
+ of the Nintendo GameCube, Wii and Wii U.
+
+ This driver can also be built as a module. If so, the module
+ will be called "rtc-gamecube".
+
config RTC_DRV_WM831X
tristate "Wolfson Microelectronics WM831x RTC"
depends on MFD_WM831X
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2dd0dd956b0e..d781aaf0909c 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o
+obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o
obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
diff --git a/drivers/rtc/rtc-gamecube.c b/drivers/rtc/rtc-gamecube.c
new file mode 100644
index 000000000000..e8260c82c07d
--- /dev/null
+++ b/drivers/rtc/rtc-gamecube.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nintendo GameCube, Wii and Wii U RTC driver
+ *
+ * This driver is for the MX23L4005, more specifically its real-time clock and
+ * SRAM storage. The value returned by the RTC counter must be added with the
+ * offset stored in a bias register in SRAM (on the GameCube and Wii) or in
+ * /config/rtc.xml (on the Wii U). The latter being very impractical to access
+ * from Linux, this driver assumes the bootloader has read it and stored it in
+ * SRAM like for the other two consoles.
+ *
+ * This device sits on a bus named EXI (which is similar to SPI), channel 0,
+ * device 1. This driver assumes no other user of the EXI bus, which is
+ * currently the case but would have to be reworked to add support for other
+ * GameCube hardware exposed on this bus.
+ *
+ * References:
+ * - https://wiiubrew.org/wiki/Hardware/RTC
+ * - https://wiibrew.org/wiki/MX23L4005
+ *
+ * Copyright (C) 2018 rw-r-r-0644
+ * Copyright (C) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+ *
+ * Based on rtc-gcn.c
+ * Copyright (C) 2004-2009 The GameCube Linux Team
+ * Copyright (C) 2005,2008,2009 Albert Herranz
+ * Based on gamecube_time.c from Torben Nielsen.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
+
+/* EXI registers */
+#define EXICSR 0
+#define EXICR 12
+#define EXIDATA 16
+
+/* EXI register values */
+#define EXICSR_DEV 0x380
+ #define EXICSR_DEV1 0x100
+#define EXICSR_CLK 0x070
+ #define EXICSR_CLK_1MHZ 0x000
+ #define EXICSR_CLK_2MHZ 0x010
+ #define EXICSR_CLK_4MHZ 0x020
+ #define EXICSR_CLK_8MHZ 0x030
+ #define EXICSR_CLK_16MHZ 0x040
+ #define EXICSR_CLK_32MHZ 0x050
+#define EXICSR_INT 0x008
+ #define EXICSR_INTSET 0x008
+
+#define EXICR_TSTART 0x001
+#define EXICR_TRSMODE 0x002
+ #define EXICR_TRSMODE_IMM 0x000
+#define EXICR_TRSTYPE 0x00C
+ #define EXICR_TRSTYPE_R 0x000
+ #define EXICR_TRSTYPE_W 0x004
+#define EXICR_TLEN 0x030
+ #define EXICR_TLEN32 0x030
+
+/* EXI registers values to access the RTC */
+#define RTC_EXICSR (EXICSR_DEV1 | EXICSR_CLK_8MHZ | EXICSR_INTSET)
+#define RTC_EXICR_W (EXICR_TSTART | EXICR_TRSMODE_IMM | EXICR_TRSTYPE_W | EXICR_TLEN32)
+#define RTC_EXICR_R (EXICR_TSTART | EXICR_TRSMODE_IMM | EXICR_TRSTYPE_R | EXICR_TLEN32)
+#define RTC_EXIDATA_W 0x80000000
+
+/* RTC registers */
+#define RTC_COUNTER 0x200000
+#define RTC_SRAM 0x200001
+#define RTC_SRAM_BIAS 0x200004
+#define RTC_SNAPSHOT 0x204000
+#define RTC_ONTMR 0x210000
+#define RTC_OFFTMR 0x210001
+#define RTC_TEST0 0x210004
+#define RTC_TEST1 0x210005
+#define RTC_TEST2 0x210006
+#define RTC_TEST3 0x210007
+#define RTC_CONTROL0 0x21000c
+#define RTC_CONTROL1 0x21000d
+
+struct priv {
+ struct regmap *regmap;
+ void __iomem *iob;
+ u32 rtc_bias;
+};
+
+static int exi_read(void *context, u32 reg, u32 *data)
+{
+ struct priv *d = (struct priv *)context;
+ void __iomem *iob = d->iob;
+
+ /* The spin loops here loop about 15~16 times each, so there is no need
+ * to use a more expensive sleep method.
+ */
+
+ /* Write register offset */
+ iowrite32be(RTC_EXICSR, iob + EXICSR);
+ iowrite32be(reg << 8, iob + EXIDATA);
+ iowrite32be(RTC_EXICR_W, iob + EXICR);
+ while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET))
+ cpu_relax();
+
+ /* Read data */
+ iowrite32be(RTC_EXICSR, iob + EXICSR);
+ iowrite32be(RTC_EXICR_R, iob + EXICR);
+ while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET))
+ cpu_relax();
+ *data = ioread32be(iob + EXIDATA);
+
+ /* Clear channel parameters */
+ iowrite32be(0, iob + EXICSR);
+
+ return 0;
+}
+
+static int exi_write(void *context, u32 reg, u32 data)
+{
+ struct priv *d = (struct priv *)context;
+ void __iomem *iob = d->iob;
+
+ /* The spin loops here loop about 15~16 times each, so there is no need
+ * to use a more expensive sleep method.
+ */
+
+ /* Write register offset */
+ iowrite32be(RTC_EXICSR, iob + EXICSR);
+ iowrite32be(RTC_EXIDATA_W | (reg << 8), iob + EXIDATA);
+ iowrite32be(RTC_EXICR_W, iob + EXICR);
+ while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET))
+ cpu_relax();
+
+ /* Write data */
+ iowrite32be(RTC_EXICSR, iob + EXICSR);
+ iowrite32be(data, iob + EXIDATA);
+ iowrite32be(RTC_EXICR_W, iob + EXICR);
+ while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET))
+ cpu_relax();
+
+ /* Clear channel parameters */
+ iowrite32be(0, iob + EXICSR);
+
+ return 0;
+}
+
+static const struct regmap_bus exi_bus = {
+ /* TODO: is that true? Not that it matters here, but still. */
+ .fast_io = true,
+ .reg_read = exi_read,
+ .reg_write = exi_write,
+};
+
+static int gamecube_rtc_read_time(struct device *dev, struct rtc_time *t)
+{
+ struct priv *d = dev_get_drvdata(dev);
+ int ret;
+ u32 counter;
+ time64_t timestamp;
+
+ ret = regmap_read(d->regmap, RTC_COUNTER, &counter);
+ if (ret)
+ return ret;
+
+ /* Add the counter and the bias to obtain the timestamp */
+ timestamp = (time64_t)d->rtc_bias + counter;
+ rtc_time64_to_tm(timestamp, t);
+
+ return 0;
+}
+
+static int gamecube_rtc_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct priv *d = dev_get_drvdata(dev);
+ time64_t timestamp;
+
+ /* Subtract the timestamp and the bias to obtain the counter value */
+ timestamp = rtc_tm_to_time64(t);
+ return regmap_write(d->regmap, RTC_COUNTER, timestamp - d->rtc_bias);
+}
+
+static const struct rtc_class_ops gamecube_rtc_ops = {
+ .read_time = gamecube_rtc_read_time,
+ .set_time = gamecube_rtc_set_time,
+};
+
+static int gamecube_rtc_read_offset_from_sram(struct priv *d)
+{
+ struct device_node *np;
+ int ret;
+ struct resource res;
+ void __iomem *hw_srnprot;
+ u32 old;
+
+ np = of_find_compatible_node(NULL, NULL, "nintendo,latte-srnprot");
+ if (!np)
+ np = of_find_compatible_node(NULL, NULL,
+ "nintendo,hollywood-srnprot");
+ if (!np) {
+ pr_info("HW_SRNPROT not found, assuming a GameCube\n");
+ return regmap_read(d->regmap, RTC_SRAM_BIAS, &d->rtc_bias);
+ }
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ pr_err("no io memory range found\n");
+ return -1;
+ }
+
+ hw_srnprot = ioremap(res.start, resource_size(&res));
+ old = ioread32be(hw_srnprot);
+
+ /* TODO: figure out why we use this magic constant. I obtained it by
+ * reading the leftover value after boot, after IOSU already ran.
+ *
+ * On my Wii U, setting this register to 1 prevents the console from
+ * rebooting properly, so wiiubrew.org must be missing something.
+ *
+ * See https://wiiubrew.org/wiki/Hardware/Latte_registers
+ */
+ if (old != 0x7bf)
+ iowrite32be(0x7bf, hw_srnprot);
+
+ /* Get the offset from RTC SRAM.
+ *
+ * Its default location on the GameCube and on the Wii is in the SRAM,
+ * while on the Wii U the bootloader needs to fill it with the contents
+ * of /config/rtc.xml on the SLC (the eMMC). We don’t do that from
+ * Linux since it requires implementing a proprietary filesystem and do
+ * file decryption, instead we require the bootloader to fill the same
+ * SRAM address as on previous consoles.
+ */
+ ret = regmap_read(d->regmap, RTC_SRAM_BIAS, &d->rtc_bias);
+ if (ret) {
+ pr_err("failed to get the RTC bias\n");
+ return -1;
+ }
+
+ /* Reset SRAM access to how it was before, our job here is done. */
+ if (old != 0x7bf)
+ iowrite32be(old, hw_srnprot);
+ iounmap(hw_srnprot);
+
+ return 0;
+}
+
+static const struct regmap_range rtc_rd_ranges[] = {
+ regmap_reg_range(0x200000, 0x200010),
+ regmap_reg_range(0x204000, 0x204000),
+ regmap_reg_range(0x210000, 0x210001),
+ regmap_reg_range(0x210004, 0x210007),
+ regmap_reg_range(0x21000c, 0x21000d),
+};
+
+static const struct regmap_access_table rtc_rd_regs = {
+ .yes_ranges = rtc_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(rtc_rd_ranges),
+};
+
+static const struct regmap_range rtc_wr_ranges[] = {
+ regmap_reg_range(0x200000, 0x200010),
+ regmap_reg_range(0x204000, 0x204000),
+ regmap_reg_range(0x210000, 0x210001),
+ regmap_reg_range(0x21000d, 0x21000d),
+};
+
+static const struct regmap_access_table rtc_wr_regs = {
+ .yes_ranges = rtc_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(rtc_wr_ranges),
+};
+
+static const struct regmap_config gamecube_rtc_regmap_config = {
+ .reg_bits = 24,
+ .val_bits = 32,
+ .rd_table = &rtc_rd_regs,
+ .wr_table = &rtc_wr_regs,
+ .max_register = 0x21000d,
+ .name = "gamecube-rtc",
+};
+
+static int gamecube_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtc_device *rtc;
+ struct priv *d;
+ int ret;
+
+ d = devm_kzalloc(dev, sizeof(struct priv), GFP_KERNEL);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+
+ d->iob = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(d->iob))
+ return PTR_ERR(d->iob);
+
+ d->regmap = devm_regmap_init(dev, &exi_bus, d,
+ &gamecube_rtc_regmap_config);
+ if (IS_ERR(d->regmap))
+ return PTR_ERR(d->regmap);
+
+ ret = gamecube_rtc_read_offset_from_sram(d);
+ if (ret)
+ return ret;
+ dev_dbg(dev, "SRAM bias: 0x%x", d->rtc_bias);
+
+ dev_set_drvdata(dev, d);
+
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ /* We can represent further than that, but it depends on the stored
+ * bias and we can’t modify it persistently on all supported consoles,
+ * so here we pretend to be limited to 2106.
+ */
+ rtc->range_min = 0;
+ rtc->range_max = U32_MAX;
+ rtc->ops = &gamecube_rtc_ops;
+
+ devm_rtc_register_device(rtc);
+
+ return 0;
+}
+
+static const struct of_device_id gamecube_rtc_of_match[] = {
+ {.compatible = "nintendo,latte-exi" },
+ {.compatible = "nintendo,hollywood-exi" },
+ {.compatible = "nintendo,flipper-exi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gamecube_rtc_of_match);
+
+static struct platform_driver gamecube_rtc_driver = {
+ .probe = gamecube_rtc_probe,
+ .driver = {
+ .name = "rtc-gamecube",
+ .of_match_table = gamecube_rtc_of_match,
+ },
+};
+module_platform_driver(gamecube_rtc_driver);
+
+MODULE_AUTHOR("Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>");
+MODULE_DESCRIPTION("Nintendo GameCube, Wii and Wii U RTC driver");
+MODULE_LICENSE("GPL");
--
2.33.1
^ permalink raw reply related
* [PATCH v2 4/5] powerpc: gamecube_defconfig: Enable the RTC driver
From: Emmanuel Gil Peyrot @ 2021-10-27 22:35 UTC (permalink / raw)
To: Alexandre Belloni, Alessandro Zummo
Cc: linux-rtc, devicetree, Emmanuel Gil Peyrot, linux-kernel,
rw-r-r-0644, Rob Herring, Paul Mackerras, Ash Logan, linuxppc-dev,
Jonathan Neuschäfer
In-Reply-To: <20211027223516.2031-1-linkmauve@linkmauve.fr>
This selects the rtc-gamecube driver, which provides a real-time clock
on this platform.
Signed-off-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
---
arch/powerpc/configs/gamecube_defconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig
index 24c0e0ea5aeb..91a1b99f4e8f 100644
--- a/arch/powerpc/configs/gamecube_defconfig
+++ b/arch/powerpc/configs/gamecube_defconfig
@@ -68,7 +68,7 @@ CONFIG_SND_SEQUENCER=y
CONFIG_SND_SEQUENCER_OSS=y
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_GENERIC=y
+CONFIG_RTC_DRV_GAMECUBE=y
CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y
CONFIG_ISO9660_FS=y
--
2.33.1
^ permalink raw reply related
* [PATCH v2 00/45] Introduce power-off+restart call chain API
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
Problem
-------
SoC devices require power-off call chaining functionality from kernel.
We have a widely used restart chaining provided by restart notifier API,
but nothing for power-off.
Solution
--------
Introduce new API that provides both restart and power-off call chains.
Why combine restart with power-off? Because drivers often do both.
More practical to have API that provides both under the same roof.
The new API is designed with simplicity and extensibility in mind.
It's built upon the existing restart and reboot APIs. The simplicity
is in new helper functions that are convenient for drivers. The
extensibility is in the design that doesn't hardcode callback
arguments, making easy to add new parameters and remove old.
This is a third attempt to introduce the new API. First was made by
Guenter Roeck back in 2014, second was made by Thierry Reding in 2017.
In fact the work didn't stop and recently arm_pm_restart() was removed
from v5.14 kernel, which was a part of preparatory work started by
Guenter Roeck. I took into account experience and ideas from the
previous attempts, extended and polished them.
Adoption plan
-------------
This patchset introduces the new API. It also converts multiple drivers
and arch code to the new API to demonstrate how it all looks in practice.
The plan is:
1. Merge new API (patches 1-8). This API will co-exist with the old APIs.
2. Convert arch code to do_kernel_power_off() (patches 9-21).
3. Convert drivers and platform code to the new API.
4. Remove obsolete pm_power_off and pm_power_off_prepare variables.
5. Make restart-notifier API private to kernel/reboot.c once no users left.
Results
-------
1. Devices can be powered off properly.
2. Global variables are removed from drivers.
3. Global pm_power_off and pm_power_off_prepare callback variables are
removed once all users are converted to the new API. The latter callback
is removed by patch #25 of this series.
4. Ambiguous call chain ordering is prohibited. See patch #5 which adds
verification of restart handlers priorities, ensuring that they are unique.
Changelog:
v2: - Replaced standalone power-off call chain demo-API with the combined
power-off+restart API because this is what drivers want. It's a more
comprehensive solution.
- Converted multiple drivers and arch code to the new API. Suggested by
Andy Shevchenko. I skimmed through the rest of drivers, verifying that
new API suits them. The rest of the drivers will be converted once we
will settle on the new API, otherwise will be too many patches here.
- v2 API doesn't expose notifier to users and require handlers to
have unique priority. Suggested by Guenter Roeck.
- v2 API has power-off chaining disabled by default and require
drivers to explicitly opt-in to the chaining. This preserves old
behaviour for existing drivers once they are converted to the new
API.
Dmitry Osipenko (45):
notifier: Remove extern annotation from function prototypes
notifier: Add blocking_notifier_call_chain_empty()
notifier: Add atomic/blocking_notifier_has_unique_priority()
reboot: Correct typo in a comment
reboot: Warn if restart handler has duplicated priority
reboot: Warn if unregister_restart_handler() fails
reboot: Remove extern annotation from function prototypes
kernel: Add combined power-off+restart handler call chain API
xen/x86: Use do_kernel_power_off()
ARM: Use do_kernel_power_off()
arm64: Use do_kernel_power_off()
csky: Use do_kernel_power_off()
ia64: Use do_kernel_power_off()
mips: Use do_kernel_power_off()
nds32: Use do_kernel_power_off()
parisc: Use do_kernel_power_off()
powerpc: Use do_kernel_power_off()
riscv: Use do_kernel_power_off()
sh: Use do_kernel_power_off()
x86: Use do_kernel_power_off()
m68k: Switch to new power-handler API
memory: emif: Use kernel_can_power_off()
ACPI: power: Switch to power-handler API
regulator: pfuze100: Use devm_register_power_handler()
reboot: Remove pm_power_off_prepare()
soc/tegra: pmc: Utilize power-handler API to power off Nexus 7
properly
mfd: ntxec: Use devm_register_power_handler()
mfd: rn5t618: Use devm_register_power_handler()
mfd: acer-a500: Use devm_register_power_handler()
mfd: ene-kb3930: Use devm_register_power_handler()
mfd: axp20x: Use register_simple_power_off_handler()
mfd: retu: Use devm_register_simple_power_off_handler()
mfd: rk808: Use devm_register_simple_power_off_handler()
mfd: palmas: Use devm_register_simple_power_off_handler()
mfd: max8907: Use devm_register_simple_power_off_handler()
mfd: tps6586x: Use devm_register_simple_power_off_handler()
mfd: tps65910: Use devm_register_simple_power_off_handler()
mfd: max77620: Use devm_register_simple_power_off_handler()
mfd: dm355evm_msp: Use devm_register_trivial_power_off_handler()
mfd: twl4030: Use devm_register_trivial_power_off_handler()
mfd: ab8500: Use devm_register_trivial_power_off_handler()
reset: ath79: Use devm_register_simple_restart_handler()
reset: intel-gw: Use devm_register_simple_restart_handler()
reset: lpc18xx: Use devm_register_prioritized_restart_handler()
reset: npcm: Use devm_register_prioritized_restart_handler()
arch/arm/kernel/reboot.c | 4 +-
arch/arm64/kernel/process.c | 3 +-
arch/csky/kernel/power.c | 6 +-
arch/ia64/kernel/process.c | 4 +-
arch/m68k/emu/natfeat.c | 3 +-
arch/m68k/include/asm/machdep.h | 1 -
arch/m68k/kernel/process.c | 5 +-
arch/m68k/kernel/setup_mm.c | 1 -
arch/m68k/kernel/setup_no.c | 1 -
arch/m68k/mac/config.c | 4 +-
arch/mips/kernel/reset.c | 3 +-
arch/nds32/kernel/process.c | 3 +-
arch/parisc/kernel/process.c | 4 +-
arch/powerpc/kernel/setup-common.c | 4 +-
arch/powerpc/xmon/xmon.c | 3 +-
arch/riscv/kernel/reset.c | 12 +-
arch/sh/kernel/reboot.c | 3 +-
arch/x86/kernel/reboot.c | 4 +-
arch/x86/xen/enlighten_pv.c | 4 +-
drivers/acpi/sleep.c | 25 +-
drivers/memory/emif.c | 2 +-
drivers/mfd/ab8500-sysctrl.c | 17 +-
drivers/mfd/acer-ec-a500.c | 52 +--
drivers/mfd/axp20x.c | 22 +-
drivers/mfd/dm355evm_msp.c | 20 +-
drivers/mfd/ene-kb3930.c | 45 +-
drivers/mfd/max77620.c | 21 +-
drivers/mfd/max8907.c | 22 +-
drivers/mfd/ntxec.c | 50 +-
drivers/mfd/palmas.c | 24 +-
drivers/mfd/retu-mfd.c | 31 +-
drivers/mfd/rk808.c | 23 +-
drivers/mfd/rn5t618.c | 56 +--
drivers/mfd/tps6586x.c | 21 +-
drivers/mfd/tps65910.c | 17 +-
drivers/mfd/twl4030-power.c | 10 +-
drivers/regulator/pfuze100-regulator.c | 39 +-
drivers/reset/reset-ath79.c | 15 +-
drivers/reset/reset-intel-gw.c | 13 +-
drivers/reset/reset-lpc18xx.c | 14 +-
drivers/reset/reset-npcm.c | 14 +-
drivers/soc/tegra/pmc.c | 54 ++-
include/linux/mfd/axp20x.h | 1 +
include/linux/notifier.h | 37 +-
include/linux/pm.h | 1 -
include/linux/reboot.h | 216 ++++++++-
kernel/notifier.c | 88 ++++
kernel/power/hibernate.c | 2 +-
kernel/reboot.c | 615 ++++++++++++++++++++++++-
49 files changed, 1209 insertions(+), 430 deletions(-)
--
2.33.1
^ permalink raw reply
* [PATCH v2 01/45] notifier: Remove extern annotation from function prototypes
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
There is no need to annotate function prototypes with 'extern', it makes
code less readable. Remove unnecessary annotations from <notifier.h>.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/notifier.h | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 87069b8459af..4b80a815b666 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -90,7 +90,7 @@ struct srcu_notifier_head {
} while (0)
/* srcu_notifier_heads must be cleaned up dynamically */
-extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
+void srcu_init_notifier_head(struct srcu_notifier_head *nh);
#define srcu_cleanup_notifier_head(name) \
cleanup_srcu_struct(&(name)->srcu);
@@ -141,36 +141,36 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
#ifdef __KERNEL__
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
-extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *nb);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *nb);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
+int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
struct notifier_block *nb);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
struct notifier_block *nb);
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
+int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v);
-extern int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
+int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
-extern int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
+int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
#define NOTIFY_DONE 0x0000 /* Don't care */
--
2.33.1
^ permalink raw reply related
* [PATCH v2 02/45] notifier: Add blocking_notifier_call_chain_empty()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Add blocking_notifier_call_chain_empty() that returns true if call chain
is empty.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/notifier.h | 2 ++
kernel/notifier.c | 14 ++++++++++++++
2 files changed, 16 insertions(+)
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 4b80a815b666..054271e9cb20 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -173,6 +173,8 @@ int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
unsigned long val_up, unsigned long val_down, void *v);
+bool blocking_notifier_call_chain_empty(struct blocking_notifier_head *nh);
+
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index b8251dc0bc0f..1f7ba8988b90 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -322,6 +322,20 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
+/**
+ * blocking_notifier_call_chain_empty - Check whether notifier chain is empty
+ * @nh: Pointer to head of the blocking notifier chain
+ *
+ * Checks whether notifier chain is empty.
+ *
+ * Returns true is notifier chain is empty, false otherwise.
+ */
+bool blocking_notifier_call_chain_empty(struct blocking_notifier_head *nh)
+{
+ return !rcu_access_pointer(nh->head);
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_empty);
+
/*
* Raw notifier chain routines. There is no protection;
* the caller must provide it. Use at your own risk!
--
2.33.1
^ permalink raw reply related
* [PATCH v2 03/45] notifier: Add atomic/blocking_notifier_has_unique_priority()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Add atomic/blocking_notifier_has_unique_priority() helpers which return
true if given handler has unique priority.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/notifier.h | 5 +++
kernel/notifier.c | 74 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 054271e9cb20..b782ce100022 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -175,6 +175,11 @@ int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
bool blocking_notifier_call_chain_empty(struct blocking_notifier_head *nh);
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+ struct notifier_block *nb);
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+ struct notifier_block *nb);
+
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 1f7ba8988b90..cf0e1c4bd364 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -203,6 +203,40 @@ int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
NOKPROBE_SYMBOL(atomic_notifier_call_chain);
+/**
+ * atomic_notifier_has_unique_priority - Checks whether notifier's priority is unique
+ * @nh: Pointer to head of the atomic notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool atomic_notifier_has_unique_priority(struct atomic_notifier_head *nh,
+ struct notifier_block *n)
+{
+ struct notifier_block **nl = &nh->head;
+ unsigned long flags;
+ bool ret = true;
+
+ spin_lock_irqsave(&nh->lock, flags);
+
+ while ((*nl) != NULL && (*nl)->priority >= n->priority) {
+ if ((*nl)->priority == n->priority && (*nl) != n) {
+ ret = false;
+ break;
+ }
+
+ nl = &((*nl)->next);
+ }
+
+ spin_unlock_irqrestore(&nh->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atomic_notifier_has_unique_priority);
+
/*
* Blocking notifier chain routines. All access to the chain is
* synchronized by an rwsem.
@@ -336,6 +370,46 @@ bool blocking_notifier_call_chain_empty(struct blocking_notifier_head *nh)
}
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_empty);
+/**
+ * blocking_notifier_has_unique_priority - Checks whether notifier's priority is unique
+ * @nh: Pointer to head of the blocking notifier chain
+ * @n: Entry in notifier chain to check
+ *
+ * Checks whether there is another notifier in the chain with the same priority.
+ * Must be called in process context.
+ *
+ * Returns true if priority is unique, false otherwise.
+ */
+bool blocking_notifier_has_unique_priority(struct blocking_notifier_head *nh,
+ struct notifier_block *n)
+{
+ struct notifier_block **nl = &nh->head;
+ bool ret = true;
+
+ /*
+ * This code gets used during boot-up, when task switching is
+ * not yet working and interrupts must remain disabled. At
+ * such times we must not call down_write().
+ */
+ if (system_state != SYSTEM_BOOTING)
+ down_write(&nh->rwsem);
+
+ while ((*nl) != NULL && (*nl)->priority >= n->priority) {
+ if ((*nl)->priority == n->priority && (*nl) != n) {
+ ret = false;
+ break;
+ }
+
+ nl = &((*nl)->next);
+ }
+
+ if (system_state != SYSTEM_BOOTING)
+ up_write(&nh->rwsem);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_has_unique_priority);
+
/*
* Raw notifier chain routines. There is no protection;
* the caller must provide it. Use at your own risk!
--
2.33.1
^ permalink raw reply related
* [PATCH v2 04/45] reboot: Correct typo in a comment
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Correct s/implemenations/implementations/ in <reboot.h>.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/reboot.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index af907a3d68d1..7c288013a3ca 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -63,7 +63,7 @@ struct pt_regs;
extern void machine_crash_shutdown(struct pt_regs *);
/*
- * Architecture independent implemenations of sys_reboot commands.
+ * Architecture independent implementations of sys_reboot commands.
*/
extern void kernel_restart_prepare(char *cmd);
--
2.33.1
^ permalink raw reply related
* [PATCH v2 05/45] reboot: Warn if restart handler has duplicated priority
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Add sanity check which ensures that there are no two restart handlers
registered with the same priority. Normally it's a direct sign of a
problem if two handlers use the same priority.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
kernel/reboot.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/kernel/reboot.c b/kernel/reboot.c
index efb40d095d1e..d39e599c3c99 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -182,7 +182,20 @@ static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
*/
int register_restart_handler(struct notifier_block *nb)
{
- return atomic_notifier_chain_register(&restart_handler_list, nb);
+ int ret;
+
+ ret = atomic_notifier_chain_register(&restart_handler_list, nb);
+ if (ret)
+ return ret;
+
+ /*
+ * Handler must have unique priority. Otherwise invocation order is
+ * determined by the registration order, which is presumed to be
+ * unreliable.
+ */
+ WARN_ON(!atomic_notifier_has_unique_priority(&restart_handler_list, nb));
+
+ return 0;
}
EXPORT_SYMBOL(register_restart_handler);
--
2.33.1
^ permalink raw reply related
* [PATCH v2 06/45] reboot: Warn if unregister_restart_handler() fails
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Emit warning if unregister_restart_handler() fails since it never should
fail. This will ease further API development by catching mistakes early.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
kernel/reboot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/reboot.c b/kernel/reboot.c
index d39e599c3c99..291d44082f42 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -210,7 +210,7 @@ EXPORT_SYMBOL(register_restart_handler);
*/
int unregister_restart_handler(struct notifier_block *nb)
{
- return atomic_notifier_chain_unregister(&restart_handler_list, nb);
+ return WARN_ON(atomic_notifier_chain_unregister(&restart_handler_list, nb));
}
EXPORT_SYMBOL(unregister_restart_handler);
--
2.33.1
^ permalink raw reply related
* [PATCH v2 07/45] reboot: Remove extern annotation from function prototypes
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
There is no need to annotate function prototypes with 'extern', it makes
code less readable. Remove unnecessary annotations from <reboot.h>.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/reboot.h | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 7c288013a3ca..b7fa25726323 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -40,36 +40,36 @@ extern int reboot_cpu;
extern int reboot_force;
-extern int register_reboot_notifier(struct notifier_block *);
-extern int unregister_reboot_notifier(struct notifier_block *);
+int register_reboot_notifier(struct notifier_block *);
+int unregister_reboot_notifier(struct notifier_block *);
-extern int devm_register_reboot_notifier(struct device *, struct notifier_block *);
+int devm_register_reboot_notifier(struct device *, struct notifier_block *);
-extern int register_restart_handler(struct notifier_block *);
-extern int unregister_restart_handler(struct notifier_block *);
-extern void do_kernel_restart(char *cmd);
+int register_restart_handler(struct notifier_block *);
+int unregister_restart_handler(struct notifier_block *);
+void do_kernel_restart(char *cmd);
/*
* Architecture-specific implementations of sys_reboot commands.
*/
-extern void migrate_to_reboot_cpu(void);
-extern void machine_restart(char *cmd);
-extern void machine_halt(void);
-extern void machine_power_off(void);
+void migrate_to_reboot_cpu(void);
+void machine_restart(char *cmd);
+void machine_halt(void);
+void machine_power_off(void);
-extern void machine_shutdown(void);
+void machine_shutdown(void);
struct pt_regs;
-extern void machine_crash_shutdown(struct pt_regs *);
+void machine_crash_shutdown(struct pt_regs *);
/*
* Architecture independent implementations of sys_reboot commands.
*/
-extern void kernel_restart_prepare(char *cmd);
-extern void kernel_restart(char *cmd);
-extern void kernel_halt(void);
-extern void kernel_power_off(void);
+void kernel_restart_prepare(char *cmd);
+void kernel_restart(char *cmd);
+void kernel_halt(void);
+void kernel_power_off(void);
extern int C_A_D; /* for sysctl */
void ctrl_alt_del(void);
@@ -77,15 +77,15 @@ void ctrl_alt_del(void);
#define POWEROFF_CMD_PATH_LEN 256
extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
-extern void orderly_poweroff(bool force);
-extern void orderly_reboot(void);
+void orderly_poweroff(bool force);
+void orderly_reboot(void);
void hw_protection_shutdown(const char *reason, int ms_until_forced);
/*
* Emergency restart, callable from an interrupt handler.
*/
-extern void emergency_restart(void);
+void emergency_restart(void);
#include <asm/emergency-restart.h>
#endif /* _LINUX_REBOOT_H */
--
2.33.1
^ permalink raw reply related
* [PATCH v2 08/45] kernel: Add combined power-off+restart handler call chain API
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
SoC platforms often have multiple options of how to perform system's
power-off and restart operations. Meanwhile today's kernel is limited to
a single option. Add combined power-off+restart handler call chain API,
which is inspired by the restart API. The new API provides both power-off
and restart functionality.
The old pm_power_off method will be kept around till all users are
converted to the new API.
Current restart API will be replaced by the new unified API since
new API is its superset. The restart functionality of the power-handler
API is built upon the existing restart-notifier APIs.
In order to ease conversion to the new API, convenient helpers are added
for the common use-cases. They will reduce amount of boilerplate code and
remove global variables. These helpers preserve old behaviour for cases
where only one power-off handler is executed, this is what existing
drivers want, and thus, they could be easily converted to the new API.
Users of the new API should explicitly enable power-off chaining by
setting corresponding flag of the power_handler structure.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
include/linux/reboot.h | 176 +++++++++++-
kernel/power/hibernate.c | 2 +-
kernel/reboot.c | 601 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 768 insertions(+), 11 deletions(-)
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index b7fa25726323..0ec835338c27 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -8,10 +8,16 @@
struct device;
-#define SYS_DOWN 0x0001 /* Notify of system down */
-#define SYS_RESTART SYS_DOWN
-#define SYS_HALT 0x0002 /* Notify of system halt */
-#define SYS_POWER_OFF 0x0003 /* Notify of system power off */
+enum reboot_prepare_mode {
+ SYS_DOWN = 1, /* Notify of system down */
+ SYS_RESTART = SYS_DOWN,
+ SYS_HALT, /* Notify of system halt */
+ SYS_POWER_OFF, /* Notify of system power off */
+};
+
+#define RESTART_PRIO_RESERVED 0
+#define RESTART_PRIO_DEFAULT 128
+#define RESTART_PRIO_HIGH 192
enum reboot_mode {
REBOOT_UNDEFINED = -1,
@@ -49,6 +55,167 @@ int register_restart_handler(struct notifier_block *);
int unregister_restart_handler(struct notifier_block *);
void do_kernel_restart(char *cmd);
+/*
+ * Unified poweroff + restart API.
+ */
+
+#define POWEROFF_PRIO_RESERVED 0
+#define POWEROFF_PRIO_PLATFORM 1
+#define POWEROFF_PRIO_DEFAULT 128
+#define POWEROFF_PRIO_HIGH 192
+#define POWEROFF_PRIO_FIRMWARE 224
+
+enum poweroff_mode {
+ POWEROFF_NORMAL = 0,
+ POWEROFF_PREPARE,
+};
+
+struct power_off_data {
+ void *cb_data;
+};
+
+struct power_off_prep_data {
+ void *cb_data;
+};
+
+struct restart_data {
+ void *cb_data;
+ const char *cmd;
+ enum reboot_mode mode;
+};
+
+struct reboot_prep_data {
+ void *cb_data;
+ const char *cmd;
+ enum reboot_prepare_mode mode;
+};
+
+struct power_handler_private_data {
+ struct notifier_block reboot_prep_nb;
+ struct notifier_block power_off_nb;
+ struct notifier_block restart_nb;
+ void (*trivial_power_off_cb)(void);
+ void (*simple_power_off_cb)(void *data);
+ void *simple_power_off_cb_data;
+ bool registered;
+};
+
+/**
+ * struct power_handler - Machine power-off + restart handler
+ *
+ * Describes power-off and restart handlers which are invoked by kernel
+ * to power off or restart this machine. Supports prioritized chaining for
+ * both restart and power-off handlers. Callback's priority must be unique.
+ * Intended to be used by device drivers that are responsible for restarting
+ * and powering off hardware which kernel is running on.
+ *
+ * Struct power_handler can be static. Members of this structure must not be
+ * altered while handler is registered.
+ *
+ * Fill the structure members and pass it to register_power_handler().
+ */
+struct power_handler {
+ /**
+ * @cb_data:
+ *
+ * User data included in callback's argument.
+ */
+ void *cb_data;
+
+ /**
+ * @power_off_cb:
+ *
+ * Callback that should turn off machine. Inactive if NULL.
+ */
+ void (*power_off_cb)(struct power_off_data *data);
+
+ /**
+ * @power_off_prepare_cb:
+ *
+ * Power-off preparation callback. All power-off preparation callbacks
+ * are invoked before @restart_cb. Inactive if NULL.
+ */
+ void (*power_off_prepare_cb)(struct power_off_prep_data *data);
+
+ /**
+ * @power_off_priority:
+ *
+ * Power-off callback priority, must be unique. Zero value is
+ * reassigned to default priority. Inactive if @power_off_cb is NULL.
+ */
+ int power_off_priority;
+
+ /**
+ * @power_off_chaining_allowed:
+ *
+ * False if callbacks execution should stop when @power_off_cb fails
+ * to power off machine. True if further lower priority power-off
+ * callback should be executed.
+ */
+ bool power_off_chaining_allowed;
+
+ /**
+ * @restart_cb:
+ *
+ * Callback that should reboot machine. Inactive if NULL.
+ */
+ void (*restart_cb)(struct restart_data *data);
+
+ /**
+ * @restart_priority:
+ *
+ * Restart callback priority, must be unique. Zero value is reassigned
+ * to default priority. Inactive if @restart_cb is NULL.
+ */
+ int restart_priority;
+
+ /**
+ * @reboot_prepare_cb:
+ *
+ * Reboot preparation callback. All reboot preparation callbacks are
+ * invoked before @restart_cb. Inactive if NULL.
+ */
+ void (*reboot_prepare_cb)(struct reboot_prep_data *data);
+
+ /**
+ * @priv:
+ *
+ * Internal data. Shouldn't be touched.
+ */
+ const struct power_handler_private_data priv;
+};
+
+int register_power_handler(struct power_handler *handler);
+void unregister_power_handler(struct power_handler *handler);
+
+struct power_handler *
+register_simple_power_off_handler(void (*callback)(void *data), void *data);
+
+void unregister_simple_power_off_handler(struct power_handler *handler);
+
+int devm_register_power_handler(struct device *dev,
+ struct power_handler *handler);
+
+int devm_register_simple_power_off_handler(struct device *dev,
+ void (*callback)(void *data),
+ void *data);
+
+int devm_register_trivial_power_off_handler(struct device *dev,
+ void (*callback)(void));
+
+int devm_register_simple_restart_handler(struct device *dev,
+ void (*callback)(struct restart_data *data),
+ void *data);
+
+int devm_register_prioritized_restart_handler(struct device *dev,
+ int priority,
+ void (*callback)(struct restart_data *data),
+ void *data);
+
+int register_platform_power_off(void (*power_off)(void));
+
+void do_kernel_power_off(void);
+
/*
* Architecture-specific implementations of sys_reboot commands.
*/
@@ -70,6 +237,7 @@ void kernel_restart_prepare(char *cmd);
void kernel_restart(char *cmd);
void kernel_halt(void);
void kernel_power_off(void);
+bool kernel_can_power_off(void);
extern int C_A_D; /* for sysctl */
void ctrl_alt_del(void);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 559acef3fddb..13ad98352fde 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -664,7 +664,7 @@ static void power_down(void)
hibernation_platform_enter();
fallthrough;
case HIBERNATION_SHUTDOWN:
- if (pm_power_off)
+ if (kernel_can_power_off())
kernel_power_off();
break;
}
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 291d44082f42..779429726616 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -189,9 +189,8 @@ int register_restart_handler(struct notifier_block *nb)
return ret;
/*
- * Handler must have unique priority. Otherwise invocation order is
- * determined by the registration order, which is presumed to be
- * unreliable.
+ * Handler must have unique priority. Otherwise call order is
+ * determined by registration order, which is unreliable.
*/
WARN_ON(!atomic_notifier_has_unique_priority(&restart_handler_list, nb));
@@ -294,6 +293,587 @@ void kernel_halt(void)
}
EXPORT_SYMBOL_GPL(kernel_halt);
+/*
+ * Notifier list for kernel code which wants to be called
+ * to power off the system.
+ */
+static BLOCKING_NOTIFIER_HEAD(power_off_handler_list);
+
+static void dummy_pm_power_off(void)
+{
+ /* temporary stub until pm_power_off() is gone, see more below */
+}
+
+static struct notifier_block *pm_power_off_nb;
+
+/**
+ * register_power_off_handler - Register function to be called to power off
+ * the system
+ * @nb: Info about handler function to be called
+ * @nb->priority: Handler priority. Handlers should follow the
+ * following guidelines for setting priorities.
+ * 0: Power-off handler of last resort,
+ * with limited power-off capabilities
+ * 128: Default power-off handler; use if no other
+ * power-off handler is expected to be available,
+ * and/or if power-off functionality is
+ * sufficient to power-off the entire system
+ * 255: Highest priority power-off handler, will
+ * preempt all other power-off handlers
+ *
+ * Registers a function with code to be called to power off the
+ * system.
+ *
+ * Registered functions will be called as last step of the power-off
+ * sequence.
+ *
+ * Registered functions are expected to power off the system immediately.
+ * If more than one function is registered, the power-off handler priority
+ * selects which function will be called first.
+ *
+ * Power-off handlers are expected to be registered from non-architecture
+ * code, typically from drivers. A typical use case would be a system
+ * where power-off functionality is provided through a PMIC. Multiple
+ * power-off handlers may exist; for example, one power-off handler might
+ * turn off the entire system, while another only turns off part of
+ * system. In such cases, the power-off handler which only disables part
+ * of the hardware is expected to register with low priority to ensure
+ * that it only runs if no other means to power off the system is
+ * available.
+ *
+ * Currently always returns zero, as blocking_notifier_chain_register()
+ * always returns zero.
+ */
+static int register_power_off_handler(struct notifier_block *nb)
+{
+ int ret;
+
+ ret = blocking_notifier_chain_register(&power_off_handler_list, nb);
+ if (ret)
+ return ret;
+
+ /*
+ * Handler must have unique priority. Otherwise invocation order is
+ * determined by the registration order, which is presumed to be
+ * unreliable.
+ */
+ WARN_ON(!blocking_notifier_has_unique_priority(&power_off_handler_list, nb));
+
+ /*
+ * Some drivers check whether pm_power_off was already installed.
+ * Install dummy callback using new API to preserve old behaviour
+ * for those drivers during period of transition to the new API.
+ */
+ if (!pm_power_off) {
+ pm_power_off = dummy_pm_power_off;
+ pm_power_off_nb = nb;
+ }
+
+ return 0;
+}
+
+static void unregister_power_off_handler(struct notifier_block *nb)
+{
+ if (nb == pm_power_off_nb) {
+ /*
+ * Check whether somebody replaced pm_power_off behind
+ * out back.
+ */
+ if (!WARN_ON(pm_power_off != dummy_pm_power_off))
+ pm_power_off = NULL;
+
+ pm_power_off_nb = NULL;
+ }
+
+ WARN_ON(blocking_notifier_chain_unregister(&power_off_handler_list, nb));
+}
+
+static void devm_unregister_power_off_handler(void *data)
+{
+ struct notifier_block *nb = data;
+
+ unregister_power_off_handler(nb);
+}
+
+static int devm_register_power_off_handler(struct device *dev,
+ struct notifier_block *nb)
+{
+ int err;
+
+ err = register_power_off_handler(nb);
+ if (err)
+ return err;
+
+ return devm_add_action_or_reset(dev, devm_unregister_power_off_handler,
+ nb);
+}
+
+static int power_handler_power_off(struct notifier_block *nb,
+ unsigned long mode, void *unused)
+{
+ struct power_off_prep_data prep_data = {};
+ struct power_handler_private_data *priv;
+ struct power_off_data data = {};
+ struct power_handler *h;
+ int ret = NOTIFY_DONE;
+
+ priv = container_of(nb, struct power_handler_private_data, power_off_nb);
+ h = container_of(priv, struct power_handler, priv);
+ prep_data.cb_data = h->cb_data;
+ data.cb_data = h->cb_data;
+
+ switch (mode) {
+ case POWEROFF_NORMAL:
+ if (h->power_off_cb)
+ h->power_off_cb(&data);
+
+ if (priv->simple_power_off_cb)
+ priv->simple_power_off_cb(priv->simple_power_off_cb_data);
+
+ if (priv->trivial_power_off_cb)
+ priv->trivial_power_off_cb();
+
+ if (!h->power_off_chaining_allowed)
+ ret = NOTIFY_STOP;
+
+ break;
+
+ case POWEROFF_PREPARE:
+ if (h->power_off_prepare_cb)
+ h->power_off_prepare_cb(&prep_data);
+
+ break;
+
+ default:
+ unreachable();
+ }
+
+ return ret;
+}
+
+static int power_handler_restart(struct notifier_block *nb,
+ unsigned long mode, void *cmd)
+{
+ struct power_handler_private_data *priv;
+ struct restart_data data = {};
+ struct power_handler *h;
+
+ priv = container_of(nb, struct power_handler_private_data, restart_nb);
+ h = container_of(priv, struct power_handler, priv);
+
+ data.cb_data = h->cb_data;
+ data.mode = mode;
+ data.cmd = cmd;
+
+ h->restart_cb(&data);
+
+ return NOTIFY_DONE;
+}
+
+static int power_handler_restart_prep(struct notifier_block *nb,
+ unsigned long mode, void *cmd)
+{
+ struct power_handler_private_data *priv;
+ struct reboot_prep_data data = {};
+ struct power_handler *h;
+
+ priv = container_of(nb, struct power_handler_private_data, reboot_prep_nb);
+ h = container_of(priv, struct power_handler, priv);
+
+ data.cb_data = h->cb_data;
+ data.mode = mode;
+ data.cmd = cmd;
+
+ h->reboot_prepare_cb(&data);
+
+ return NOTIFY_DONE;
+}
+
+static struct power_handler_private_data *
+power_handler_private_data(struct power_handler *handler)
+{
+ return (struct power_handler_private_data *)&handler->priv;
+}
+
+/**
+ * devm_register_power_handler - Register power handler
+ * @dev: Device that registers handler
+ * @handler: Power handler descriptor
+ *
+ * Registers power handler that will be called as last step of the
+ * power-off and restart sequences.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int register_power_handler(struct power_handler *handler)
+{
+ struct power_handler_private_data *priv = power_handler_private_data(handler);
+ int err, priority;
+
+ /* sanity-check whether handler is registered twice */
+ if (WARN_ON(priv->registered))
+ return -EBUSY;
+
+ if (handler->power_off_cb || handler->power_off_prepare_cb) {
+ if (handler->power_off_priority == POWEROFF_PRIO_RESERVED)
+ priority = POWEROFF_PRIO_DEFAULT;
+ else
+ priority = handler->power_off_priority;
+
+ priv->power_off_nb.notifier_call = power_handler_power_off;
+ priv->power_off_nb.priority = priority;
+
+ err = register_power_off_handler(&priv->power_off_nb);
+ if (err)
+ goto reset_power_handler;
+ }
+
+ if (handler->restart_cb) {
+ if (handler->restart_priority == RESTART_PRIO_RESERVED)
+ priority = RESTART_PRIO_DEFAULT;
+ else
+ priority = handler->restart_priority;
+
+ priv->restart_nb.notifier_call = power_handler_restart;
+ priv->restart_nb.priority = priority;
+
+ err = register_restart_handler(&priv->restart_nb);
+ if (err)
+ goto unreg_power_off_handler;
+ }
+
+ if (handler->reboot_prepare_cb) {
+ priv->reboot_prep_nb.notifier_call = power_handler_restart_prep;
+ priv->reboot_prep_nb.priority = 0;
+
+ err = register_reboot_notifier(&priv->reboot_prep_nb);
+ if (err)
+ goto unreg_restart_handler;
+ }
+
+ priv->registered = true;
+
+ return 0;
+
+unreg_restart_handler:
+ if (handler->restart_cb)
+ unregister_restart_handler(&priv->restart_nb);
+
+unreg_power_off_handler:
+ if (handler->power_off_cb)
+ unregister_power_off_handler(&priv->power_off_nb);
+
+reset_power_handler:
+ memset(priv, 0, sizeof(*priv));
+
+ return err;
+}
+EXPORT_SYMBOL(register_power_handler);
+
+/**
+ * unregister_power_handler - Unregister power handler
+ * @handler: Power handler descriptor
+ *
+ * Unregisters a previously registered power handler. Does nothing if
+ * handler is NULL.
+ */
+void unregister_power_handler(struct power_handler *handler)
+{
+ struct power_handler_private_data *priv;
+
+ if (!handler)
+ return;
+
+ priv = power_handler_private_data(handler);
+
+ /* sanity-check whether handler is unregistered twice */
+ if (WARN_ON(!priv->registered))
+ return;
+
+ if (handler->reboot_prepare_cb)
+ unregister_reboot_notifier(&priv->reboot_prep_nb);
+
+ if (handler->restart_cb)
+ unregister_restart_handler(&priv->restart_nb);
+
+ if (handler->power_off_cb)
+ unregister_power_off_handler(&priv->power_off_nb);
+
+ memset(priv, 0, sizeof(*priv));
+}
+EXPORT_SYMBOL(unregister_power_handler);
+
+static void devm_unregister_power_handler(void *data)
+{
+ struct power_handler *handler = data;
+
+ unregister_power_handler(handler);
+}
+
+/**
+ * devm_register_power_handler - Register power handler
+ * @dev: Device that registers handler
+ * @handler: Power handler descriptor
+ *
+ * Resource-managed variant of register_power_handler();
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int devm_register_power_handler(struct device *dev,
+ struct power_handler *handler)
+{
+ int err;
+
+ err = register_power_handler(handler);
+ if (err)
+ return err;
+
+ return devm_add_action_or_reset(dev, devm_unregister_power_handler,
+ handler);
+}
+EXPORT_SYMBOL(devm_register_power_handler);
+
+/**
+ * register_simple_power_off_handler - Register simple power-off callback
+ * @dev: Device that registers callback
+ * @callback: Callback function
+ * @data: Callback's argument
+ *
+ * Registers power-off callback with default priority, it will be called
+ * as last step of the power-off sequence.
+ *
+ * Returns power_handler pointer on success, or ERR_PTR on failure.
+ */
+struct power_handler *
+register_simple_power_off_handler(void (*callback)(void *data), void *data)
+{
+ struct power_handler_private_data *priv;
+ struct power_handler *handler;
+ int err;
+
+ handler = kzalloc(sizeof(*handler), GFP_KERNEL);
+ if (!handler)
+ return ERR_PTR(-ENOMEM);
+
+ priv = power_handler_private_data(handler);
+
+ priv->power_off_nb.notifier_call = power_handler_power_off;
+ priv->power_off_nb.priority = POWEROFF_PRIO_DEFAULT;
+ priv->simple_power_off_cb_data = data;
+ priv->simple_power_off_cb = callback;
+
+ err = register_power_off_handler(&priv->power_off_nb);
+ if (err) {
+ kfree(handler);
+ return ERR_PTR(err);
+ }
+
+ return handler;
+}
+EXPORT_SYMBOL(register_simple_power_off_handler);
+
+/**
+ * unregister_power_handler - Unregister simple power-off handler
+ * @handler: Power handler descriptor
+ *
+ * Unregisters power handler that was registered by
+ * register_simple_power_off_handler(). Does nothing if handler is
+ * error or NULL.
+ */
+void unregister_simple_power_off_handler(struct power_handler *handler)
+{
+ struct power_handler_private_data *priv;
+
+ if (!IS_ERR_OR_NULL(handler)) {
+ priv = power_handler_private_data(handler);
+ unregister_power_off_handler(&priv->power_off_nb);
+ kfree(handler);
+ }
+}
+EXPORT_SYMBOL(unregister_simple_power_off_handler);
+
+/**
+ * devm_register_simple_power_off_handler - Register simple power-off callback
+ * @dev: Device that registers callback
+ * @callback: Callback function
+ * @data: Callback's argument
+ *
+ * Registers resource-managed power-off callback with default priority,
+ * it will be called as last step of the power-off sequence. Further
+ * lower priority callbacks won't be executed if this @callback fails.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int devm_register_simple_power_off_handler(struct device *dev,
+ void (*callback)(void *data),
+ void *data)
+{
+ struct power_handler_private_data *priv;
+ struct power_handler *handler;
+
+ handler = devm_kzalloc(dev, sizeof(*handler), GFP_KERNEL);
+ if (!handler)
+ return -ENOMEM;
+
+ priv = power_handler_private_data(handler);
+
+ priv->power_off_nb.notifier_call = power_handler_power_off;
+ priv->power_off_nb.priority = POWEROFF_PRIO_DEFAULT;
+ priv->simple_power_off_cb_data = data;
+ priv->simple_power_off_cb = callback;
+
+ return devm_register_power_off_handler(dev, &priv->power_off_nb);
+}
+EXPORT_SYMBOL(devm_register_simple_power_off_handler);
+
+/**
+ * devm_register_trivial_power_off_handler - Register trivial power-off callback
+ * @dev: Device that registers callback
+ * @desc: Callback descriptor
+ *
+ * Same as devm_register_simple_power_off_handler(), but callback
+ * doesn't take argument. Further lower priority callbacks won't be
+ * executed if this @callback fails.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int devm_register_trivial_power_off_handler(struct device *dev,
+ void (*callback)(void))
+{
+ struct power_handler_private_data *priv;
+ struct power_handler *handler;
+
+ handler = devm_kzalloc(dev, sizeof(*handler), GFP_KERNEL);
+ if (!handler)
+ return -ENOMEM;
+
+ priv = power_handler_private_data(handler);
+
+ priv->power_off_nb.notifier_call = power_handler_power_off;
+ priv->power_off_nb.priority = POWEROFF_PRIO_DEFAULT;
+ priv->trivial_power_off_cb = callback;
+
+ return devm_register_power_off_handler(dev, &priv->power_off_nb);
+}
+EXPORT_SYMBOL(devm_register_trivial_power_off_handler);
+
+/**
+ * devm_register_simple_restart_handler - Register simple restart callback
+ * @dev: Device that registers callback
+ * @callback: Callback function
+ * @data: Callback's argument
+ *
+ * Registers resource-managed restart callback with default priority,
+ * it will be called as last step of the restart sequence.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int devm_register_simple_restart_handler(struct device *dev,
+ void (*callback)(struct restart_data *data),
+ void *data)
+{
+ return devm_register_prioritized_restart_handler(dev,
+ RESTART_PRIO_DEFAULT,
+ callback, data);
+}
+EXPORT_SYMBOL(devm_register_simple_restart_handler);
+
+/**
+ * devm_register_prioritized_restart_handler - Register prioritized restart callback
+ * @dev: Device that registers callback
+ * @priority: Callback's priority
+ * @callback: Callback function
+ * @data: Callback's argument
+ *
+ * Registers resource-managed restart callback with a given priority,
+ * it will be called as last step of the restart sequence.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int devm_register_prioritized_restart_handler(struct device *dev,
+ int priority,
+ void (*callback)(struct restart_data *data),
+ void *data)
+{
+ struct power_handler *handler;
+
+ handler = devm_kzalloc(dev, sizeof(*handler), GFP_KERNEL);
+ if (!handler)
+ return -ENOMEM;
+
+ handler->restart_priority = priority;
+ handler->restart_cb = callback;
+ handler->cb_data = data;
+
+ return devm_register_power_handler(dev, handler);
+}
+EXPORT_SYMBOL(devm_register_prioritized_restart_handler);
+
+static struct power_handler platform_power_off_handler = {
+ .priv = {
+ .power_off_nb = {
+ .notifier_call = power_handler_power_off,
+ .priority = POWEROFF_PRIO_PLATFORM,
+ },
+ },
+};
+
+/**
+ * register_platform_power_off - Register platform-level power-off callback
+ * @power_off: Power-off callback
+ *
+ * Registers power-off callback that will be called as last step
+ * of the power-off sequence. This callback is expected to be invoked
+ * for the last resort. Further lower priority callbacks won't be
+ * executed if @power_off fails. Only one platform power-off callback
+ * is allowed to be registered.
+ *
+ * Returns zero on success, or error code on failure.
+ */
+int register_platform_power_off(void (*power_off)(void))
+{
+ struct power_handler_private_data *priv;
+
+ /* this function is allowed to be called only once */
+ if (WARN_ON(platform_power_off_handler.priv.trivial_power_off_cb))
+ return -EBUSY;
+
+ priv = power_handler_private_data(&platform_power_off_handler);
+ priv->trivial_power_off_cb = power_off;
+
+ return register_power_off_handler(&priv->power_off_nb);
+}
+
+/**
+ * do_kernel_power_off - Execute kernel power-off handler call chain
+ *
+ * Calls functions registered with register_power_off_handler.
+ *
+ * Expected to be called as last step of the power-off sequence.
+ *
+ * Powers off the system immediately if a power-off handler function has
+ * been registered. Otherwise does nothing.
+ */
+void do_kernel_power_off(void)
+{
+ /* legacy pm_power_off() is unchained and it has highest priority */
+ if (pm_power_off && pm_power_off != dummy_pm_power_off)
+ return pm_power_off();
+
+ blocking_notifier_call_chain(&power_off_handler_list, POWEROFF_NORMAL,
+ NULL);
+}
+
+static void do_kernel_power_off_prepare(void)
+{
+ /* legacy pm_power_off_prepare() is unchained and it has highest priority */
+ if (pm_power_off_prepare)
+ return pm_power_off_prepare();
+
+ blocking_notifier_call_chain(&power_off_handler_list, POWEROFF_PREPARE,
+ NULL);
+}
+
/**
* kernel_power_off - power_off the system
*
@@ -302,8 +882,7 @@ EXPORT_SYMBOL_GPL(kernel_halt);
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
- if (pm_power_off_prepare)
- pm_power_off_prepare();
+ do_kernel_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown();
pr_emerg("Power down\n");
@@ -312,6 +891,16 @@ void kernel_power_off(void)
}
EXPORT_SYMBOL_GPL(kernel_power_off);
+bool kernel_can_power_off(void)
+{
+ if (!pm_power_off &&
+ blocking_notifier_call_chain_empty(&power_off_handler_list))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(kernel_can_power_off);
+
DEFINE_MUTEX(system_transition_mutex);
/*
@@ -353,7 +942,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
- if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
+ if (cmd == LINUX_REBOOT_CMD_POWER_OFF && !kernel_can_power_off())
cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&system_transition_mutex);
--
2.33.1
^ permalink raw reply related
* [PATCH v2 09/45] xen/x86: Use do_kernel_power_off()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
arch/x86/xen/enlighten_pv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 4f63117f09bb..4a0b9b7baf02 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -32,6 +32,7 @@
#include <linux/gfp.h>
#include <linux/edd.h>
#include <linux/objtool.h>
+#include <linux/reboot.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -1087,8 +1088,7 @@ static void xen_machine_halt(void)
static void xen_machine_power_off(void)
{
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
xen_reboot(SHUTDOWN_poweroff);
}
--
2.33.1
^ permalink raw reply related
* [PATCH v2 10/45] ARM: Use do_kernel_power_off()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
arch/arm/kernel/reboot.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
index 3044fcb8d073..2cb943422554 100644
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -116,9 +116,7 @@ void machine_power_off(void)
{
local_irq_disable();
smp_send_stop();
-
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
}
/*
--
2.33.1
^ permalink raw reply related
* [PATCH v2 11/45] arm64: Use do_kernel_power_off()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
arch/arm64/kernel/process.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index aacf2f5559a8..f8db031afa7d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -110,8 +110,7 @@ void machine_power_off(void)
{
local_irq_disable();
smp_send_stop();
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
}
/*
--
2.33.1
^ permalink raw reply related
* [PATCH v2 12/45] csky: Use do_kernel_power_off()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
arch/csky/kernel/power.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/csky/kernel/power.c b/arch/csky/kernel/power.c
index 923ee4e381b8..86ee202906f8 100644
--- a/arch/csky/kernel/power.c
+++ b/arch/csky/kernel/power.c
@@ -9,16 +9,14 @@ EXPORT_SYMBOL(pm_power_off);
void machine_power_off(void)
{
local_irq_disable();
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
asm volatile ("bkpt");
}
void machine_halt(void)
{
local_irq_disable();
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
asm volatile ("bkpt");
}
--
2.33.1
^ permalink raw reply related
* [PATCH v2 13/45] ia64: Use do_kernel_power_off()
From: Dmitry Osipenko @ 2021-10-27 21:16 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Lee Jones, Rafael J . Wysocki,
Mark Brown, Andrew Morton, Guenter Roeck, Russell King,
Daniel Lezcano, Andy Shevchenko, Ulf Hansson
Cc: Rich Felker, linux-ia64, Tomer Maimon, Santosh Shilimkar,
linux-sh, Boris Ostrovsky, Linus Walleij, Dave Hansen, linux-acpi,
Tali Perry, James E.J. Bottomley, Paul Mackerras, Pavel Machek,
H. Peter Anvin, linux-riscv, Vincent Chen, Will Deacon,
Greg Ungerer, Stefano Stabellini, Benjamin Fair, Yoshinori Sato,
Krzysztof Kozlowski, Helge Deller, x86, linux-csky, Tony Lindgren,
Chen-Yu Tsai, Ingo Molnar, Geert Uytterhoeven, Catalin Marinas,
xen-devel, linux-mips, Len Brown, Albert Ou, linux-pm,
Jonathan Neuschäfer, Vladimir Zapolskiy, linux-m68k,
Borislav Petkov, Greentime Hu, Paul Walmsley, linux-tegra,
Thomas Gleixner, linux-omap, Nancy Yuen, linux-arm-kernel,
Juergen Gross, Thomas Bogendoerfer, linux-parisc, Nick Hu,
Avi Fishman, Patrick Venture, Liam Girdwood, linux-kernel,
Palmer Dabbelt, Philipp Zabel, Guo Ren, linuxppc-dev, openbmc,
Joshua Thompson
In-Reply-To: <20211027211715.12671-1-digetx@gmail.com>
Kernel now supports chained power-off handlers. Use do_kernel_power_off()
that invokes chained power-off handlers. It also invokes legacy
pm_power_off() for now, which will be removed once all drivers will
be converted to the new power-off API.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
arch/ia64/kernel/process.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 834df24a88f1..cee4d7db2143 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/personality.h>
+#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/hotplug.h>
@@ -599,8 +600,7 @@ machine_halt (void)
void
machine_power_off (void)
{
- if (pm_power_off)
- pm_power_off();
+ do_kernel_power_off();
machine_halt();
}
--
2.33.1
^ permalink raw reply related
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