162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2004 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Max Asböck <amax@us.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/sched/signal.h> 1162306a36Sopenharmony_ci#include "ibmasm.h" 1262306a36Sopenharmony_ci#include "dot_command.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Reverse Heartbeat, i.e. heartbeats sent from the driver to the 1662306a36Sopenharmony_ci * service processor. 1762306a36Sopenharmony_ci * These heartbeats are initiated by user level programs. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* the reverse heartbeat dot command */ 2162306a36Sopenharmony_ci#pragma pack(1) 2262306a36Sopenharmony_cistatic struct { 2362306a36Sopenharmony_ci struct dot_command_header header; 2462306a36Sopenharmony_ci unsigned char command[3]; 2562306a36Sopenharmony_ci} rhb_dot_cmd = { 2662306a36Sopenharmony_ci .header = { 2762306a36Sopenharmony_ci .type = sp_read, 2862306a36Sopenharmony_ci .command_size = 3, 2962306a36Sopenharmony_ci .data_size = 0, 3062306a36Sopenharmony_ci .status = 0 3162306a36Sopenharmony_ci }, 3262306a36Sopenharmony_ci .command = { 4, 3, 6 } 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci#pragma pack() 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_civoid ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci init_waitqueue_head(&rhb->wait); 3962306a36Sopenharmony_ci rhb->stopped = 0; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * start_reverse_heartbeat 4462306a36Sopenharmony_ci * Loop forever, sending a reverse heartbeat dot command to the service 4562306a36Sopenharmony_ci * processor, then sleeping. The loop comes to an end if the service 4662306a36Sopenharmony_ci * processor fails to respond 3 times or we were interrupted. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ciint ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct command *cmd; 5162306a36Sopenharmony_ci int times_failed = 0; 5262306a36Sopenharmony_ci int result = 1; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd); 5562306a36Sopenharmony_ci if (!cmd) 5662306a36Sopenharmony_ci return -ENOMEM; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci while (times_failed < 3) { 5962306a36Sopenharmony_ci memcpy(cmd->buffer, (void *)&rhb_dot_cmd, sizeof rhb_dot_cmd); 6062306a36Sopenharmony_ci cmd->status = IBMASM_CMD_PENDING; 6162306a36Sopenharmony_ci ibmasm_exec_command(sp, cmd); 6262306a36Sopenharmony_ci ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (cmd->status != IBMASM_CMD_COMPLETE) 6562306a36Sopenharmony_ci times_failed++; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci wait_event_interruptible_timeout(rhb->wait, 6862306a36Sopenharmony_ci rhb->stopped, 6962306a36Sopenharmony_ci REVERSE_HEARTBEAT_TIMEOUT * HZ); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (signal_pending(current) || rhb->stopped) { 7262306a36Sopenharmony_ci result = -EINTR; 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci command_put(cmd); 7762306a36Sopenharmony_ci rhb->stopped = 0; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return result; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci rhb->stopped = 1; 8562306a36Sopenharmony_ci wake_up_interruptible(&rhb->wait); 8662306a36Sopenharmony_ci} 87