/* * drivers/watchdog/m54xx_wdt.c * * Watchdog driver for ColdFire MCF547x & MCF548x processors * Copyright 2010 (c) Philippe De Muyter * * Adapted from the IXP4xx watchdog driver, which carries these notices: * * Author: Deepak Saxena * * Copyright 2004 (c) MontaVista, Software, Inc. * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bool nowayout = WATCHDOG_NOWAYOUT; static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */ static unsigned long wdt_status; #define WDT_IN_USE 0 #define WDT_OK_TO_CLOSE 1 static void wdt_enable(void) { unsigned int gms0; /* preserve GPIO usage, if any */ gms0 = __raw_readl(MCF_GPT_GMS0); if (gms0 & MCF_GPT_GMS_TMS_GPIO) gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK | MCF_GPT_GMS_OD); else gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD; __raw_writel(gms0, MCF_GPT_GMS0); __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) | MCF_GPT_GCIR_CNT(0xffff), MCF_GPT_GCIR0); gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE; __raw_writel(gms0, MCF_GPT_GMS0); } static void wdt_disable(void) { unsigned int gms0; /* disable watchdog */ gms0 = __raw_readl(MCF_GPT_GMS0); gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE); __raw_writel(gms0, MCF_GPT_GMS0); } static void wdt_keepalive(void) { unsigned int gms0; gms0 = __raw_readl(MCF_GPT_GMS0); gms0 |= MCF_GPT_GMS_OCPW(0xA5); __raw_writel(gms0, MCF_GPT_GMS0); } static int m54xx_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(WDT_IN_USE, &wdt_status)) return -EBUSY; clear_bit(WDT_OK_TO_CLOSE, &wdt_status); wdt_enable(); return nonseekable_open(inode, file); } static ssize_t m54xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) { if (len) { if (!nowayout) { size_t i; clear_bit(WDT_OK_TO_CLOSE, &wdt_status); for (i = 0; i != len; i++) { char c; if (get_user(c, data + i)) return -EFAULT; if (c == 'V') set_bit(WDT_OK_TO_CLOSE, &wdt_status); } } wdt_keepalive(); } return len; } static const struct watchdog_info ident = { .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "Coldfire M54xx Watchdog", }; static long m54xx_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOTTY; int time; switch (cmd) { case WDIOC_GETSUPPORT: ret = copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; break; case WDIOC_GETSTATUS: ret = put_user(0, (int *)arg); break; case WDIOC_GETBOOTSTATUS: ret = put_user(0, (int *)arg); break; case WDIOC_KEEPALIVE: wdt_keepalive(); ret = 0; break; case WDIOC_SETTIMEOUT: ret = get_user(time, (int *)arg); if (ret) break; if (time <= 0 || time > 30) { ret = -EINVAL; break; } heartbeat = time; wdt_enable(); /* Fall through */ case WDIOC_GETTIMEOUT: ret = put_user(heartbeat, (int *)arg); break; } return ret; } static int m54xx_wdt_release(struct inode *inode, struct file *file) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) wdt_disable(); else { pr_crit("Device closed unexpectedly - timer will not stop\n"); wdt_keepalive(); } clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status); return 0; } static const struct file_operations m54xx_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = m54xx_wdt_write, .unlocked_ioctl = m54xx_wdt_ioctl, .open = m54xx_wdt_open, .release = m54xx_wdt_release, }; static struct miscdevice m54xx_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &m54xx_wdt_fops, }; static int __init m54xx_wdt_init(void) { if (!request_mem_region(MCF_GPT_GCIR0, 4, "Coldfire M54xx Watchdog")) { pr_warn("I/O region busy\n"); return -EBUSY; } pr_info("driver is loaded\n"); return misc_register(&m54xx_wdt_miscdev); } static void __exit m54xx_wdt_exit(void) { misc_deregister(&m54xx_wdt_miscdev); release_mem_region(MCF_GPT_GCIR0, 4); } module_init(m54xx_wdt_init); module_exit(m54xx_wdt_exit); MODULE_AUTHOR("Philippe De Muyter "); MODULE_DESCRIPTION("Coldfire M54xx Watchdog"); module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)"); module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); MODULE_LICENSE("GPL"); td class='right'>2017-02-01 17:45:02 +0000 committerIngo Molnar <mingo@kernel.org>2017-02-01 21:17:49 +0100 commitc8f325a59cfc718d13a50fbc746ed9b415c25e92 (patch) treed53fbdac9d0781e39a13b2ac6b2bd258cf3b4140 /net/dccp/ccids/ccid2.h parentbf29bddf0417a4783da3b24e8c9e017ac649326f (diff)
efi/fdt: Avoid FDT manipulation after ExitBootServices()
Some AArch64 UEFI implementations disable the MMU in ExitBootServices(), after which unaligned accesses to RAM are no longer supported. Commit: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") fixed an issue in the memory map handling of the stub FDT code, but inadvertently created an issue with such firmware, by moving some of the FDT manipulation to after the invocation of ExitBootServices(). Given that the stub's libfdt implementation uses the ordinary, accelerated string functions, which rely on hardware handling of unaligned accesses, manipulating the FDT with the MMU off may result in alignment faults. So fix the situation by moving the update_fdt_memmap() call into the callback function invoked by efi_exit_boot_services() right before it calls the ExitBootServices() UEFI service (which is arguably a better place for it anyway) Note that disabling the MMU in ExitBootServices() is not compliant with the UEFI spec, and carries great risk due to the fact that switching from cached to uncached memory accesses halfway through compiler generated code (i.e., involving a stack) can never be done in a way that is architecturally safe. Fixes: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Riku Voipio <riku.voipio@linaro.org> Cc: <stable@vger.kernel.org> Cc: mark.rutland@arm.com Cc: linux-efi@vger.kernel.org Cc: matt@codeblueprint.co.uk Cc: leif.lindholm@linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1485971102-23330-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'net/dccp/ccids/ccid2.h')