forked from Minki/linux
Merge branch 'ipa-fixes'
Alex Elder says: ==================== net: ipa: prevent shutdown during setup The setup phase of the IPA driver occurs in one of two ways. Normally, it is done directly by the main driver probe function. But some systems (those having a "modem-init" DTS property) don't start setup until an SMP2P interrupt (sent by the modem) arrives. Because it isn't performed by the probe function, setup on "modem-init" systems could be underway at the time a driver remove (or shutdown) request arrives (or vice-versa). This situation can lead to hardware state not being cleaned up properly. This series addresses this problem by having the driver remove function disable the setup interrupt. A consequence of this is that setup will complete if it is underway when the remove function is called. So now, when removing the driver, setup: - will have already completed; - is underway, and will complete before proceeding; or - will not have begun (and will not occur). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
60ebd6737c
@ -28,6 +28,7 @@
|
||||
#include "ipa_reg.h"
|
||||
#include "ipa_mem.h"
|
||||
#include "ipa_table.h"
|
||||
#include "ipa_smp2p.h"
|
||||
#include "ipa_modem.h"
|
||||
#include "ipa_uc.h"
|
||||
#include "ipa_interrupt.h"
|
||||
@ -801,6 +802,11 @@ static int ipa_remove(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
/* Prevent the modem from triggering a call to ipa_setup(). This
|
||||
* also ensures a modem-initiated setup that's underway completes.
|
||||
*/
|
||||
ipa_smp2p_irq_disable_setup(ipa);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (WARN_ON(ret < 0))
|
||||
goto out_power_put;
|
||||
|
@ -339,9 +339,6 @@ int ipa_modem_stop(struct ipa *ipa)
|
||||
if (state != IPA_MODEM_STATE_RUNNING)
|
||||
return -EBUSY;
|
||||
|
||||
/* Prevent the modem from triggering a call to ipa_setup() */
|
||||
ipa_smp2p_disable(ipa);
|
||||
|
||||
/* Clean up the netdev and endpoints if it was started */
|
||||
if (netdev) {
|
||||
struct ipa_priv *priv = netdev_priv(netdev);
|
||||
@ -369,6 +366,9 @@ static void ipa_modem_crashed(struct ipa *ipa)
|
||||
struct device *dev = &ipa->pdev->dev;
|
||||
int ret;
|
||||
|
||||
/* Prevent the modem from triggering a call to ipa_setup() */
|
||||
ipa_smp2p_irq_disable_setup(ipa);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error %d getting power to handle crash\n", ret);
|
||||
|
@ -53,7 +53,7 @@
|
||||
* @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready
|
||||
* @power_on: Whether IPA power is on
|
||||
* @notified: Whether modem has been notified of power state
|
||||
* @disabled: Whether setup ready interrupt handling is disabled
|
||||
* @setup_disabled: Whether setup ready interrupt handler is disabled
|
||||
* @mutex: Mutex protecting ready-interrupt/shutdown interlock
|
||||
* @panic_notifier: Panic notifier structure
|
||||
*/
|
||||
@ -67,7 +67,7 @@ struct ipa_smp2p {
|
||||
u32 setup_ready_irq;
|
||||
bool power_on;
|
||||
bool notified;
|
||||
bool disabled;
|
||||
bool setup_disabled;
|
||||
struct mutex mutex;
|
||||
struct notifier_block panic_notifier;
|
||||
};
|
||||
@ -155,11 +155,9 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&smp2p->mutex);
|
||||
|
||||
if (smp2p->disabled)
|
||||
goto out_mutex_unlock;
|
||||
smp2p->disabled = true; /* If any others arrive, ignore them */
|
||||
/* Ignore any (spurious) interrupts received after the first */
|
||||
if (smp2p->ipa->setup_complete)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Power needs to be active for setup */
|
||||
dev = &smp2p->ipa->pdev->dev;
|
||||
@ -176,8 +174,6 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
|
||||
out_power_put:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
(void)pm_runtime_put_autosuspend(dev);
|
||||
out_mutex_unlock:
|
||||
mutex_unlock(&smp2p->mutex);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -313,7 +309,7 @@ void ipa_smp2p_exit(struct ipa *ipa)
|
||||
kfree(smp2p);
|
||||
}
|
||||
|
||||
void ipa_smp2p_disable(struct ipa *ipa)
|
||||
void ipa_smp2p_irq_disable_setup(struct ipa *ipa)
|
||||
{
|
||||
struct ipa_smp2p *smp2p = ipa->smp2p;
|
||||
|
||||
@ -322,7 +318,10 @@ void ipa_smp2p_disable(struct ipa *ipa)
|
||||
|
||||
mutex_lock(&smp2p->mutex);
|
||||
|
||||
smp2p->disabled = true;
|
||||
if (!smp2p->setup_disabled) {
|
||||
disable_irq(smp2p->setup_ready_irq);
|
||||
smp2p->setup_disabled = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&smp2p->mutex);
|
||||
}
|
||||
|
@ -27,13 +27,12 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init);
|
||||
void ipa_smp2p_exit(struct ipa *ipa);
|
||||
|
||||
/**
|
||||
* ipa_smp2p_disable() - Prevent "ipa-setup-ready" interrupt handling
|
||||
* ipa_smp2p_irq_disable_setup() - Disable the "setup ready" interrupt
|
||||
* @ipa: IPA pointer
|
||||
*
|
||||
* Prevent handling of the "setup ready" interrupt from the modem.
|
||||
* This is used before initiating shutdown of the driver.
|
||||
* Disable the "ipa-setup-ready" interrupt from the modem.
|
||||
*/
|
||||
void ipa_smp2p_disable(struct ipa *ipa);
|
||||
void ipa_smp2p_irq_disable_setup(struct ipa *ipa);
|
||||
|
||||
/**
|
||||
* ipa_smp2p_notify_reset() - Reset modem notification state
|
||||
|
Loading…
Reference in New Issue
Block a user