summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-07-02 14:31:21 -0700
committerDavid S. Miller <davem@davemloft.net>2020-07-02 14:31:21 -0700
commitdd2b7a66b6a9c7bdf2c3d62e5d5b1a2abdddb052 (patch)
treea8d12cabe11d614075454fc5c4aa6f0e13176d28
parent4e1a69116869b26d244c2522bd1631967b62ffce (diff)
parentfb57c3ea98519f811b37f299e0ac4988a021fe2a (diff)
downloadlinux-stable-dd2b7a66b6a9c7bdf2c3d62e5d5b1a2abdddb052.tar.gz
linux-stable-dd2b7a66b6a9c7bdf2c3d62e5d5b1a2abdddb052.tar.bz2
linux-stable-dd2b7a66b6a9c7bdf2c3d62e5d5b1a2abdddb052.zip
Merge branch 'net-ipa-simplify-endpoint-programming'
Alex Elder says: ==================== net: ipa: simplify endpoint programming Add tests to functions so they don't update undefined endpoint registers, rather than requiring the caller to avoid calling them. Move the call to a workaround function required when suspending inside the function that puts an endpoint into suspend mode. This requires moving a few functions (which are otherwise unchanged). Then simplify ipa_endpoint_program() to call essentially all endpoint register update functions unconditionally. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ipa/ipa_endpoint.c190
1 files changed, 99 insertions, 91 deletions
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c
index a7b5a6407e8f..99115a2a29ae 100644
--- a/drivers/net/ipa/ipa_endpoint.c
+++ b/drivers/net/ipa/ipa_endpoint.c
@@ -318,41 +318,102 @@ ipa_endpoint_program_delay(struct ipa_endpoint *endpoint, bool enable)
{
/* assert(endpoint->toward_ipa); */
- (void)ipa_endpoint_init_ctrl(endpoint, enable);
+ /* Delay mode doesn't work properly for IPA v4.2 */
+ if (endpoint->ipa->version != IPA_VERSION_4_2)
+ (void)ipa_endpoint_init_ctrl(endpoint, enable);
}
-/* Returns previous suspend state (true means it was enabled) */
+static bool ipa_endpoint_aggr_active(struct ipa_endpoint *endpoint)
+{
+ u32 mask = BIT(endpoint->endpoint_id);
+ struct ipa *ipa = endpoint->ipa;
+ u32 offset;
+ u32 val;
+
+ /* assert(mask & ipa->available); */
+ offset = ipa_reg_state_aggr_active_offset(ipa->version);
+ val = ioread32(ipa->reg_virt + offset);
+
+ return !!(val & mask);
+}
+
+static void ipa_endpoint_force_close(struct ipa_endpoint *endpoint)
+{
+ u32 mask = BIT(endpoint->endpoint_id);
+ struct ipa *ipa = endpoint->ipa;
+
+ /* assert(mask & ipa->available); */
+ iowrite32(mask, ipa->reg_virt + IPA_REG_AGGR_FORCE_CLOSE_OFFSET);
+}
+
+/**
+ * ipa_endpoint_suspend_aggr() - Emulate suspend interrupt
+ * @endpoint_id: Endpoint on which to emulate a suspend
+ *
+ * Emulate suspend IPA interrupt to unsuspend an endpoint suspended
+ * with an open aggregation frame. This is to work around a hardware
+ * issue in IPA version 3.5.1 where the suspend interrupt will not be
+ * generated when it should be.
+ */
+static void ipa_endpoint_suspend_aggr(struct ipa_endpoint *endpoint)
+{
+ struct ipa *ipa = endpoint->ipa;
+
+ if (!endpoint->data->aggregation)
+ return;
+
+ /* Nothing to do if the endpoint doesn't have aggregation open */
+ if (!ipa_endpoint_aggr_active(endpoint))
+ return;
+
+ /* Force close aggregation */
+ ipa_endpoint_force_close(endpoint);
+
+ ipa_interrupt_simulate_suspend(ipa->interrupt);
+}
+
+/* Returns previous suspend state (true means suspend was enabled) */
static bool
ipa_endpoint_program_suspend(struct ipa_endpoint *endpoint, bool enable)
{
+ bool suspended;
+
+ if (endpoint->ipa->version != IPA_VERSION_3_5_1)
+ return enable; /* For IPA v4.0+, no change made */
+
/* assert(!endpoint->toward_ipa); */
- return ipa_endpoint_init_ctrl(endpoint, enable);
+ suspended = ipa_endpoint_init_ctrl(endpoint, enable);
+
+ /* A client suspended with an open aggregation frame will not
+ * generate a SUSPEND IPA interrupt. If enabling suspend, have
+ * ipa_endpoint_suspend_aggr() handle this.
+ */
+ if (enable && !suspended)
+ ipa_endpoint_suspend_aggr(endpoint);
+
+ return suspended;
}
/* Enable or disable delay or suspend mode on all modem endpoints */
void ipa_endpoint_modem_pause_all(struct ipa *ipa, bool enable)
{
- bool support_suspend;
u32 endpoint_id;
/* DELAY mode doesn't work correctly on IPA v4.2 */
if (ipa->version == IPA_VERSION_4_2)
return;
- /* Only IPA v3.5.1 supports SUSPEND mode on RX endpoints */
- support_suspend = ipa->version == IPA_VERSION_3_5_1;
-
for (endpoint_id = 0; endpoint_id < IPA_ENDPOINT_MAX; endpoint_id++) {
struct ipa_endpoint *endpoint = &ipa->endpoint[endpoint_id];
if (endpoint->ee_id != GSI_EE_MODEM)
continue;
- /* Set TX delay mode, or for IPA v3.5.1 RX suspend mode */
+ /* Set TX delay mode or RX suspend mode */
if (endpoint->toward_ipa)
ipa_endpoint_program_delay(endpoint, enable);
- else if (support_suspend)
+ else
(void)ipa_endpoint_program_suspend(endpoint, enable);
}
}
@@ -527,6 +588,9 @@ static void ipa_endpoint_init_hdr_metadata_mask(struct ipa_endpoint *endpoint)
u32 val = 0;
u32 offset;
+ if (endpoint->toward_ipa)
+ return; /* Register not valid for TX endpoints */
+
offset = IPA_REG_ENDP_INIT_HDR_METADATA_MASK_N_OFFSET(endpoint_id);
/* Note that HDR_ENDIANNESS indicates big endian header fields */
@@ -541,6 +605,9 @@ static void ipa_endpoint_init_mode(struct ipa_endpoint *endpoint)
u32 offset = IPA_REG_ENDP_INIT_MODE_N_OFFSET(endpoint->endpoint_id);
u32 val;
+ if (!endpoint->toward_ipa)
+ return; /* Register not valid for RX endpoints */
+
if (endpoint->data->dma_mode) {
enum ipa_endpoint_name name = endpoint->data->dma_endpoint;
u32 dma_endpoint_id;
@@ -699,6 +766,9 @@ static void ipa_endpoint_init_deaggr(struct ipa_endpoint *endpoint)
u32 offset = IPA_REG_ENDP_INIT_DEAGGR_N_OFFSET(endpoint->endpoint_id);
u32 val = 0;
+ if (!endpoint->toward_ipa)
+ return; /* Register not valid for RX endpoints */
+
/* DEAGGR_HDR_LEN is 0 */
/* PACKET_OFFSET_VALID is 0 */
/* PACKET_OFFSET_LOCATION is ignored (not valid) */
@@ -713,6 +783,9 @@ static void ipa_endpoint_init_seq(struct ipa_endpoint *endpoint)
u32 seq_type = endpoint->seq_type;
u32 val = 0;
+ if (!endpoint->toward_ipa)
+ return; /* Register not valid for RX endpoints */
+
/* Sequencer type is made up of four nibbles */
val |= u32_encode_bits(seq_type & 0xf, HPS_SEQ_TYPE_FMASK);
val |= u32_encode_bits((seq_type >> 4) & 0xf, DPS_SEQ_TYPE_FMASK);
@@ -1142,29 +1215,6 @@ void ipa_endpoint_default_route_clear(struct ipa *ipa)
ipa_endpoint_default_route_set(ipa, 0);
}
-static bool ipa_endpoint_aggr_active(struct ipa_endpoint *endpoint)
-{
- u32 mask = BIT(endpoint->endpoint_id);
- struct ipa *ipa = endpoint->ipa;
- u32 offset;
- u32 val;
-
- /* assert(mask & ipa->available); */
- offset = ipa_reg_state_aggr_active_offset(ipa->version);
- val = ioread32(ipa->reg_virt + offset);
-
- return !!(val & mask);
-}
-
-static void ipa_endpoint_force_close(struct ipa_endpoint *endpoint)
-{
- u32 mask = BIT(endpoint->endpoint_id);
- struct ipa *ipa = endpoint->ipa;
-
- /* assert(mask & ipa->available); */
- iowrite32(mask, ipa->reg_virt + IPA_REG_AGGR_FORCE_CLOSE_OFFSET);
-}
-
/**
* ipa_endpoint_reset_rx_aggr() - Reset RX endpoint with aggregation active
* @endpoint: Endpoint to be reset
@@ -1209,8 +1259,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
gsi_channel_reset(gsi, endpoint->channel_id, false);
/* Make sure the channel isn't suspended */
- if (endpoint->ipa->version == IPA_VERSION_3_5_1)
- suspended = ipa_endpoint_program_suspend(endpoint, false);
+ suspended = ipa_endpoint_program_suspend(endpoint, false);
/* Start channel and do a 1 byte read */
ret = gsi_channel_start(gsi, endpoint->channel_id);
@@ -1293,23 +1342,18 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint)
static void ipa_endpoint_program(struct ipa_endpoint *endpoint)
{
- if (endpoint->toward_ipa) {
- if (endpoint->ipa->version != IPA_VERSION_4_2)
- ipa_endpoint_program_delay(endpoint, false);
- ipa_endpoint_init_hdr_ext(endpoint);
- ipa_endpoint_init_aggr(endpoint);
- ipa_endpoint_init_deaggr(endpoint);
- ipa_endpoint_init_seq(endpoint);
- ipa_endpoint_init_mode(endpoint);
- } else {
- if (endpoint->ipa->version == IPA_VERSION_3_5_1)
- (void)ipa_endpoint_program_suspend(endpoint, false);
- ipa_endpoint_init_hdr_ext(endpoint);
- ipa_endpoint_init_aggr(endpoint);
- ipa_endpoint_init_hdr_metadata_mask(endpoint);
- }
+ if (endpoint->toward_ipa)
+ ipa_endpoint_program_delay(endpoint, false);
+ else
+ (void)ipa_endpoint_program_suspend(endpoint, false);
ipa_endpoint_init_cfg(endpoint);
ipa_endpoint_init_hdr(endpoint);
+ ipa_endpoint_init_hdr_ext(endpoint);
+ ipa_endpoint_init_hdr_metadata_mask(endpoint);
+ ipa_endpoint_init_mode(endpoint);
+ ipa_endpoint_init_aggr(endpoint);
+ ipa_endpoint_init_deaggr(endpoint);
+ ipa_endpoint_init_seq(endpoint);
ipa_endpoint_status(endpoint);
}
@@ -1365,34 +1409,6 @@ void ipa_endpoint_disable_one(struct ipa_endpoint *endpoint)
endpoint->endpoint_id);
}
-/**
- * ipa_endpoint_suspend_aggr() - Emulate suspend interrupt
- * @endpoint_id: Endpoint on which to emulate a suspend
- *
- * Emulate suspend IPA interrupt to unsuspend an endpoint suspended
- * with an open aggregation frame. This is to work around a hardware
- * issue in IPA version 3.5.1 where the suspend interrupt will not be
- * generated when it should be.
- */
-static void ipa_endpoint_suspend_aggr(struct ipa_endpoint *endpoint)
-{
- struct ipa *ipa = endpoint->ipa;
-
- /* assert(ipa->version == IPA_VERSION_3_5_1); */
-
- if (!endpoint->data->aggregation)
- return;
-
- /* Nothing to do if the endpoint doesn't have aggregation open */
- if (!ipa_endpoint_aggr_active(endpoint))
- return;
-
- /* Force close aggregation */
- ipa_endpoint_force_close(endpoint);
-
- ipa_interrupt_simulate_suspend(ipa->interrupt);
-}
-
void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint)
{
struct device *dev = &endpoint->ipa->pdev->dev;
@@ -1406,19 +1422,11 @@ void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint)
if (!endpoint->toward_ipa)
ipa_endpoint_replenish_disable(endpoint);
- /* IPA v3.5.1 doesn't use channel stop for suspend */
- stop_channel = endpoint->ipa->version != IPA_VERSION_3_5_1;
- if (!endpoint->toward_ipa && !stop_channel) {
- /* Due to a hardware bug, a client suspended with an open
- * aggregation frame will not generate a SUSPEND IPA
- * interrupt. We work around this by force-closing the
- * aggregation frame, then simulating the arrival of such
- * an interrupt.
- */
+ if (!endpoint->toward_ipa)
(void)ipa_endpoint_program_suspend(endpoint, true);
- ipa_endpoint_suspend_aggr(endpoint);
- }
+ /* IPA v3.5.1 doesn't use channel stop for suspend */
+ stop_channel = endpoint->ipa->version != IPA_VERSION_3_5_1;
ret = gsi_channel_suspend(gsi, endpoint->channel_id, stop_channel);
if (ret)
dev_err(dev, "error %d suspending channel %u\n", ret,
@@ -1435,11 +1443,11 @@ void ipa_endpoint_resume_one(struct ipa_endpoint *endpoint)
if (!(endpoint->ipa->enabled & BIT(endpoint->endpoint_id)))
return;
- /* IPA v3.5.1 doesn't use channel start for resume */
- start_channel = endpoint->ipa->version != IPA_VERSION_3_5_1;
- if (!endpoint->toward_ipa && !start_channel)
+ if (!endpoint->toward_ipa)
(void)ipa_endpoint_program_suspend(endpoint, false);
+ /* IPA v3.5.1 doesn't use channel start for resume */
+ start_channel = endpoint->ipa->version != IPA_VERSION_3_5_1;
ret = gsi_channel_resume(gsi, endpoint->channel_id, start_channel);
if (ret)
dev_err(dev, "error %d resuming channel %u\n", ret,