ipa_smp2p.c (1aac309d32075e73d1f93208b38cd2d5f03e0a5c) | ipa_smp2p.c (7aa0e8b8bd5b252c94900b19f2af8b7ec8a4e11d) |
---|---|
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 unchanged lines hidden (view full) --- 18#include "ipa_uc.h" 19 20/** 21 * DOC: IPA SMP2P communication with the modem 22 * 23 * SMP2P is a primitive communication mechanism available between the AP and 24 * the modem. The IPA driver uses this for two purposes: to enable the modem 25 * to state that the GSI hardware is ready to use; and to communicate the | 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 unchanged lines hidden (view full) --- 18#include "ipa_uc.h" 19 20/** 21 * DOC: IPA SMP2P communication with the modem 22 * 23 * SMP2P is a primitive communication mechanism available between the AP and 24 * the modem. The IPA driver uses this for two purposes: to enable the modem 25 * to state that the GSI hardware is ready to use; and to communicate the |
26 * state of the IPA clock in the event of a crash. | 26 * state of IPA power in the event of a crash. |
27 * 28 * GSI needs to have early initialization completed before it can be used. 29 * This initialization is done either by Trust Zone or by the modem. In the 30 * latter case, the modem uses an SMP2P interrupt to tell the AP IPA driver 31 * when the GSI is ready to use. 32 * | 27 * 28 * GSI needs to have early initialization completed before it can be used. 29 * This initialization is done either by Trust Zone or by the modem. In the 30 * latter case, the modem uses an SMP2P interrupt to tell the AP IPA driver 31 * when the GSI is ready to use. 32 * |
33 * The modem is also able to inquire about the current state of the IPA 34 * clock by trigging another SMP2P interrupt to the AP. We communicate 35 * whether the clock is enabled using two SMP2P state bits--one to 36 * indicate the clock state (on or off), and a second to indicate the 37 * clock state bit is valid. The modem will poll the valid bit until it 38 * is set, and at that time records whether the AP has the IPA clock enabled. | 33 * The modem is also able to inquire about the current state of IPA 34 * power by trigging another SMP2P interrupt to the AP. We communicate 35 * whether power is enabled using two SMP2P state bits--one to indicate 36 * the power state (on or off), and a second to indicate the power state 37 * bit is valid. The modem will poll the valid bit until it is set, and 38 * at that time records whether the AP has IPA power enabled. |
39 * 40 * Finally, if the AP kernel panics, we update the SMP2P state bits even if 41 * we never receive an interrupt from the modem requesting this. 42 */ 43 44/** 45 * struct ipa_smp2p - IPA SMP2P information 46 * @ipa: IPA pointer 47 * @valid_state: SMEM state indicating enabled state is valid | 39 * 40 * Finally, if the AP kernel panics, we update the SMP2P state bits even if 41 * we never receive an interrupt from the modem requesting this. 42 */ 43 44/** 45 * struct ipa_smp2p - IPA SMP2P information 46 * @ipa: IPA pointer 47 * @valid_state: SMEM state indicating enabled state is valid |
48 * @enabled_state: SMEM state to indicate clock is enabled | 48 * @enabled_state: SMEM state to indicate power is enabled |
49 * @valid_bit: Valid bit in 32-bit SMEM state mask 50 * @enabled_bit: Enabled bit in 32-bit SMEM state mask 51 * @enabled_bit: Enabled bit in 32-bit SMEM state mask | 49 * @valid_bit: Valid bit in 32-bit SMEM state mask 50 * @enabled_bit: Enabled bit in 32-bit SMEM state mask 51 * @enabled_bit: Enabled bit in 32-bit SMEM state mask |
52 * @clock_query_irq: IPA interrupt triggered by modem for clock query | 52 * @clock_query_irq: IPA interrupt triggered by modem for power query |
53 * @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready | 53 * @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready |
54 * @clock_on: Whether IPA clock is on 55 * @notified: Whether modem has been notified of clock state | 54 * @power_on: Whether IPA power is on 55 * @notified: Whether modem has been notified of power state |
56 * @disabled: Whether setup ready interrupt handling is disabled 57 * @mutex: Mutex protecting ready-interrupt/shutdown interlock 58 * @panic_notifier: Panic notifier structure 59*/ 60struct ipa_smp2p { 61 struct ipa *ipa; 62 struct qcom_smem_state *valid_state; 63 struct qcom_smem_state *enabled_state; 64 u32 valid_bit; 65 u32 enabled_bit; 66 u32 clock_query_irq; 67 u32 setup_ready_irq; | 56 * @disabled: Whether setup ready interrupt handling is disabled 57 * @mutex: Mutex protecting ready-interrupt/shutdown interlock 58 * @panic_notifier: Panic notifier structure 59*/ 60struct ipa_smp2p { 61 struct ipa *ipa; 62 struct qcom_smem_state *valid_state; 63 struct qcom_smem_state *enabled_state; 64 u32 valid_bit; 65 u32 enabled_bit; 66 u32 clock_query_irq; 67 u32 setup_ready_irq; |
68 bool clock_on; | 68 bool power_on; |
69 bool notified; 70 bool disabled; 71 struct mutex mutex; 72 struct notifier_block panic_notifier; 73}; 74 75/** | 69 bool notified; 70 bool disabled; 71 struct mutex mutex; 72 struct notifier_block panic_notifier; 73}; 74 75/** |
76 * ipa_smp2p_notify() - use SMP2P to tell modem about IPA clock state | 76 * ipa_smp2p_notify() - use SMP2P to tell modem about IPA power state |
77 * @smp2p: SMP2P information 78 * 79 * This is called either when the modem has requested it (by triggering | 77 * @smp2p: SMP2P information 78 * 79 * This is called either when the modem has requested it (by triggering |
80 * the modem clock query IPA interrupt) or whenever the AP is shutting down | 80 * the modem power query IPA interrupt) or whenever the AP is shutting down |
81 * (via a panic notifier). It sets the two SMP2P state bits--one saying | 81 * (via a panic notifier). It sets the two SMP2P state bits--one saying |
82 * whether the IPA clock is running, and the other indicating the first bit | 82 * whether the IPA power is on, and the other indicating the first bit |
83 * is valid. 84 */ 85static void ipa_smp2p_notify(struct ipa_smp2p *smp2p) 86{ 87 struct device *dev; 88 u32 value; 89 u32 mask; 90 91 if (smp2p->notified) 92 return; 93 94 dev = &smp2p->ipa->pdev->dev; | 83 * is valid. 84 */ 85static void ipa_smp2p_notify(struct ipa_smp2p *smp2p) 86{ 87 struct device *dev; 88 u32 value; 89 u32 mask; 90 91 if (smp2p->notified) 92 return; 93 94 dev = &smp2p->ipa->pdev->dev; |
95 smp2p->clock_on = pm_runtime_get_if_active(dev, true) > 0; | 95 smp2p->power_on = pm_runtime_get_if_active(dev, true) > 0; |
96 | 96 |
97 /* Signal whether the clock is enabled */ | 97 /* Signal whether the IPA power is enabled */ |
98 mask = BIT(smp2p->enabled_bit); | 98 mask = BIT(smp2p->enabled_bit); |
99 value = smp2p->clock_on ? mask : 0; | 99 value = smp2p->power_on ? mask : 0; |
100 qcom_smem_state_update_bits(smp2p->enabled_state, mask, value); 101 102 /* Now indicate that the enabled flag is valid */ 103 mask = BIT(smp2p->valid_bit); 104 value = mask; 105 qcom_smem_state_update_bits(smp2p->valid_state, mask, value); 106 107 smp2p->notified = true; --- 13 unchanged lines hidden (view full) --- 121 unsigned long action, void *data) 122{ 123 struct ipa_smp2p *smp2p; 124 125 smp2p = container_of(nb, struct ipa_smp2p, panic_notifier); 126 127 ipa_smp2p_notify(smp2p); 128 | 100 qcom_smem_state_update_bits(smp2p->enabled_state, mask, value); 101 102 /* Now indicate that the enabled flag is valid */ 103 mask = BIT(smp2p->valid_bit); 104 value = mask; 105 qcom_smem_state_update_bits(smp2p->valid_state, mask, value); 106 107 smp2p->notified = true; --- 13 unchanged lines hidden (view full) --- 121 unsigned long action, void *data) 122{ 123 struct ipa_smp2p *smp2p; 124 125 smp2p = container_of(nb, struct ipa_smp2p, panic_notifier); 126 127 ipa_smp2p_notify(smp2p); 128 |
129 if (smp2p->clock_on) | 129 if (smp2p->power_on) |
130 ipa_uc_panic_notifier(smp2p->ipa); 131 132 return NOTIFY_DONE; 133} 134 135static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p) 136{ 137 /* IPA panic handler needs to run before modem shuts down */ --- 66 unchanged lines hidden (view full) --- 204 return irq; 205} 206 207static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq) 208{ 209 free_irq(irq, smp2p); 210} 211 | 130 ipa_uc_panic_notifier(smp2p->ipa); 131 132 return NOTIFY_DONE; 133} 134 135static int ipa_smp2p_panic_notifier_register(struct ipa_smp2p *smp2p) 136{ 137 /* IPA panic handler needs to run before modem shuts down */ --- 66 unchanged lines hidden (view full) --- 204 return irq; 205} 206 207static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq) 208{ 209 free_irq(irq, smp2p); 210} 211 |
212/* Drop the clock reference if it was taken in ipa_smp2p_notify() */ 213static void ipa_smp2p_clock_release(struct ipa *ipa) | 212/* Drop the power reference if it was taken in ipa_smp2p_notify() */ 213static void ipa_smp2p_power_release(struct ipa *ipa) |
214{ 215 struct device *dev = &ipa->pdev->dev; 216 | 214{ 215 struct device *dev = &ipa->pdev->dev; 216 |
217 if (!ipa->smp2p->clock_on) | 217 if (!ipa->smp2p->power_on) |
218 return; 219 220 pm_runtime_mark_last_busy(dev); 221 (void)pm_runtime_put_autosuspend(dev); | 218 return; 219 220 pm_runtime_mark_last_busy(dev); 221 (void)pm_runtime_put_autosuspend(dev); |
222 ipa->smp2p->clock_on = false; | 222 ipa->smp2p->power_on = false; |
223} 224 225/* Initialize the IPA SMP2P subsystem */ 226int ipa_smp2p_init(struct ipa *ipa, bool modem_init) 227{ 228 struct qcom_smem_state *enabled_state; 229 struct device *dev = &ipa->pdev->dev; 230 struct qcom_smem_state *valid_state; --- 17 unchanged lines hidden (view full) --- 248 return -EINVAL; 249 250 smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL); 251 if (!smp2p) 252 return -ENOMEM; 253 254 smp2p->ipa = ipa; 255 | 223} 224 225/* Initialize the IPA SMP2P subsystem */ 226int ipa_smp2p_init(struct ipa *ipa, bool modem_init) 227{ 228 struct qcom_smem_state *enabled_state; 229 struct device *dev = &ipa->pdev->dev; 230 struct qcom_smem_state *valid_state; --- 17 unchanged lines hidden (view full) --- 248 return -EINVAL; 249 250 smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL); 251 if (!smp2p) 252 return -ENOMEM; 253 254 smp2p->ipa = ipa; 255 |
256 /* These fields are needed by the clock query interrupt | 256 /* These fields are needed by the power query interrupt |
257 * handler, so initialize them now. 258 */ 259 mutex_init(&smp2p->mutex); 260 smp2p->valid_state = valid_state; 261 smp2p->valid_bit = valid_bit; 262 smp2p->enabled_state = enabled_state; 263 smp2p->enabled_bit = enabled_bit; 264 --- 36 unchanged lines hidden (view full) --- 301void ipa_smp2p_exit(struct ipa *ipa) 302{ 303 struct ipa_smp2p *smp2p = ipa->smp2p; 304 305 if (smp2p->setup_ready_irq) 306 ipa_smp2p_irq_exit(smp2p, smp2p->setup_ready_irq); 307 ipa_smp2p_panic_notifier_unregister(smp2p); 308 ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq); | 257 * handler, so initialize them now. 258 */ 259 mutex_init(&smp2p->mutex); 260 smp2p->valid_state = valid_state; 261 smp2p->valid_bit = valid_bit; 262 smp2p->enabled_state = enabled_state; 263 smp2p->enabled_bit = enabled_bit; 264 --- 36 unchanged lines hidden (view full) --- 301void ipa_smp2p_exit(struct ipa *ipa) 302{ 303 struct ipa_smp2p *smp2p = ipa->smp2p; 304 305 if (smp2p->setup_ready_irq) 306 ipa_smp2p_irq_exit(smp2p, smp2p->setup_ready_irq); 307 ipa_smp2p_panic_notifier_unregister(smp2p); 308 ipa_smp2p_irq_exit(smp2p, smp2p->clock_query_irq); |
309 /* We won't get notified any more; drop clock reference (if any) */ 310 ipa_smp2p_clock_release(ipa); | 309 /* We won't get notified any more; drop power reference (if any) */ 310 ipa_smp2p_power_release(ipa); |
311 ipa->smp2p = NULL; 312 mutex_destroy(&smp2p->mutex); 313 kfree(smp2p); 314} 315 316void ipa_smp2p_disable(struct ipa *ipa) 317{ 318 struct ipa_smp2p *smp2p = ipa->smp2p; --- 12 unchanged lines hidden (view full) --- 331void ipa_smp2p_notify_reset(struct ipa *ipa) 332{ 333 struct ipa_smp2p *smp2p = ipa->smp2p; 334 u32 mask; 335 336 if (!smp2p->notified) 337 return; 338 | 311 ipa->smp2p = NULL; 312 mutex_destroy(&smp2p->mutex); 313 kfree(smp2p); 314} 315 316void ipa_smp2p_disable(struct ipa *ipa) 317{ 318 struct ipa_smp2p *smp2p = ipa->smp2p; --- 12 unchanged lines hidden (view full) --- 331void ipa_smp2p_notify_reset(struct ipa *ipa) 332{ 333 struct ipa_smp2p *smp2p = ipa->smp2p; 334 u32 mask; 335 336 if (!smp2p->notified) 337 return; 338 |
339 ipa_smp2p_clock_release(ipa); | 339 ipa_smp2p_power_release(ipa); |
340 | 340 |
341 /* Reset the clock enabled valid flag */ | 341 /* Reset the power enabled valid flag */ |
342 mask = BIT(smp2p->valid_bit); 343 qcom_smem_state_update_bits(smp2p->valid_state, mask, 0); 344 | 342 mask = BIT(smp2p->valid_bit); 343 qcom_smem_state_update_bits(smp2p->valid_state, mask, 0); 344 |
345 /* Mark the clock disabled for good measure... */ | 345 /* Mark the power disabled for good measure... */ |
346 mask = BIT(smp2p->enabled_bit); 347 qcom_smem_state_update_bits(smp2p->enabled_state, mask, 0); 348 349 smp2p->notified = false; 350} | 346 mask = BIT(smp2p->enabled_bit); 347 qcom_smem_state_update_bits(smp2p->enabled_state, mask, 0); 348 349 smp2p->notified = false; 350} |