Skip to content

Commit

Permalink
Merge branch 'net-ipa-simplify-endpoint-programming'
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Jul 2, 2020
2 parents 4e1a691 + fb57c3e commit dd2b7a6
Showing 1 changed file with 99 additions and 91 deletions.
190 changes: 99 additions & 91 deletions drivers/net/ipa/ipa_endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand Down Expand Up @@ -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) */
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit dd2b7a6

Please sign in to comment.