1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 /* 4 * IBM ASM Service Processor Device Driver 5 * 6 * Copyright (C) IBM Corporation, 2004 7 * 8 * Author: Max Asböck <amax@us.ibm.com> 9 */ 10 11 #include <linux/notifier.h> 12 #include "ibmasm.h" 13 #include "dot_command.h" 14 #include "lowlevel.h" 15 16 static int suspend_heartbeats = 0; 17 18 /* 19 * Once the driver indicates to the service processor that it is running 20 * - see send_os_state() - the service processor sends periodic heartbeats 21 * to the driver. The driver must respond to the heartbeats or else the OS 22 * will be rebooted. 23 * In the case of a panic the interrupt handler continues to work and thus 24 * continues to respond to heartbeats, making the service processor believe 25 * the OS is still running and thus preventing a reboot. 26 * To prevent this from happening a callback is added the panic_notifier_list. 27 * Before responding to a heartbeat the driver checks if a panic has happened, 28 * if yes it suspends heartbeat, causing the service processor to reboot as 29 * expected. 30 */ 31 static int panic_happened(struct notifier_block *n, unsigned long val, void *v) 32 { 33 suspend_heartbeats = 1; 34 return 0; 35 } 36 37 static struct notifier_block panic_notifier = { panic_happened, NULL, 1 }; 38 39 void ibmasm_register_panic_notifier(void) 40 { 41 atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier); 42 } 43 44 void ibmasm_unregister_panic_notifier(void) 45 { 46 atomic_notifier_chain_unregister(&panic_notifier_list, 47 &panic_notifier); 48 } 49 50 51 int ibmasm_heartbeat_init(struct service_processor *sp) 52 { 53 sp->heartbeat = ibmasm_new_command(sp, HEARTBEAT_BUFFER_SIZE); 54 if (sp->heartbeat == NULL) 55 return -ENOMEM; 56 57 return 0; 58 } 59 60 void ibmasm_heartbeat_exit(struct service_processor *sp) 61 { 62 char tsbuf[32]; 63 64 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 65 ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL); 66 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 67 suspend_heartbeats = 1; 68 command_put(sp->heartbeat); 69 } 70 71 void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size) 72 { 73 struct command *cmd = sp->heartbeat; 74 struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; 75 char tsbuf[32]; 76 77 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 78 if (suspend_heartbeats) 79 return; 80 81 /* return the received dot command to sender */ 82 cmd->status = IBMASM_CMD_PENDING; 83 size = min(size, cmd->buffer_size); 84 memcpy_fromio(cmd->buffer, message, size); 85 header->type = sp_write; 86 ibmasm_exec_command(sp, cmd); 87 } 88