1150970Srwatson// SPDX-License-Identifier: GPL-2.0-or-later
2150970Srwatson
3150970Srwatson/*
4150970Srwatson * IBM ASM Service Processor Device Driver
5150970Srwatson *
6150970Srwatson * Copyright (C) IBM Corporation, 2004
7150970Srwatson *
8150970Srwatson * Author: Max Asb��ck <amax@us.ibm.com>
9150970Srwatson */
10150970Srwatson
11150970Srwatson#include <linux/notifier.h>
12150970Srwatson#include <linux/panic_notifier.h>
13150970Srwatson#include "ibmasm.h"
14150970Srwatson#include "dot_command.h"
15150970Srwatson#include "lowlevel.h"
16150970Srwatson
17150970Srwatsonstatic int suspend_heartbeats = 0;
18150970Srwatson
19150970Srwatson/*
20150970Srwatson * Once the driver indicates to the service processor that it is running
21150970Srwatson * - see send_os_state() - the service processor sends periodic heartbeats
22150970Srwatson * to the driver. The driver must respond to the heartbeats or else the OS
23150970Srwatson * will be rebooted.
24150970Srwatson * In the case of a panic the interrupt handler continues to work and thus
25150970Srwatson * continues to respond to heartbeats, making the service processor believe
26150970Srwatson * the OS is still running and thus preventing a reboot.
27150970Srwatson * To prevent this from happening a callback is added the panic_notifier_list.
28150970Srwatson * Before responding to a heartbeat the driver checks if a panic has happened,
29150970Srwatson * if yes it suspends heartbeat, causing the service processor to reboot as
30150970Srwatson * expected.
31150970Srwatson */
32150970Srwatsonstatic int panic_happened(struct notifier_block *n, unsigned long val, void *v)
33150970Srwatson{
34213574Spluknet	suspend_heartbeats = 1;
35150970Srwatson	return 0;
36150970Srwatson}
37150970Srwatson
38150970Srwatsonstatic struct notifier_block panic_notifier = { panic_happened, NULL, 1 };
39150970Srwatson
40150970Srwatsonvoid ibmasm_register_panic_notifier(void)
41150970Srwatson{
42150970Srwatson	atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier);
43150970Srwatson}
44150970Srwatson
45150970Srwatsonvoid ibmasm_unregister_panic_notifier(void)
46150970Srwatson{
47150970Srwatson	atomic_notifier_chain_unregister(&panic_notifier_list,
48150970Srwatson			&panic_notifier);
49150970Srwatson}
50150970Srwatson
51150970Srwatson
52150970Srwatsonint ibmasm_heartbeat_init(struct service_processor *sp)
53150970Srwatson{
54150970Srwatson	sp->heartbeat = ibmasm_new_command(sp, HEARTBEAT_BUFFER_SIZE);
55150970Srwatson	if (sp->heartbeat == NULL)
56150970Srwatson		return -ENOMEM;
57150970Srwatson
58150970Srwatson	return 0;
59150970Srwatson}
60150970Srwatson
61150970Srwatsonvoid ibmasm_heartbeat_exit(struct service_processor *sp)
62150970Srwatson{
63150970Srwatson	char tsbuf[32];
64150970Srwatson
65150970Srwatson	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
66150970Srwatson	ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL);
67150970Srwatson	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
68150970Srwatson	suspend_heartbeats = 1;
69150970Srwatson	command_put(sp->heartbeat);
70150970Srwatson}
71150970Srwatson
72150970Srwatsonvoid ibmasm_receive_heartbeat(struct service_processor *sp,  void *message, size_t size)
73150970Srwatson{
74150970Srwatson	struct command *cmd = sp->heartbeat;
75150970Srwatson	struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
76150970Srwatson	char tsbuf[32];
77150970Srwatson
78150970Srwatson	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
79150970Srwatson	if (suspend_heartbeats)
80150970Srwatson		return;
81150970Srwatson
82150970Srwatson	/* return the received dot command to sender */
83150970Srwatson	cmd->status = IBMASM_CMD_PENDING;
84150970Srwatson	size = min(size, cmd->buffer_size);
85150970Srwatson	memcpy_fromio(cmd->buffer, message, size);
86150970Srwatson	header->type = sp_write;
87150970Srwatson	ibmasm_exec_command(sp, cmd);
88150970Srwatson}
89150970Srwatson