1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) IBM Corporation, 2004
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Max Asböck <amax@us.ibm.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/sched/signal.h>
11*4882a593Smuzhiyun #include "ibmasm.h"
12*4882a593Smuzhiyun #include "dot_command.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun * Reverse Heartbeat, i.e. heartbeats sent from the driver to the
16*4882a593Smuzhiyun * service processor.
17*4882a593Smuzhiyun * These heartbeats are initiated by user level programs.
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* the reverse heartbeat dot command */
21*4882a593Smuzhiyun #pragma pack(1)
22*4882a593Smuzhiyun static struct {
23*4882a593Smuzhiyun struct dot_command_header header;
24*4882a593Smuzhiyun unsigned char command[3];
25*4882a593Smuzhiyun } rhb_dot_cmd = {
26*4882a593Smuzhiyun .header = {
27*4882a593Smuzhiyun .type = sp_read,
28*4882a593Smuzhiyun .command_size = 3,
29*4882a593Smuzhiyun .data_size = 0,
30*4882a593Smuzhiyun .status = 0
31*4882a593Smuzhiyun },
32*4882a593Smuzhiyun .command = { 4, 3, 6 }
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun #pragma pack()
35*4882a593Smuzhiyun
ibmasm_init_reverse_heartbeat(struct service_processor * sp,struct reverse_heartbeat * rhb)36*4882a593Smuzhiyun void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun init_waitqueue_head(&rhb->wait);
39*4882a593Smuzhiyun rhb->stopped = 0;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun * start_reverse_heartbeat
44*4882a593Smuzhiyun * Loop forever, sending a reverse heartbeat dot command to the service
45*4882a593Smuzhiyun * processor, then sleeping. The loop comes to an end if the service
46*4882a593Smuzhiyun * processor fails to respond 3 times or we were interrupted.
47*4882a593Smuzhiyun */
ibmasm_start_reverse_heartbeat(struct service_processor * sp,struct reverse_heartbeat * rhb)48*4882a593Smuzhiyun int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun struct command *cmd;
51*4882a593Smuzhiyun int times_failed = 0;
52*4882a593Smuzhiyun int result = 1;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd);
55*4882a593Smuzhiyun if (!cmd)
56*4882a593Smuzhiyun return -ENOMEM;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun while (times_failed < 3) {
59*4882a593Smuzhiyun memcpy(cmd->buffer, (void *)&rhb_dot_cmd, sizeof rhb_dot_cmd);
60*4882a593Smuzhiyun cmd->status = IBMASM_CMD_PENDING;
61*4882a593Smuzhiyun ibmasm_exec_command(sp, cmd);
62*4882a593Smuzhiyun ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (cmd->status != IBMASM_CMD_COMPLETE)
65*4882a593Smuzhiyun times_failed++;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun wait_event_interruptible_timeout(rhb->wait,
68*4882a593Smuzhiyun rhb->stopped,
69*4882a593Smuzhiyun REVERSE_HEARTBEAT_TIMEOUT * HZ);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (signal_pending(current) || rhb->stopped) {
72*4882a593Smuzhiyun result = -EINTR;
73*4882a593Smuzhiyun break;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun command_put(cmd);
77*4882a593Smuzhiyun rhb->stopped = 0;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun return result;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat * rhb)82*4882a593Smuzhiyun void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun rhb->stopped = 1;
85*4882a593Smuzhiyun wake_up_interruptible(&rhb->wait);
86*4882a593Smuzhiyun }
87