diff options
Diffstat (limited to 'drivers/net/ipa/ipa_endpoint.c')
| -rw-r--r-- | drivers/net/ipa/ipa_endpoint.c | 82 | 
1 files changed, 57 insertions, 25 deletions
| diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 7209ee3c3124..ccc99ad983eb 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2020 Linaro Ltd. + * Copyright (C) 2019-2021 Linaro Ltd.   */  #include <linux/types.h> @@ -88,6 +88,11 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,  	if (ipa_gsi_endpoint_data_empty(data))  		return true; +	/* IPA v4.5+ uses checksum offload, not yet supported by RMNet */ +	if (ipa->version >= IPA_VERSION_4_5) +		if (data->endpoint.config.checksum) +			return false; +  	if (!data->toward_ipa) {  		if (data->endpoint.filter_support) {  			dev_err(dev, "filtering not supported for " @@ -230,6 +235,17 @@ static bool ipa_endpoint_data_valid(struct ipa *ipa, u32 count,  static bool ipa_endpoint_data_valid(struct ipa *ipa, u32 count,  				    const struct ipa_gsi_endpoint_data *data)  { +	const struct ipa_gsi_endpoint_data *dp = data; +	enum ipa_endpoint_name name; + +	if (ipa->version < IPA_VERSION_4_5) +		return true; + +	/* IPA v4.5+ uses checksum offload, not yet supported by RMNet */ +	for (name = 0; name < count; name++, dp++) +		if (data->endpoint.config.checksum) +			return false; +  	return true;  } @@ -266,7 +282,7 @@ ipa_endpoint_init_ctrl(struct ipa_endpoint *endpoint, bool suspend_delay)  	 * if (endpoint->toward_ipa)  	 * 	assert(ipa->version != IPA_VERSION_4.2);  	 * else -	 * 	assert(ipa->version == IPA_VERSION_3_5_1); +	 *	assert(ipa->version < IPA_VERSION_4_0);  	 */  	mask = endpoint->toward_ipa ? ENDP_DELAY_FMASK : ENDP_SUSPEND_FMASK; @@ -347,7 +363,7 @@ ipa_endpoint_program_suspend(struct ipa_endpoint *endpoint, bool enable)  {  	bool suspended; -	if (endpoint->ipa->version != IPA_VERSION_3_5_1) +	if (endpoint->ipa->version >= IPA_VERSION_4_0)  		return enable;	/* For IPA v4.0+, no change made */  	/* assert(!endpoint->toward_ipa); */ @@ -397,7 +413,7 @@ int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa)  	/* We need one command per modem TX endpoint.  We can get an upper  	 * bound on that by assuming all initialized endpoints are modem->IPA.  	 * That won't happen, and we could be more precise, but this is fine -	 * for now.  We need to end the transaction with a "tag process." +	 * for now.  End the transaction with commands to clear the pipeline.  	 */  	count = hweight32(initialized) + ipa_cmd_pipeline_clear_count();  	trans = ipa_cmd_trans_alloc(ipa, count); @@ -468,6 +484,20 @@ static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint)  	iowrite32(val, endpoint->ipa->reg_virt + offset);  } +static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint) +{ +	u32 offset; +	u32 val; + +	if (!endpoint->toward_ipa) +		return; + +	offset = IPA_REG_ENDP_INIT_NAT_N_OFFSET(endpoint->endpoint_id); +	val = u32_encode_bits(IPA_NAT_BYPASS, NAT_EN_FMASK); + +	iowrite32(val, endpoint->ipa->reg_virt + offset); +} +  /**   * ipa_endpoint_init_hdr() - Initialize HDR endpoint configuration register   * @endpoint:	Endpoint pointer @@ -515,7 +545,7 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)  			/* Where IPA will write the length */  			offset = offsetof(struct rmnet_map_header, pkt_len);  			/* Upper bits are stored in HDR_EXT with IPA v4.5 */ -			if (version == IPA_VERSION_4_5) +			if (version >= IPA_VERSION_4_5)  				offset &= field_mask(HDR_OFST_PKT_SIZE_FMASK);  			val |= HDR_OFST_PKT_SIZE_VALID_FMASK; @@ -562,7 +592,7 @@ static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint)  	/* IPA v4.5 adds some most-significant bits to a few fields,  	 * two of which are defined in the HDR (not HDR_EXT) register.  	 */ -	if (ipa->version == IPA_VERSION_4_5) { +	if (ipa->version >= IPA_VERSION_4_5) {  		/* HDR_TOTAL_LEN_OR_PAD_OFFSET is 0, so MSB is 0 */  		if (endpoint->data->qmap && !endpoint->toward_ipa) {  			u32 offset; @@ -776,7 +806,7 @@ static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds)  	if (!microseconds)  		return 0;	/* Nothing to compute if timer period is 0 */ -	if (ipa->version == IPA_VERSION_4_5) +	if (ipa->version >= IPA_VERSION_4_5)  		return hol_block_timer_qtime_val(ipa, microseconds);  	/* Use 64 bit arithmetic to avoid overflow... */ @@ -795,7 +825,7 @@ static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds)  	 * The best precision is achieved when the base value is as  	 * large as possible.  Find the highest set bit in the tick  	 * count, and extract the number of bits in the base field -	 * such that that high bit is included. +	 * such that high bit is included.  	 */  	high = fls(ticks);		/* 1..32 */  	width = HWEIGHT32(BASE_VALUE_FMASK); @@ -884,18 +914,17 @@ static void ipa_endpoint_init_rsrc_grp(struct ipa_endpoint *endpoint)  static void ipa_endpoint_init_seq(struct ipa_endpoint *endpoint)  {  	u32 offset = IPA_REG_ENDP_INIT_SEQ_N_OFFSET(endpoint->endpoint_id); -	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); -	/* The second two apply to replicated packets */ -	val |= u32_encode_bits((seq_type >> 8) & 0xf, HPS_REP_SEQ_TYPE_FMASK); -	val |= u32_encode_bits((seq_type >> 12) & 0xf, DPS_REP_SEQ_TYPE_FMASK); +	/* Low-order byte configures primary packet processing */ +	val |= u32_encode_bits(endpoint->data->tx.seq_type, SEQ_TYPE_FMASK); + +	/* Second byte configures replicated packet processing */ +	val |= u32_encode_bits(endpoint->data->tx.seq_rep_type, +			       SEQ_REP_TYPE_FMASK);  	iowrite32(val, endpoint->ipa->reg_virt + offset);  } @@ -1435,7 +1464,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)  	if (ret)  		goto out_suspend_again; -	/* Finally, reset and reconfigure the channel again (re-enabling the +	/* Finally, reset and reconfigure the channel again (re-enabling  	 * the doorbell engine if appropriate).  Sleep for 1 millisecond to  	 * complete the channel reset sequence.  Finish by suspending the  	 * channel again (if necessary). @@ -1469,8 +1498,7 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint)  	 * is active, we need to handle things specially to recover.  	 * All other cases just need to reset the underlying GSI channel.  	 */ -	special = ipa->version == IPA_VERSION_3_5_1 && -			!endpoint->toward_ipa && +	special = ipa->version < IPA_VERSION_4_0 && !endpoint->toward_ipa &&  			endpoint->data->aggregation;  	if (special && ipa_endpoint_aggr_active(endpoint))  		ret = ipa_endpoint_reset_rx_aggr(endpoint); @@ -1490,6 +1518,7 @@ static void ipa_endpoint_program(struct ipa_endpoint *endpoint)  	else  		(void)ipa_endpoint_program_suspend(endpoint, false);  	ipa_endpoint_init_cfg(endpoint); +	ipa_endpoint_init_nat(endpoint);  	ipa_endpoint_init_hdr(endpoint);  	ipa_endpoint_init_hdr_ext(endpoint);  	ipa_endpoint_init_hdr_metadata_mask(endpoint); @@ -1568,8 +1597,10 @@ void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint)  		(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; +	/* Starting with IPA v4.0, endpoints are suspended by stopping the +	 * underlying GSI channel rather than using endpoint suspend mode. +	 */ +	stop_channel = endpoint->ipa->version >= IPA_VERSION_4_0;  	ret = gsi_channel_suspend(gsi, endpoint->channel_id, stop_channel);  	if (ret)  		dev_err(dev, "error %d suspending channel %u\n", ret, @@ -1589,8 +1620,10 @@ void ipa_endpoint_resume_one(struct ipa_endpoint *endpoint)  	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; +	/* Starting with IPA v4.0, the underlying GSI channel must be +	 * restarted for resume. +	 */ +	start_channel = endpoint->ipa->version >= IPA_VERSION_4_0;  	ret = gsi_channel_resume(gsi, endpoint->channel_id, start_channel);  	if (ret)  		dev_err(dev, "error %d resuming channel %u\n", ret, @@ -1738,7 +1771,7 @@ int ipa_endpoint_config(struct ipa *ipa)  		/* Make sure it's pointing in the right direction */  		endpoint = &ipa->endpoint[endpoint_id]; -		if ((endpoint_id < rx_base) != !!endpoint->toward_ipa) { +		if ((endpoint_id < rx_base) != endpoint->toward_ipa) {  			dev_err(dev, "endpoint id %u wrong direction\n",  				endpoint_id);  			ret = -EINVAL; @@ -1766,7 +1799,6 @@ static void ipa_endpoint_init_one(struct ipa *ipa, enum ipa_endpoint_name name,  	endpoint->ipa = ipa;  	endpoint->ee_id = data->ee_id; -	endpoint->seq_type = data->endpoint.seq_type;  	endpoint->channel_id = data->channel_id;  	endpoint->endpoint_id = data->endpoint_id;  	endpoint->toward_ipa = data->toward_ipa; @@ -1775,7 +1807,7 @@ static void ipa_endpoint_init_one(struct ipa *ipa, enum ipa_endpoint_name name,  	ipa->initialized |= BIT(endpoint->endpoint_id);  } -void ipa_endpoint_exit_one(struct ipa_endpoint *endpoint) +static void ipa_endpoint_exit_one(struct ipa_endpoint *endpoint)  {  	endpoint->ipa->initialized &= ~BIT(endpoint->endpoint_id); | 
