diff options
Diffstat (limited to 'drivers/s390/char')
| -rw-r--r-- | drivers/s390/char/Makefile | 3 | ||||
| -rw-r--r-- | drivers/s390/char/raw3270.c | 8 | ||||
| -rw-r--r-- | drivers/s390/char/sclp.c | 90 | ||||
| -rw-r--r-- | drivers/s390/char/sclp.h | 9 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_cmd.c | 19 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_early.c | 34 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_vt220.c | 16 | ||||
| -rw-r--r-- | drivers/s390/char/tape_std.c | 3 | ||||
| -rw-r--r-- | drivers/s390/char/vmlogrdr.c | 2 | ||||
| -rw-r--r-- | drivers/s390/char/vmwatchdog.c | 338 | ||||
| -rw-r--r-- | drivers/s390/char/zcore.c | 44 |
11 files changed, 175 insertions, 391 deletions
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index b69ab17f13f..78b6ace7edc 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o -obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o obj-$(CONFIG_VMCP) += vmcp.o @@ -33,4 +32,4 @@ obj-$(CONFIG_MONWRITER) += monwriter.o obj-$(CONFIG_S390_VMUR) += vmur.o zcore_mod-objs := sclp_sdias.o zcore.o -obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o +obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 9f849df4381..220acb4cbee 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -632,6 +632,7 @@ raw3270_reset_device_cb(struct raw3270_request *rq, void *data) raw3270_size_device_done(rp); } else raw3270_writesf_readpart(rp); + memset(&rp->init_reset, 0, sizeof(rp->init_reset)); } static int @@ -639,9 +640,10 @@ __raw3270_reset_device(struct raw3270 *rp) { int rc; + /* Check if reset is already pending */ + if (rp->init_reset.view) + return -EBUSY; /* Store reset data stream to init_data/init_reset */ - memset(&rp->init_reset, 0, sizeof(rp->init_reset)); - memset(&rp->init_data, 0, sizeof(rp->init_data)); rp->init_data[0] = TW_KR; rp->init_reset.ccw.cmd_code = TC_EWRITEA; rp->init_reset.ccw.flags = CCW_FLAG_SLI; @@ -850,7 +852,7 @@ raw3270_create_device(struct ccw_device *cdev) char *ascebc; int rc; - rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); + rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); if (!rp) return ERR_PTR(-ENOMEM); ascebc = kmalloc(256, GFP_KERNEL); diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 1fe264379e0..c316051d9bd 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -91,6 +91,9 @@ static struct sclp_req sclp_suspend_req; /* Timer for request retries. */ static struct timer_list sclp_request_timer; +/* Timer for queued requests. */ +static struct timer_list sclp_queue_timer; + /* Internal state: is the driver initialized? */ static volatile enum sclp_init_state_t { sclp_init_state_uninitialized, @@ -215,6 +218,76 @@ sclp_request_timeout(unsigned long data) sclp_process_queue(); } +/* + * Returns the expire value in jiffies of the next pending request timeout, + * if any. Needs to be called with sclp_lock. + */ +static unsigned long __sclp_req_queue_find_next_timeout(void) +{ + unsigned long expires_next = 0; + struct sclp_req *req; + + list_for_each_entry(req, &sclp_req_queue, list) { + if (!req->queue_expires) + continue; + if (!expires_next || + (time_before(req->queue_expires, expires_next))) + expires_next = req->queue_expires; + } + return expires_next; +} + +/* + * Returns expired request, if any, and removes it from the list. + */ +static struct sclp_req *__sclp_req_queue_remove_expired_req(void) +{ + unsigned long flags, now; + struct sclp_req *req; + + spin_lock_irqsave(&sclp_lock, flags); + now = jiffies; + /* Don't need list_for_each_safe because we break out after list_del */ + list_for_each_entry(req, &sclp_req_queue, list) { + if (!req->queue_expires) + continue; + if (time_before_eq(req->queue_expires, now)) { + if (req->status == SCLP_REQ_QUEUED) { + req->status = SCLP_REQ_QUEUED_TIMEOUT; + list_del(&req->list); + goto out; + } + } + } + req = NULL; +out: + spin_unlock_irqrestore(&sclp_lock, flags); + return req; +} + +/* + * Timeout handler for queued requests. Removes request from list and + * invokes callback. This timer can be set per request in situations where + * waiting too long would be harmful to the system, e.g. during SE reboot. + */ +static void sclp_req_queue_timeout(unsigned long data) +{ + unsigned long flags, expires_next; + struct sclp_req *req; + + do { + req = __sclp_req_queue_remove_expired_req(); + if (req && req->callback) + req->callback(req, req->callback_data); + } while (req); + + spin_lock_irqsave(&sclp_lock, flags); + expires_next = __sclp_req_queue_find_next_timeout(); + if (expires_next) + mod_timer(&sclp_queue_timer, expires_next); + spin_unlock_irqrestore(&sclp_lock, flags); +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -317,6 +390,13 @@ sclp_add_request(struct sclp_req *req) req->start_count = 0; list_add_tail(&req->list, &sclp_req_queue); rc = 0; + if (req->queue_timeout) { + req->queue_expires = jiffies + req->queue_timeout * HZ; + if (!timer_pending(&sclp_queue_timer) || + time_after(sclp_queue_timer.expires, req->queue_expires)) + mod_timer(&sclp_queue_timer, req->queue_expires); + } else + req->queue_expires = 0; /* Start if request is first in list */ if (sclp_running_state == sclp_running_state_idle && req->list.prev == &sclp_req_queue) { @@ -892,7 +972,7 @@ sclp_check_interface(void) spin_lock_irqsave(&sclp_lock, flags); /* Prepare init mask command */ - rc = register_external_interrupt(0x2401, sclp_check_handler); + rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); if (rc) { spin_unlock_irqrestore(&sclp_lock, flags); return rc; @@ -925,7 +1005,7 @@ sclp_check_interface(void) } else rc = -EBUSY; } - unregister_external_interrupt(0x2401, sclp_check_handler); + unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); spin_unlock_irqrestore(&sclp_lock, flags); return rc; } @@ -1113,6 +1193,8 @@ sclp_init(void) INIT_LIST_HEAD(&sclp_reg_list); list_add(&sclp_state_change_event.list, &sclp_reg_list); init_timer(&sclp_request_timer); + init_timer(&sclp_queue_timer); + sclp_queue_timer.function = sclp_req_queue_timeout; /* Check interface */ spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_check_interface(); @@ -1124,7 +1206,7 @@ sclp_init(void) if (rc) goto fail_init_state_uninitialized; /* Register interrupt handler */ - rc = register_external_interrupt(0x2401, sclp_interrupt_handler); + rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_interrupt_handler); if (rc) goto fail_unregister_reboot_notifier; sclp_init_state = sclp_init_state_initialized; @@ -1170,7 +1252,7 @@ static __init int sclp_initcall(void) return rc; sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); - rc = PTR_RET(sclp_pdev); + rc = PTR_ERR_OR_ZERO(sclp_pdev); if (rc) goto fail_platform_driver_unregister; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index fea76aed9ee..a68b5ec7d04 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -133,6 +133,11 @@ struct sclp_req { /* Callback that is called after reaching final status. */ void (*callback)(struct sclp_req *, void *data); void *callback_data; + int queue_timeout; /* request queue timeout (sec), set by + caller of sclp_add_request(), if + needed */ + /* Internal fields */ + unsigned long queue_expires; /* request queue timeout (jiffies) */ }; #define SCLP_REQ_FILLED 0x00 /* request is ready to be processed */ @@ -140,6 +145,9 @@ struct sclp_req { #define SCLP_REQ_RUNNING 0x02 /* request is currently running */ #define SCLP_REQ_DONE 0x03 /* request is completed successfully */ #define SCLP_REQ_FAILED 0x05 /* request is finally failed */ +#define SCLP_REQ_QUEUED_TIMEOUT 0x06 /* request on queue timed out */ + +#define SCLP_QUEUE_INTERVAL 5 /* timeout interval for request queue */ /* function pointers that a high level driver has to use for registration */ /* of some routines it wants to be called from the low level driver */ @@ -173,6 +181,7 @@ int sclp_deactivate(void); int sclp_reactivate(void); int sclp_service_call(sclp_cmdw_t command, void *sccb); int sclp_sync_request(sclp_cmdw_t command, void *sccb); +int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); int sclp_sdias_init(void); void sclp_sdias_exit(void); diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 49af8eeb90e..6e14999f9e8 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -37,6 +37,11 @@ static void sclp_sync_callback(struct sclp_req *req, void *data) int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) { + return sclp_sync_request_timeout(cmd, sccb, 0); +} + +int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) +{ struct completion completion; struct sclp_req *request; int rc; @@ -44,6 +49,8 @@ int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; + if (timeout) + request->queue_timeout = timeout; request->command = cmd; request->sccb = sccb; request->status = SCLP_REQ_FILLED; @@ -110,7 +117,8 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info) if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = sclp_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); + rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; if (sccb->header.response_code != 0x0010) { @@ -144,7 +152,7 @@ static int do_cpu_configure(sclp_cmdw_t cmd) if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = sclp_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -214,7 +222,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) return -ENOMEM; sccb->header.length = PAGE_SIZE; sccb->rn = rn; - rc = sclp_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -269,7 +277,8 @@ static int sclp_attach_storage(u8 id) if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; - rc = sclp_sync_request(0x00080001 | id << 8, sccb); + rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -506,7 +515,7 @@ static int __init sclp_detect_standby_memory(void) if (rc) goto out; sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); - rc = PTR_RET(sclp_pdev); + rc = PTR_ERR_OR_ZERO(sclp_pdev); if (rc) goto out_driver; sclp_add_standby_memory(); diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 14196ea0fdf..1918d9dff45 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -22,11 +22,14 @@ struct read_info_sccb { u8 rnsize; /* 10 */ u8 _reserved0[16 - 11]; /* 11-15 */ u16 ncpurl; /* 16-17 */ - u8 _reserved7[24 - 18]; /* 18-23 */ + u16 cpuoff; /* 18-19 */ + u8 _reserved7[24 - 20]; /* 20-23 */ u8 loadparm[8]; /* 24-31 */ u8 _reserved1[48 - 32]; /* 32-47 */ u64 facilities; /* 48-55 */ - u8 _reserved2[84 - 56]; /* 56-83 */ + u8 _reserved2a[76 - 56]; /* 56-75 */ + u32 ibc; /* 76-79 */ + u8 _reserved2b[84 - 80]; /* 80-83 */ u8 fac84; /* 84 */ u8 fac85; /* 85 */ u8 _reserved3[91 - 86]; /* 86-90 */ @@ -45,6 +48,8 @@ static unsigned int sclp_con_has_linemode __initdata; static unsigned long sclp_hsa_size; static unsigned int sclp_max_cpu; static struct sclp_ipl_info sclp_ipl_info; +static unsigned char sclp_siif; +static u32 sclp_ibc; u64 sclp_facilities; u8 sclp_fac84; @@ -96,6 +101,9 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) static void __init sclp_facilities_detect(struct read_info_sccb *sccb) { + struct sclp_cpu_entry *cpue; + u16 boot_cpu_address, cpu; + if (sclp_read_info_early(sccb)) return; @@ -106,6 +114,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp_rzm <<= 20; + sclp_ibc = sccb->ibc; if (!sccb->hcpua) { if (MACHINE_IS_VM) @@ -116,6 +125,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) sclp_max_cpu = sccb->hcpua + 1; } + boot_cpu_address = stap(); + cpue = (void *)sccb + sccb->cpuoff; + for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) { + if (boot_cpu_address != cpue->address) + continue; + sclp_siif = cpue->siif; + break; + } + /* Save IPL information */ sclp_ipl_info.is_valid = 1; if (sccb->flags & 0x2) @@ -148,6 +166,18 @@ unsigned int sclp_get_max_cpu(void) return sclp_max_cpu; } +int sclp_has_siif(void) +{ + return sclp_siif; +} +EXPORT_SYMBOL(sclp_has_siif); + +unsigned int sclp_get_ibc(void) +{ + return sclp_ibc; +} +EXPORT_SYMBOL(sclp_get_ibc); + /* * This function will be called after sclp_facilities_detect(), which gets * called from early.c code. The sclp_facilities_detect() function retrieves diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 4eed38cd0af..b9a9f721716 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -97,13 +97,16 @@ static void sclp_vt220_pm_event_fn(struct sclp_register *reg, static int __sclp_vt220_emit(struct sclp_vt220_request *request); static void sclp_vt220_emit_current(void); -/* Registration structure for our interest in SCLP event buffers */ +/* Registration structure for SCLP output event buffers */ static struct sclp_register sclp_vt220_register = { .send_mask = EVTYP_VT220MSG_MASK, + .pm_event_fn = sclp_vt220_pm_event_fn, +}; + +/* Registration structure for SCLP input event buffers */ +static struct sclp_register sclp_vt220_register_input = { .receive_mask = EVTYP_VT220MSG_MASK, - .state_change_fn = NULL, .receiver_fn = sclp_vt220_receiver_fn, - .pm_event_fn = sclp_vt220_pm_event_fn, }; @@ -715,9 +718,14 @@ static int __init sclp_vt220_tty_init(void) rc = tty_register_driver(driver); if (rc) goto out_init; + rc = sclp_register(&sclp_vt220_register_input); + if (rc) + goto out_reg; sclp_vt220_driver = driver; return 0; +out_reg: + tty_unregister_driver(driver); out_init: __sclp_vt220_cleanup(); out_driver: @@ -830,8 +838,6 @@ sclp_vt220_con_init(void) { int rc; - if (!CONSOLE_IS_SCLP) - return 0; rc = __sclp_vt220_init(sclp_console_pages); if (rc) return rc; diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 981a99fd8d4..3478e19ae19 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -78,7 +78,8 @@ tape_std_assign(struct tape_device *device) rc = tape_do_io_interruptible(device, request); - del_timer(&timeout); + del_timer_sync(&timeout); + destroy_timer_on_stack(&timeout); if (rc != 0) { DBF_EVENT(3, "%08x: assign failed - device might be busy\n", diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index cf31d3321da..a8848db7b09 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -761,7 +761,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (dev) { - dev_set_name(dev, priv->internal_name); + dev_set_name(dev, "%s", priv->internal_name); dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c deleted file mode 100644 index d5eac985976..00000000000 --- a/drivers/s390/char/vmwatchdog.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Watchdog implementation based on z/VM Watchdog Timer API - * - * Copyright IBM Corp. 2004, 2009 - * - * The user space watchdog daemon can use this driver as - * /dev/vmwatchdog to have z/VM execute the specified CP - * command when the timeout expires. The default command is - * "IPL", which which cause an immediate reboot. - */ -#define KMSG_COMPONENT "vmwatchdog" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/miscdevice.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/suspend.h> -#include <linux/watchdog.h> - -#include <asm/ebcdic.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#define MAX_CMDLEN 240 -#define MIN_INTERVAL 15 -static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; -static bool vmwdt_conceal; - -static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT; - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); -MODULE_DESCRIPTION("z/VM Watchdog Timer"); -module_param_string(cmd, vmwdt_cmd, MAX_CMDLEN, 0644); -MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers"); -module_param_named(conceal, vmwdt_conceal, bool, 0644); -MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog " - " is active"); -module_param_named(nowayout, vmwdt_nowayout, bool, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" - " (default=CONFIG_WATCHDOG_NOWAYOUT)"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); - -static unsigned int vmwdt_interval = 60; -static unsigned long vmwdt_is_open; -static int vmwdt_expect_close; - -static DEFINE_MUTEX(vmwdt_mutex); - -#define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ -#define VMWDT_RUNNING 1 /* The watchdog is armed */ - -enum vmwdt_func { - /* function codes */ - wdt_init = 0, - wdt_change = 1, - wdt_cancel = 2, - /* flags */ - wdt_conceal = 0x80000000, -}; - -static int __diag288(enum vmwdt_func func, unsigned int timeout, - char *cmd, size_t len) -{ - register unsigned long __func asm("2") = func; - register unsigned long __timeout asm("3") = timeout; - register unsigned long __cmdp asm("4") = virt_to_phys(cmd); - register unsigned long __cmdl asm("5") = len; - int err; - - err = -EINVAL; - asm volatile( - " diag %1,%3,0x288\n" - "0: la %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl) : "1", "cc"); - return err; -} - -static int vmwdt_keepalive(void) -{ - /* we allocate new memory every time to avoid having - * to track the state. static allocation is not an - * option since that might not be contiguous in real - * storage in case of a modular build */ - static char *ebc_cmd; - size_t len; - int ret; - unsigned int func; - - ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); - if (!ebc_cmd) - return -ENOMEM; - - len = strlcpy(ebc_cmd, vmwdt_cmd, MAX_CMDLEN); - ASCEBC(ebc_cmd, MAX_CMDLEN); - EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); - - func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; - set_bit(VMWDT_RUNNING, &vmwdt_is_open); - ret = __diag288(func, vmwdt_interval, ebc_cmd, len); - WARN_ON(ret != 0); - kfree(ebc_cmd); - return ret; -} - -static int vmwdt_disable(void) -{ - char cmd[] = {'\0'}; - int ret = __diag288(wdt_cancel, 0, cmd, 0); - WARN_ON(ret != 0); - clear_bit(VMWDT_RUNNING, &vmwdt_is_open); - return ret; -} - -static int __init vmwdt_probe(void) -{ - /* there is no real way to see if the watchdog is supported, - * so we try initializing it with a NOP command ("BEGIN") - * that won't cause any harm even if the following disable - * fails for some reason */ - char ebc_begin[] = { - 194, 197, 199, 201, 213 - }; - if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) - return -EINVAL; - return vmwdt_disable(); -} - -static int vmwdt_open(struct inode *i, struct file *f) -{ - int ret; - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) - return -EBUSY; - ret = vmwdt_keepalive(); - if (ret) - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return ret ? ret : nonseekable_open(i, f); -} - -static int vmwdt_close(struct inode *i, struct file *f) -{ - if (vmwdt_expect_close == 42) - vmwdt_disable(); - vmwdt_expect_close = 0; - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return 0; -} - -static struct watchdog_info vmwdt_info = { - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, - .firmware_version = 0, - .identity = "z/VM Watchdog Timer", -}; - -static int __vmwdt_ioctl(unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user((void __user *)arg, &vmwdt_info, - sizeof(vmwdt_info))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int __user *)arg); - case WDIOC_GETTEMP: - return -EINVAL; - case WDIOC_SETOPTIONS: - { - int options, ret; - if (get_user(options, (int __user *)arg)) - return -EFAULT; - ret = -EINVAL; - if (options & WDIOS_DISABLECARD) { - ret = vmwdt_disable(); - if (ret) - return ret; - } - if (options & WDIOS_ENABLECARD) { - ret = vmwdt_keepalive(); - } - return ret; - } - case WDIOC_GETTIMEOUT: - return put_user(vmwdt_interval, (int __user *)arg); - case WDIOC_SETTIMEOUT: - { - int interval; - if (get_user(interval, (int __user *)arg)) - return -EFAULT; - if (interval < MIN_INTERVAL) - return -EINVAL; - vmwdt_interval = interval; - } - return vmwdt_keepalive(); - case WDIOC_KEEPALIVE: - return vmwdt_keepalive(); - } - return -EINVAL; -} - -static long vmwdt_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int rc; - - mutex_lock(&vmwdt_mutex); - rc = __vmwdt_ioctl(cmd, arg); - mutex_unlock(&vmwdt_mutex); - return (long) rc; -} - -static ssize_t vmwdt_write(struct file *f, const char __user *buf, - size_t count, loff_t *ppos) -{ - if(count) { - if (!vmwdt_nowayout) { - size_t i; - - /* note: just in case someone wrote the magic character - * five months ago... */ - vmwdt_expect_close = 0; - - for (i = 0; i != count; i++) { - char c; - if (get_user(c, buf+i)) - return -EFAULT; - if (c == 'V') - vmwdt_expect_close = 42; - } - } - /* someone wrote to us, we should restart timer */ - vmwdt_keepalive(); - } - return count; -} - -static int vmwdt_resume(void) -{ - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - return NOTIFY_DONE; -} - -/* - * It makes no sense to go into suspend while the watchdog is running. - * Depending on the memory size, the watchdog might trigger, while we - * are still saving the memory. - * We reuse the open flag to ensure that suspend and watchdog open are - * exclusive operations - */ -static int vmwdt_suspend(void) -{ - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { - pr_err("The system cannot be suspended while the watchdog" - " is in use\n"); - return notifier_from_errno(-EBUSY); - } - if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { - clear_bit(VMWDT_OPEN, &vmwdt_is_open); - pr_err("The system cannot be suspended while the watchdog" - " is running\n"); - return notifier_from_errno(-EBUSY); - } - return NOTIFY_DONE; -} - -/* - * This function is called for suspend and resume. - */ -static int vmwdt_power_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - switch (event) { - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - return vmwdt_resume(); - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - return vmwdt_suspend(); - default: - return NOTIFY_DONE; - } -} - -static struct notifier_block vmwdt_power_notifier = { - .notifier_call = vmwdt_power_event, -}; - -static const struct file_operations vmwdt_fops = { - .open = &vmwdt_open, - .release = &vmwdt_close, - .unlocked_ioctl = &vmwdt_ioctl, - .write = &vmwdt_write, - .owner = THIS_MODULE, - .llseek = noop_llseek, -}; - -static struct miscdevice vmwdt_dev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &vmwdt_fops, -}; - -static int __init vmwdt_init(void) -{ - int ret; - - ret = vmwdt_probe(); - if (ret) - return ret; - ret = register_pm_notifier(&vmwdt_power_notifier); - if (ret) - return ret; - /* - * misc_register() has to be the last action in module_init(), because - * file operations will be available right after this. - */ - ret = misc_register(&vmwdt_dev); - if (ret) { - unregister_pm_notifier(&vmwdt_power_notifier); - return ret; - } - return 0; -} -module_init(vmwdt_init); - -static void __exit vmwdt_exit(void) -{ - unregister_pm_notifier(&vmwdt_power_notifier); - misc_deregister(&vmwdt_dev); -} -module_exit(vmwdt_exit); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3d8e4d63f51..1884653e447 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -17,6 +17,8 @@ #include <linux/miscdevice.h> #include <linux/debugfs.h> #include <linux/module.h> +#include <linux/memblock.h> + #include <asm/asm-offsets.h> #include <asm/ipl.h> #include <asm/sclp.h> @@ -411,33 +413,24 @@ static ssize_t zcore_memmap_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return simple_read_from_buffer(buf, count, ppos, filp->private_data, - MEMORY_CHUNKS * CHUNK_INFO_SIZE); + memblock.memory.cnt * CHUNK_INFO_SIZE); } static int zcore_memmap_open(struct inode *inode, struct file *filp) { - int i; + struct memblock_region *reg; char *buf; - struct mem_chunk *chunk_array; + int i = 0; - chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), - GFP_KERNEL); - if (!chunk_array) - return -ENOMEM; - detect_memory_layout(chunk_array, 0); - buf = kzalloc(MEMORY_CHUNKS * CHUNK_INFO_SIZE, GFP_KERNEL); + buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL); if (!buf) { - kfree(chunk_array); return -ENOMEM; } - for (i = 0; i < MEMORY_CHUNKS; i++) { - sprintf(buf + (i * CHUNK_INFO_SIZE), "%016llx %016llx ", - (unsigned long long) chunk_array[i].addr, - (unsigned long long) chunk_array[i].size); - if (chunk_array[i].size == 0) - break; + for_each_memblock(memory, reg) { + sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ", + (unsigned long long) reg->base, + (unsigned long long) reg->size); } - kfree(chunk_array); filp->private_data = buf; return nonseekable_open(inode, filp); } @@ -593,21 +586,12 @@ static int __init check_sdias(void) static int __init get_mem_info(unsigned long *mem, unsigned long *end) { - int i; - struct mem_chunk *chunk_array; + struct memblock_region *reg; - chunk_array = kzalloc(MEMORY_CHUNKS * sizeof(struct mem_chunk), - GFP_KERNEL); - if (!chunk_array) - return -ENOMEM; - detect_memory_layout(chunk_array, 0); - for (i = 0; i < MEMORY_CHUNKS; i++) { - if (chunk_array[i].size == 0) - break; - *mem += chunk_array[i].size; - *end = max(*end, chunk_array[i].addr + chunk_array[i].size); + for_each_memblock(memory, reg) { + *mem += reg->size; + *end = max_t(unsigned long, *end, reg->base + reg->size); } - kfree(chunk_array); return 0; } |
