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>
This commit is contained in:
commit
dd2b7a66b6
1 changed files with 99 additions and 91 deletions
|
|
@ -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);
|
||||
|
||||
if (!endpoint->toward_ipa)
|
||||
(void)ipa_endpoint_program_suspend(endpoint, true);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
(void)ipa_endpoint_program_suspend(endpoint, true);
|
||||
ipa_endpoint_suspend_aggr(endpoint);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue