summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ipa/ipa_clock.c44
-rw-r--r--drivers/net/ipa/ipa_clock.h14
-rw-r--r--drivers/net/ipa/ipa_interrupt.c9
-rw-r--r--drivers/net/ipa/ipa_main.c36
-rw-r--r--drivers/net/ipa/ipa_modem.c15
-rw-r--r--drivers/net/ipa/ipa_smp2p.c28
-rw-r--r--drivers/net/ipa/ipa_uc.c12
7 files changed, 99 insertions, 59 deletions
diff --git a/drivers/net/ipa/ipa_clock.c b/drivers/net/ipa/ipa_clock.c
index a67b6136e3c0..d5a8b45ee59d 100644
--- a/drivers/net/ipa/ipa_clock.c
+++ b/drivers/net/ipa/ipa_clock.c
@@ -223,10 +223,11 @@ static int ipa_clock_enable(struct ipa *ipa)
}
/* Inverse of ipa_clock_enable() */
-static void ipa_clock_disable(struct ipa *ipa)
+static int ipa_clock_disable(struct ipa *ipa)
{
clk_disable_unprepare(ipa->clock->core);
- (void)ipa_interconnect_disable(ipa);
+
+ return ipa_interconnect_disable(ipa);
}
/* Get an IPA clock reference, but only if the reference count is
@@ -246,43 +247,51 @@ bool ipa_clock_get_additional(struct ipa *ipa)
* Incrementing the reference count is intentionally deferred until
* after the clock is running and endpoints are resumed.
*/
-void ipa_clock_get(struct ipa *ipa)
+int ipa_clock_get(struct ipa *ipa)
{
struct ipa_clock *clock = ipa->clock;
int ret;
/* If the clock is running, just bump the reference count */
if (ipa_clock_get_additional(ipa))
- return;
+ return 1;
/* Otherwise get the mutex and check again */
mutex_lock(&clock->mutex);
/* A reference might have been added before we got the mutex. */
- if (ipa_clock_get_additional(ipa))
+ if (ipa_clock_get_additional(ipa)) {
+ ret = 1;
goto out_mutex_unlock;
+ }
ret = ipa_clock_enable(ipa);
- if (!ret)
- refcount_set(&clock->count, 1);
+
+ refcount_set(&clock->count, 1);
+
out_mutex_unlock:
mutex_unlock(&clock->mutex);
+
+ return ret;
}
/* Attempt to remove an IPA clock reference. If this represents the
* last reference, disable the IPA clock under protection of the mutex.
*/
-void ipa_clock_put(struct ipa *ipa)
+int ipa_clock_put(struct ipa *ipa)
{
struct ipa_clock *clock = ipa->clock;
+ int ret;
/* If this is not the last reference there's nothing more to do */
if (!refcount_dec_and_mutex_lock(&clock->count, &clock->mutex))
- return;
+ return 0;
- ipa_clock_disable(ipa);
+ ret = ipa_clock_disable(ipa);
mutex_unlock(&clock->mutex);
+
+ return ret;
}
/* Return the current IPA core clock rate */
@@ -388,7 +397,7 @@ void ipa_clock_exit(struct ipa_clock *clock)
* ipa_suspend() - Power management system suspend callback
* @dev: IPA device structure
*
- * Return: Always returns zero
+ * Return: 0 on success, or a negative error code
*
* Called by the PM framework when a system suspend operation is invoked.
* Suspends endpoints and releases the clock reference held to keep
@@ -405,16 +414,14 @@ static int ipa_suspend(struct device *dev)
gsi_suspend(&ipa->gsi);
}
- ipa_clock_put(ipa);
-
- return 0;
+ return ipa_clock_put(ipa);
}
/**
* ipa_resume() - Power management system resume callback
* @dev: IPA device structure
*
- * Return: Always returns 0
+ * Return: 0 on success, or a negative error code
*
* Called by the PM framework when a system resume operation is invoked.
* Takes an IPA clock reference to keep the clock running until suspend,
@@ -423,11 +430,16 @@ static int ipa_suspend(struct device *dev)
static int ipa_resume(struct device *dev)
{
struct ipa *ipa = dev_get_drvdata(dev);
+ int ret;
/* This clock reference will keep the IPA out of suspend
* until we get a power management suspend request.
*/
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0)) {
+ (void)ipa_clock_put(ipa);
+ return ret;
+ }
/* Endpoints aren't usable until setup is complete */
if (ipa->setup_complete) {
diff --git a/drivers/net/ipa/ipa_clock.h b/drivers/net/ipa/ipa_clock.h
index 2a0f7ff3c9e6..8692c0d98bd1 100644
--- a/drivers/net/ipa/ipa_clock.h
+++ b/drivers/net/ipa/ipa_clock.h
@@ -54,14 +54,20 @@ void ipa_clock_exit(struct ipa_clock *clock);
* ipa_clock_get() - Get an IPA clock reference
* @ipa: IPA pointer
*
- * This call blocks if this is the first reference.
+ * Return: 0 if clock started, 1 if clock already running, or a negative
+ * error code
+ *
+ * This call blocks if this is the first reference. A reference is
+ * taken even if an error occurs starting the IPA clock.
*/
-void ipa_clock_get(struct ipa *ipa);
+int ipa_clock_get(struct ipa *ipa);
/**
* ipa_clock_get_additional() - Get an IPA clock reference if not first
* @ipa: IPA pointer
*
+ * Return: true if reference taken, false otherwise
+ *
* This returns immediately, and only takes a reference if not the first
*/
bool ipa_clock_get_additional(struct ipa *ipa);
@@ -70,10 +76,12 @@ bool ipa_clock_get_additional(struct ipa *ipa);
* ipa_clock_put() - Drop an IPA clock reference
* @ipa: IPA pointer
*
+ * Return: 0 if successful, or a negative error code
+ *
* This drops a clock reference. If the last reference is being dropped,
* the clock is stopped and RX endpoints are suspended. This call will
* not block unless the last reference is dropped.
*/
-void ipa_clock_put(struct ipa *ipa);
+int ipa_clock_put(struct ipa *ipa);
#endif /* _IPA_CLOCK_H_ */
diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c
index aa37f03f4557..934c14e066a0 100644
--- a/drivers/net/ipa/ipa_interrupt.c
+++ b/drivers/net/ipa/ipa_interrupt.c
@@ -83,8 +83,11 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
u32 pending;
u32 offset;
u32 mask;
+ int ret;
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto out_clock_put;
/* The status register indicates which conditions are present,
* including conditions whose interrupt is not enabled. Handle
@@ -112,8 +115,8 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
offset = ipa_reg_irq_clr_offset(ipa->version);
iowrite32(pending, ipa->reg_virt + offset);
}
-
- ipa_clock_put(ipa);
+out_clock_put:
+ (void)ipa_clock_put(ipa);
return IRQ_HANDLED;
}
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 25bbb456e007..64112a676774 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -431,7 +431,9 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
* is held after initialization completes, and won't get dropped
* unless/until a system suspend request arrives.
*/
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto err_clock_put;
ipa_hardware_config(ipa, data);
@@ -475,7 +477,8 @@ err_mem_deconfig:
ipa_mem_deconfig(ipa);
err_hardware_deconfig:
ipa_hardware_deconfig(ipa);
- ipa_clock_put(ipa);
+err_clock_put:
+ (void)ipa_clock_put(ipa);
return ret;
}
@@ -493,7 +496,7 @@ static void ipa_deconfig(struct ipa *ipa)
ipa->interrupt = NULL;
ipa_mem_deconfig(ipa);
ipa_hardware_deconfig(ipa);
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
}
static int ipa_firmware_load(struct device *dev)
@@ -750,20 +753,22 @@ static int ipa_probe(struct platform_device *pdev)
goto err_table_exit;
/* The clock needs to be active for config and setup */
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto err_clock_put;
ret = ipa_config(ipa, data);
if (ret)
- goto err_clock_put; /* Error */
+ goto err_clock_put;
dev_info(dev, "IPA driver initialized");
/* If the modem is doing early initialization, it will trigger a
- * call to ipa_setup() call when it has finished. In that case
- * we're done here.
+ * call to ipa_setup() when it has finished. In that case we're
+ * done here.
*/
if (modem_init)
- goto out_clock_put; /* Done; no error */
+ goto done;
/* Otherwise we need to load the firmware and have Trust Zone validate
* and install it. If that succeeds we can proceed with setup.
@@ -775,16 +780,15 @@ static int ipa_probe(struct platform_device *pdev)
ret = ipa_setup(ipa);
if (ret)
goto err_deconfig;
-
-out_clock_put:
- ipa_clock_put(ipa);
+done:
+ (void)ipa_clock_put(ipa);
return 0;
err_deconfig:
ipa_deconfig(ipa);
err_clock_put:
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
ipa_modem_exit(ipa);
err_table_exit:
ipa_table_exit(ipa);
@@ -810,7 +814,9 @@ static int ipa_remove(struct platform_device *pdev)
struct ipa_clock *clock = ipa->clock;
int ret;
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto out_clock_put;
if (ipa->setup_complete) {
ret = ipa_modem_stop(ipa);
@@ -826,8 +832,8 @@ static int ipa_remove(struct platform_device *pdev)
}
ipa_deconfig(ipa);
-
- ipa_clock_put(ipa);
+out_clock_put:
+ (void)ipa_clock_put(ipa);
ipa_modem_exit(ipa);
ipa_table_exit(ipa);
diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c
index ad4019e8016e..06e44afd2cf6 100644
--- a/drivers/net/ipa/ipa_modem.c
+++ b/drivers/net/ipa/ipa_modem.c
@@ -45,7 +45,9 @@ static int ipa_open(struct net_device *netdev)
struct ipa *ipa = priv->ipa;
int ret;
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto err_clock_put;
ret = ipa_endpoint_enable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
if (ret)
@@ -62,7 +64,7 @@ static int ipa_open(struct net_device *netdev)
err_disable_tx:
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
err_clock_put:
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
return ret;
}
@@ -78,7 +80,7 @@ static int ipa_stop(struct net_device *netdev)
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
return 0;
}
@@ -297,7 +299,9 @@ static void ipa_modem_crashed(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev;
int ret;
- ipa_clock_get(ipa);
+ ret = ipa_clock_get(ipa);
+ if (WARN_ON(ret < 0))
+ goto out_clock_put;
ipa_endpoint_modem_pause_all(ipa, true);
@@ -324,7 +328,8 @@ static void ipa_modem_crashed(struct ipa *ipa)
if (ret)
dev_err(dev, "error %d zeroing modem memory regions\n", ret);
- ipa_clock_put(ipa);
+out_clock_put:
+ (void)ipa_clock_put(ipa);
}
static int ipa_modem_notify(struct notifier_block *nb, unsigned long action,
diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
index 0d15438a79e2..f84d6523636e 100644
--- a/drivers/net/ipa/ipa_smp2p.c
+++ b/drivers/net/ipa/ipa_smp2p.c
@@ -150,24 +150,26 @@ static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p)
static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
{
struct ipa_smp2p *smp2p = dev_id;
+ int ret;
mutex_lock(&smp2p->mutex);
- if (!smp2p->disabled) {
- int ret;
-
- /* The clock needs to be active for setup */
- ipa_clock_get(smp2p->ipa);
+ if (smp2p->disabled)
+ goto out_mutex_unlock;
+ smp2p->disabled = true; /* If any others arrive, ignore them */
- ret = ipa_setup(smp2p->ipa);
- if (ret)
- dev_err(&smp2p->ipa->pdev->dev,
- "error %d from ipa_setup()\n", ret);
- smp2p->disabled = true;
+ /* The clock needs to be active for setup */
+ ret = ipa_clock_get(smp2p->ipa);
+ if (WARN_ON(ret < 0))
+ goto out_clock_put;
- ipa_clock_put(smp2p->ipa);
- }
+ /* An error here won't cause driver shutdown, so warn if one occurs */
+ ret = ipa_setup(smp2p->ipa);
+ WARN(ret != 0, "error %d from ipa_setup()\n", ret);
+out_clock_put:
+ (void)ipa_clock_put(smp2p->ipa);
+out_mutex_unlock:
mutex_unlock(&smp2p->mutex);
return IRQ_HANDLED;
@@ -206,7 +208,7 @@ static void ipa_smp2p_clock_release(struct ipa *ipa)
if (!ipa->smp2p->clock_on)
return;
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
ipa->smp2p->clock_on = false;
}
diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c
index f88ee02457d4..9c8818c39073 100644
--- a/drivers/net/ipa/ipa_uc.c
+++ b/drivers/net/ipa/ipa_uc.c
@@ -154,7 +154,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
case IPA_UC_RESPONSE_INIT_COMPLETED:
if (ipa->uc_clocked) {
ipa->uc_loaded = true;
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
ipa->uc_clocked = false;
} else {
dev_warn(dev, "unexpected init_completed response\n");
@@ -182,21 +182,25 @@ void ipa_uc_deconfig(struct ipa *ipa)
ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
if (ipa->uc_clocked)
- ipa_clock_put(ipa);
+ (void)ipa_clock_put(ipa);
}
/* Take a proxy clock reference for the microcontroller */
void ipa_uc_clock(struct ipa *ipa)
{
static bool already;
+ int ret;
if (already)
return;
already = true; /* Only do this on first boot */
/* This clock reference dropped in ipa_uc_response_hdlr() above */
- ipa_clock_get(ipa);
- ipa->uc_clocked = true;
+ ret = ipa_clock_get(ipa);
+ if (WARN(ret < 0, "error %d getting proxy clock\n", ret))
+ (void)ipa_clock_put(ipa);
+
+ ipa->uc_clocked = ret >= 0;
}
/* Send a command to the microcontroller */