Commit 60ebd673 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents bd08ee23 8afc7e47
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "ipa_reg.h" #include "ipa_reg.h"
#include "ipa_mem.h" #include "ipa_mem.h"
#include "ipa_table.h" #include "ipa_table.h"
#include "ipa_smp2p.h"
#include "ipa_modem.h" #include "ipa_modem.h"
#include "ipa_uc.h" #include "ipa_uc.h"
#include "ipa_interrupt.h" #include "ipa_interrupt.h"
...@@ -801,6 +802,11 @@ static int ipa_remove(struct platform_device *pdev) ...@@ -801,6 +802,11 @@ static int ipa_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int ret; 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); ret = pm_runtime_get_sync(dev);
if (WARN_ON(ret < 0)) if (WARN_ON(ret < 0))
goto out_power_put; goto out_power_put;
......
...@@ -339,9 +339,6 @@ int ipa_modem_stop(struct ipa *ipa) ...@@ -339,9 +339,6 @@ int ipa_modem_stop(struct ipa *ipa)
if (state != IPA_MODEM_STATE_RUNNING) if (state != IPA_MODEM_STATE_RUNNING)
return -EBUSY; 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 */ /* Clean up the netdev and endpoints if it was started */
if (netdev) { if (netdev) {
struct ipa_priv *priv = netdev_priv(netdev); struct ipa_priv *priv = netdev_priv(netdev);
...@@ -369,6 +366,9 @@ static void ipa_modem_crashed(struct ipa *ipa) ...@@ -369,6 +366,9 @@ static void ipa_modem_crashed(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev; struct device *dev = &ipa->pdev->dev;
int ret; int ret;
/* Prevent the modem from triggering a call to ipa_setup() */
ipa_smp2p_irq_disable_setup(ipa);
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "error %d getting power to handle crash\n", ret); dev_err(dev, "error %d getting power to handle crash\n", ret);
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
* @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready * @setup_ready_irq: IPA interrupt triggered by modem to signal GSI ready
* @power_on: Whether IPA power is on * @power_on: Whether IPA power is on
* @notified: Whether modem has been notified of power state * @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 * @mutex: Mutex protecting ready-interrupt/shutdown interlock
* @panic_notifier: Panic notifier structure * @panic_notifier: Panic notifier structure
*/ */
...@@ -67,7 +67,7 @@ struct ipa_smp2p { ...@@ -67,7 +67,7 @@ struct ipa_smp2p {
u32 setup_ready_irq; u32 setup_ready_irq;
bool power_on; bool power_on;
bool notified; bool notified;
bool disabled; bool setup_disabled;
struct mutex mutex; struct mutex mutex;
struct notifier_block panic_notifier; struct notifier_block panic_notifier;
}; };
...@@ -155,11 +155,9 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id) ...@@ -155,11 +155,9 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
struct device *dev; struct device *dev;
int ret; int ret;
mutex_lock(&smp2p->mutex); /* Ignore any (spurious) interrupts received after the first */
if (smp2p->ipa->setup_complete)
if (smp2p->disabled) return IRQ_HANDLED;
goto out_mutex_unlock;
smp2p->disabled = true; /* If any others arrive, ignore them */
/* Power needs to be active for setup */ /* Power needs to be active for setup */
dev = &smp2p->ipa->pdev->dev; dev = &smp2p->ipa->pdev->dev;
...@@ -176,8 +174,6 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id) ...@@ -176,8 +174,6 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
out_power_put: out_power_put:
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev); (void)pm_runtime_put_autosuspend(dev);
out_mutex_unlock:
mutex_unlock(&smp2p->mutex);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -313,7 +309,7 @@ void ipa_smp2p_exit(struct ipa *ipa) ...@@ -313,7 +309,7 @@ void ipa_smp2p_exit(struct ipa *ipa)
kfree(smp2p); kfree(smp2p);
} }
void ipa_smp2p_disable(struct ipa *ipa) void ipa_smp2p_irq_disable_setup(struct ipa *ipa)
{ {
struct ipa_smp2p *smp2p = ipa->smp2p; struct ipa_smp2p *smp2p = ipa->smp2p;
...@@ -322,7 +318,10 @@ void ipa_smp2p_disable(struct ipa *ipa) ...@@ -322,7 +318,10 @@ void ipa_smp2p_disable(struct ipa *ipa)
mutex_lock(&smp2p->mutex); 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); mutex_unlock(&smp2p->mutex);
} }
......
...@@ -27,13 +27,12 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init); ...@@ -27,13 +27,12 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init);
void ipa_smp2p_exit(struct ipa *ipa); 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 * @ipa: IPA pointer
* *
* Prevent handling of the "setup ready" interrupt from the modem. * Disable the "ipa-setup-ready" interrupt from the modem.
* This is used before initiating shutdown of the driver.
*/ */
void ipa_smp2p_disable(struct ipa *ipa); void ipa_smp2p_irq_disable_setup(struct ipa *ipa);
/** /**
* ipa_smp2p_notify_reset() - Reset modem notification state * ipa_smp2p_notify_reset() - Reset modem notification state
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment