18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2004 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Max Asböck <amax@us.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 118c2ecf20Sopenharmony_ci#include "ibmasm.h" 128c2ecf20Sopenharmony_ci#include "dot_command.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Reverse Heartbeat, i.e. heartbeats sent from the driver to the 168c2ecf20Sopenharmony_ci * service processor. 178c2ecf20Sopenharmony_ci * These heartbeats are initiated by user level programs. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* the reverse heartbeat dot command */ 218c2ecf20Sopenharmony_ci#pragma pack(1) 228c2ecf20Sopenharmony_cistatic struct { 238c2ecf20Sopenharmony_ci struct dot_command_header header; 248c2ecf20Sopenharmony_ci unsigned char command[3]; 258c2ecf20Sopenharmony_ci} rhb_dot_cmd = { 268c2ecf20Sopenharmony_ci .header = { 278c2ecf20Sopenharmony_ci .type = sp_read, 288c2ecf20Sopenharmony_ci .command_size = 3, 298c2ecf20Sopenharmony_ci .data_size = 0, 308c2ecf20Sopenharmony_ci .status = 0 318c2ecf20Sopenharmony_ci }, 328c2ecf20Sopenharmony_ci .command = { 4, 3, 6 } 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci#pragma pack() 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_civoid ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci init_waitqueue_head(&rhb->wait); 398c2ecf20Sopenharmony_ci rhb->stopped = 0; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * start_reverse_heartbeat 448c2ecf20Sopenharmony_ci * Loop forever, sending a reverse heartbeat dot command to the service 458c2ecf20Sopenharmony_ci * processor, then sleeping. The loop comes to an end if the service 468c2ecf20Sopenharmony_ci * processor fails to respond 3 times or we were interrupted. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct command *cmd; 518c2ecf20Sopenharmony_ci int times_failed = 0; 528c2ecf20Sopenharmony_ci int result = 1; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd); 558c2ecf20Sopenharmony_ci if (!cmd) 568c2ecf20Sopenharmony_ci return -ENOMEM; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci while (times_failed < 3) { 598c2ecf20Sopenharmony_ci memcpy(cmd->buffer, (void *)&rhb_dot_cmd, sizeof rhb_dot_cmd); 608c2ecf20Sopenharmony_ci cmd->status = IBMASM_CMD_PENDING; 618c2ecf20Sopenharmony_ci ibmasm_exec_command(sp, cmd); 628c2ecf20Sopenharmony_ci ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (cmd->status != IBMASM_CMD_COMPLETE) 658c2ecf20Sopenharmony_ci times_failed++; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci wait_event_interruptible_timeout(rhb->wait, 688c2ecf20Sopenharmony_ci rhb->stopped, 698c2ecf20Sopenharmony_ci REVERSE_HEARTBEAT_TIMEOUT * HZ); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (signal_pending(current) || rhb->stopped) { 728c2ecf20Sopenharmony_ci result = -EINTR; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci command_put(cmd); 778c2ecf20Sopenharmony_ci rhb->stopped = 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return result; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci rhb->stopped = 1; 858c2ecf20Sopenharmony_ci wake_up_interruptible(&rhb->wait); 868c2ecf20Sopenharmony_ci} 87