1// SPDX-License-Identifier: GPL-2.0
2
3/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2019-2020 Linaro Ltd.
5 */
6
7#include <linux/types.h>
8#include <linux/device.h>
9#include <linux/interrupt.h>
10#include <linux/notifier.h>
11#include <linux/soc/qcom/smem.h>
12#include <linux/soc/qcom/smem_state.h>
13
14#include "ipa_smp2p.h"
15#include "ipa.h"
16#include "ipa_uc.h"
17#include "ipa_clock.h"
18
19/**
20 * DOC: IPA SMP2P communication with the modem
21 *
22 * SMP2P is a primitive communication mechanism available between the AP and
23 * the modem.  The IPA driver uses this for two purposes:  to enable the modem
24 * to state that the GSI hardware is ready to use; and to communicate the
25 * state of the IPA clock in the event of a crash.
26 *
27 * GSI needs to have early initialization completed before it can be used.
28 * This initialization is done either by Trust Zone or by the modem.  In the
29 * latter case, the modem uses an SMP2P interrupt to tell the AP IPA driver
30 * when the GSI is ready to use.
31 *
32 * The modem is also able to inquire about the current state of the IPA
33 * clock by trigging another SMP2P interrupt to the AP.  We communicate
34 * whether the clock is enabled using two SMP2P state bits--one to
35 * indicate the clock state (on or off), and a second to indicate the
36 * clock state bit is valid.  The modem will poll the valid bit until it
37 * is set, and at that time records whether the AP has the IPA clock enabled.
38 *
39 * Finally, if the AP kernel panics, we update the SMP2P state bits even if
40 * we never receive an interrupt from the modem requesting this.
41 */
42
43/**
44 * struct ipa_smp2p - IPA SMP2P information
45 * @ipa:		IPA pointer
46 * @valid_state:	SMEM state indicating enabled state is valid
47 * @enabled_state:	SMEM state to indicate clock is enabled
48 * @valid_bit:		Valid bit in 32-bit SMEM state mask
49 * @enabled_bit:	Enabled bit in 32-bit SMEM state mask
50 * @enabled_bit:	Enabled bit in 32-bit SMEM state mask
51 * @clock_query_irq:	IPA interrupt triggered by modem for clock query
52 * @setup_ready_irq:	IPA interrupt triggered by modem to signal GSI ready
53 * @clock_on:		Whether IPA clock is on
54 * @notified:		Whether modem has been notified of clock state
55 * @disabled:		Whether setup ready interrupt handling is disabled
56 * @mutex:		Mutex protecting ready-interrupt/shutdown interlock
57 * @panic_notifier:	Panic notifier structure
58*/
59struct ipa_smp2p {
60	struct ipa *ipa;
61	struct qcom_smem_state *valid_state;
62	struct qcom_smem_state *enabled_state;
63	u32 valid_bit;
64	u32 enabled_bit;
65	u32 clock_query_irq;
66	u32 setup_ready_irq;
67	bool clock_on;
68	bool notified;
69	bool disabled;
70	struct mutex mutex;
71	struct notifier_block panic_notifier;
72};
73
74/**
75 * ipa_smp2p_notify() - use SMP2P to tell modem about IPA clock state
76 * @smp2p:	SMP2P information
77 *
78 * This is called either when the modem has requested it (by triggering
79 * the modem clock query IPA interrupt) or whenever the AP is shutting down
80 * (via a panic notifier).  It sets the two SMP2P state bits--one saying
81 * whether the IPA clock is running, and the other indicating the first bit
82 * is valid.
83 */
84static void ipa_smp2p_notify(struct ipa_smp2p *smp2p)
85{
86	u32 value;
87	u32 mask;
88
89	if (smp2p->notified)
90		return;
91
92	smp2p->clock_on = ipa_clock_get_additional(smp2p->ipa);
93
94	/* Signal whether the clock is enabled */
95	mask = BIT(smp2p->enabled_bit);
96	value = smp2p->clock_on ? mask : 0;
97	qcom_smem_state_update_bits(smp2p->enabled_state, mask, value);
98
99	/* Now indicate that the enabled flag is valid */
100	mask = BIT(smp2p->valid_bit);
101	value = mask;
102	qcom_smem_state_update_bits(smp2p->valid_state, mask, value);
103
104	smp2p->notified = true;
105}
106
107/* Threaded IRQ handler for modem "ipa-clock-query" SMP2P interrupt */
108static irqreturn_t ipa_smp2p_modem_clk_query_isr(int irq, void *dev_id)
109{
110	struct ipa_smp2p *smp2p = dev_id;
111
112	ipa_smp2p_notify(smp2p);
113
114	return IRQ_HANDLED;
115}
116
117static int ipa_smp2p_panic_notifier(struct notifier_block *nb,
118				    unsigned long action, void *data)
119{
120	struct ipa_smp2p *smp2p;
121
122	smp2p = container_of(nb, struct ipa_smp2p, panic_notifier);
123
124	ipa_smp2p_notify(smp2p);
125
126	if (smp2p->clock_on)
127		ipa_uc_panic_notifier(smp2p->ipa);
128
129	return NOTIFY_DONE;
130}
131
132static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p)
133{
134	/* IPA panic handler needs to run before modem shuts down */
135	smp2p->panic_notifier.notifier_call = ipa_smp2p_panic_notifier;
136	smp2p->panic_notifier.priority = INT_MAX;	/* Do it early */
137
138	return atomic_notifier_chain_register(&panic_notifier_list,
139					      &smp2p->panic_notifier);
140}
141
142static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p)
143{
144	atomic_notifier_chain_unregister(&panic_notifier_list,
145					 &smp2p->panic_notifier);
146}
147
148/* Threaded IRQ handler for modem "ipa-setup-ready" SMP2P interrupt */
149static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
150{
151	struct ipa_smp2p *smp2p = dev_id;
152
153	mutex_lock(&smp2p->mutex);
154
155	if (!smp2p->disabled) {
156		int ret;
157
158		ret = ipa_setup(smp2p->ipa);
159		if (ret)
160			dev_err(&smp2p->ipa->pdev->dev,
161				"error %d from ipa_setup()\n", ret);
162		smp2p->disabled = true;
163	}
164
165	mutex_unlock(&smp2p->mutex);
166
167	return IRQ_HANDLED;
168}
169
170/* Initialize SMP2P interrupts */
171static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, const char *name,
172			      irq_handler_t handler)
173{
174	struct device *dev = &smp2p->ipa->pdev->dev;
175	unsigned int irq;
176	int ret;
177
178	ret = platform_get_irq_byname(smp2p->ipa->pdev, name);
179	if (ret <= 0) {
180		dev_err(dev, "DT error %d getting \"%s\" IRQ property\n",
181			ret, name);
182		return ret ? : -EINVAL;
183	}
184	irq = ret;
185
186	ret = request_threaded_irq(irq, NULL, handler, 0, name, smp2p);
187	if (ret) {
188		dev_err(dev, "error %d requesting \"%s\" IRQ\n", ret, name);
189		return ret;
190	}
191
192	return irq;
193}
194
195static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq)
196{
197	free_irq(irq, smp2p);
198}
199
200/* Drop the clock reference if it was taken in ipa_smp2p_notify() */
201static void ipa_smp2p_clock_release(struct ipa *ipa)
202{
203	if (!ipa->smp2p->clock_on)
204		return;
205
206	ipa_clock_put(ipa);
207	ipa->smp2p->clock_on = false;
208}
209
210/* Initialize the IPA SMP2P subsystem */
211int ipa_smp2p_init(struct ipa *ipa, bool modem_init)
212{
213	struct qcom_smem_state *enabled_state;
214	struct device *dev = &ipa->pdev->dev;
215	struct qcom_smem_state *valid_state;
216	struct ipa_smp2p *smp2p;
217	u32 enabled_bit;
218	u32 valid_bit;
219	int ret;
220
221	valid_state = qcom_smem_state_get(dev, "ipa-clock-enabled-valid",
222					  &valid_bit);
223	if (IS_ERR(valid_state))
224		return PTR_ERR(valid_state);
225	if (valid_bit >= 32)		/* BITS_PER_U32 */
226		return -EINVAL;
227
228	enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
229					    &enabled_bit);
230	if (IS_ERR(enabled_state))
231		return PTR_ERR(enabled_state);
232	if (enabled_bit >= 32)		/* BITS_PER_U32 */
233		return -EINVAL;
234
235	smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL);
236	if (!smp2p)
237		return -ENOMEM;
238
239	smp2p->ipa = ipa;
240
241	/* These fields are needed by the clock query interrupt
242	 * handler, so initialize them now.
243	 */
244	mutex_init(&smp2p->mutex);
245	smp2p->valid_state = valid_state;
246	smp2p->valid_bit = valid_bit;
247	smp2p->enabled_state = enabled_state;
248	smp2p->enabled_bit = enabled_bit;
249
250	/* We have enough information saved to handle notifications */
251	ipa->smp2p = smp2p;
252
253	ret = ipa_smp2p_irq_init(smp2p, "ipa-clock-query",
254				 ipa_smp2p_modem_clk_query_isr);
255	if (ret < 0)
256		goto err_null_smp2p;
257	smp2p->clock_query_irq = ret;
258
259	ret = ipa_smp2p_panic_notifier_register(smp2p);
260	if (ret)
261		goto err_irq_exit;
262
263	if (modem_init) {
264		/* Result will be non-zero (negative for error) */
265		ret = ipa_smp2p_irq_init(smp2p, "ipa-setup-ready",
266					 ipa_smp2p_modem_setup_ready_isr);
267		if (ret < 0)
268			goto err_notifier_unregister;
269		smp2p->setup_ready_irq = ret;
270	}
271
272	return 0;
273
274err_notifier_unregister:
275	ipa_smp2p_panic_notifier_unregister(smp2p);
276err_irq_exit:
277	ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq);
278err_null_smp2p:
279	ipa->smp2p = NULL;
280	mutex_destroy(&smp2p->mutex);
281	kfree(smp2p);
282
283	return ret;
284}
285
286void ipa_smp2p_exit(struct ipa *ipa)
287{
288	struct ipa_smp2p *smp2p = ipa->smp2p;
289
290	if (smp2p->setup_ready_irq)
291		ipa_smp2p_irq_exit(smp2p, smp2p->setup_ready_irq);
292	ipa_smp2p_panic_notifier_unregister(smp2p);
293	ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq);
294	/* We won't get notified any more; drop clock reference (if any) */
295	ipa_smp2p_clock_release(ipa);
296	ipa->smp2p = NULL;
297	mutex_destroy(&smp2p->mutex);
298	kfree(smp2p);
299}
300
301void ipa_smp2p_disable(struct ipa *ipa)
302{
303	struct ipa_smp2p *smp2p = ipa->smp2p;
304
305	if (!smp2p->setup_ready_irq)
306		return;
307
308	mutex_lock(&smp2p->mutex);
309
310	smp2p->disabled = true;
311
312	mutex_unlock(&smp2p->mutex);
313}
314
315/* Reset state tracking whether we have notified the modem */
316void ipa_smp2p_notify_reset(struct ipa *ipa)
317{
318	struct ipa_smp2p *smp2p = ipa->smp2p;
319	u32 mask;
320
321	if (!smp2p->notified)
322		return;
323
324	ipa_smp2p_clock_release(ipa);
325
326	/* Reset the clock enabled valid flag */
327	mask = BIT(smp2p->valid_bit);
328	qcom_smem_state_update_bits(smp2p->valid_state, mask, 0);
329
330	/* Mark the clock disabled for good measure... */
331	mask = BIT(smp2p->enabled_bit);
332	qcom_smem_state_update_bits(smp2p->enabled_state, mask, 0);
333
334	smp2p->notified = false;
335}
336