mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-12-16 20:02:45 +00:00
net: ipa: support hard aggregation limits
Add a new flag for AP receive endpoints that indicates whether a "hard limit" is used as a criterion for closing aggregation. Add comments explaining the difference between "hard" and "soft" aggregation limits. Pass a flag to ipa_aggr_size_kb() so it computes the proper aggregation size value whether using hard or soft limits. Move that function earlier in "ipa_endpoint.c" so it can be used without a forward-reference. Update ipa_endpoint_data_valid_one() so it validates endpoints whose data indicate a hard aggregation limit is used, and so it reports set aggregation flags for endpoints without aggregation enabled. Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
153213f055
commit
3cebb7c2ed
@ -81,6 +81,24 @@ static u32 aggr_byte_limit_max(enum ipa_version version)
|
|||||||
return field_max(aggr_byte_limit_fmask(false));
|
return field_max(aggr_byte_limit_fmask(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the aggregation size value to use for a given buffer size */
|
||||||
|
static u32 ipa_aggr_size_kb(u32 rx_buffer_size, bool aggr_hard_limit)
|
||||||
|
{
|
||||||
|
/* A hard aggregation limit will not be crossed; aggregation closes
|
||||||
|
* if saving incoming data would cross the hard byte limit boundary.
|
||||||
|
*
|
||||||
|
* With a soft limit, aggregation closes *after* the size boundary
|
||||||
|
* has been crossed. In that case the limit must leave enough space
|
||||||
|
* after that limit to receive a full MTU of data plus overhead.
|
||||||
|
*/
|
||||||
|
if (!aggr_hard_limit)
|
||||||
|
rx_buffer_size -= IPA_MTU + IPA_RX_BUFFER_OVERHEAD;
|
||||||
|
|
||||||
|
/* The byte limit is encoded as a number of kilobytes */
|
||||||
|
|
||||||
|
return rx_buffer_size / SZ_1K;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
|
static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
|
||||||
const struct ipa_gsi_endpoint_data *all_data,
|
const struct ipa_gsi_endpoint_data *all_data,
|
||||||
const struct ipa_gsi_endpoint_data *data)
|
const struct ipa_gsi_endpoint_data *data)
|
||||||
@ -93,7 +111,9 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!data->toward_ipa) {
|
if (!data->toward_ipa) {
|
||||||
|
const struct ipa_endpoint_rx *rx_config;
|
||||||
u32 buffer_size;
|
u32 buffer_size;
|
||||||
|
u32 aggr_size;
|
||||||
u32 limit;
|
u32 limit;
|
||||||
|
|
||||||
if (data->endpoint.filter_support) {
|
if (data->endpoint.filter_support) {
|
||||||
@ -107,8 +127,10 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
|
|||||||
if (data->ee_id != GSI_EE_AP)
|
if (data->ee_id != GSI_EE_AP)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
buffer_size = data->endpoint.config.rx.buffer_size;
|
rx_config = &data->endpoint.config.rx;
|
||||||
|
|
||||||
/* The buffer size must hold an MTU plus overhead */
|
/* The buffer size must hold an MTU plus overhead */
|
||||||
|
buffer_size = rx_config->buffer_size;
|
||||||
limit = IPA_MTU + IPA_RX_BUFFER_OVERHEAD;
|
limit = IPA_MTU + IPA_RX_BUFFER_OVERHEAD;
|
||||||
if (buffer_size < limit) {
|
if (buffer_size < limit) {
|
||||||
dev_err(dev, "RX buffer size too small for RX endpoint %u (%u < %u)\n",
|
dev_err(dev, "RX buffer size too small for RX endpoint %u (%u < %u)\n",
|
||||||
@ -116,28 +138,40 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For an endpoint supporting receive aggregation, the
|
if (!data->endpoint.config.aggregation) {
|
||||||
* aggregation byte limit defines the point at which an
|
bool result = true;
|
||||||
* aggregation window will close. It is programmed into the
|
|
||||||
* IPA hardware as a number of KB. We don't use "hard byte
|
/* No aggregation; check for bogus aggregation data */
|
||||||
* limit" aggregation, so we need to supply enough space in
|
if (rx_config->aggr_hard_limit) {
|
||||||
* a receive buffer to hold a complete MTU plus normal skb
|
dev_err(dev, "hard limit with no aggregation for RX endpoint %u\n",
|
||||||
* overhead *after* that aggregation byte limit has been
|
data->endpoint_id);
|
||||||
* crossed.
|
result = false;
|
||||||
*
|
}
|
||||||
* This check just ensures the receive buffer size doesn't
|
|
||||||
* exceed what's representable in the aggregation limit field.
|
if (rx_config->aggr_close_eof) {
|
||||||
|
dev_err(dev, "close EOF with no aggregation for RX endpoint %u\n",
|
||||||
|
data->endpoint_id);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; /* Nothing more to check */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For an endpoint supporting receive aggregation, the byte
|
||||||
|
* limit defines the point at which aggregation closes. This
|
||||||
|
* check ensures the receive buffer size doesn't result in a
|
||||||
|
* limit that exceeds what's representable in the aggregation
|
||||||
|
* byte limit field.
|
||||||
*/
|
*/
|
||||||
if (data->endpoint.config.aggregation) {
|
aggr_size = ipa_aggr_size_kb(buffer_size - NET_SKB_PAD,
|
||||||
limit += SZ_1K * aggr_byte_limit_max(ipa->version);
|
rx_config->aggr_hard_limit);
|
||||||
if (buffer_size - NET_SKB_PAD > limit) {
|
limit = aggr_byte_limit_max(ipa->version);
|
||||||
dev_err(dev, "RX buffer size too large for aggregated RX endpoint %u (%u > %u)\n",
|
if (aggr_size > limit) {
|
||||||
data->endpoint_id,
|
dev_err(dev, "aggregated size too large for RX endpoint %u (%u KB > %u KB)\n",
|
||||||
buffer_size - NET_SKB_PAD, limit);
|
data->endpoint_id, aggr_size, limit);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true; /* Nothing more to check for RX */
|
return true; /* Nothing more to check for RX */
|
||||||
}
|
}
|
||||||
@ -670,18 +704,6 @@ static void ipa_endpoint_init_mode(struct ipa_endpoint *endpoint)
|
|||||||
iowrite32(val, endpoint->ipa->reg_virt + offset);
|
iowrite32(val, endpoint->ipa->reg_virt + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the aggregation size value to use for a given buffer size */
|
|
||||||
static u32 ipa_aggr_size_kb(u32 rx_buffer_size)
|
|
||||||
{
|
|
||||||
/* We don't use "hard byte limit" aggregation, so we define the
|
|
||||||
* aggregation limit such that our buffer has enough space *after*
|
|
||||||
* that limit to receive a full MTU of data, plus overhead.
|
|
||||||
*/
|
|
||||||
rx_buffer_size -= IPA_MTU + IPA_RX_BUFFER_OVERHEAD;
|
|
||||||
|
|
||||||
return rx_buffer_size / SZ_1K;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Encoded values for AGGR endpoint register fields */
|
/* Encoded values for AGGR endpoint register fields */
|
||||||
static u32 aggr_byte_limit_encoded(enum ipa_version version, u32 limit)
|
static u32 aggr_byte_limit_encoded(enum ipa_version version, u32 limit)
|
||||||
{
|
{
|
||||||
@ -753,7 +775,8 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
|
|||||||
val |= u32_encode_bits(IPA_GENERIC, AGGR_TYPE_FMASK);
|
val |= u32_encode_bits(IPA_GENERIC, AGGR_TYPE_FMASK);
|
||||||
|
|
||||||
buffer_size = rx_config->buffer_size;
|
buffer_size = rx_config->buffer_size;
|
||||||
limit = ipa_aggr_size_kb(buffer_size - NET_SKB_PAD);
|
limit = ipa_aggr_size_kb(buffer_size - NET_SKB_PAD,
|
||||||
|
rx_config->aggr_hard_limit);
|
||||||
val |= aggr_byte_limit_encoded(version, limit);
|
val |= aggr_byte_limit_encoded(version, limit);
|
||||||
|
|
||||||
limit = IPA_AGGR_TIME_LIMIT;
|
limit = IPA_AGGR_TIME_LIMIT;
|
||||||
|
|||||||
@ -59,21 +59,32 @@ struct ipa_endpoint_tx {
|
|||||||
* struct ipa_endpoint_rx - Endpoint configuration for RX endpoints
|
* struct ipa_endpoint_rx - Endpoint configuration for RX endpoints
|
||||||
* @buffer_size: requested receive buffer size (bytes)
|
* @buffer_size: requested receive buffer size (bytes)
|
||||||
* @pad_align: power-of-2 boundary to which packet payload is aligned
|
* @pad_align: power-of-2 boundary to which packet payload is aligned
|
||||||
|
* @aggr_hard_limit: whether aggregation closes before or after boundary
|
||||||
* @aggr_close_eof: whether aggregation closes on end-of-frame
|
* @aggr_close_eof: whether aggregation closes on end-of-frame
|
||||||
* @holb_drop: whether to drop packets to avoid head-of-line blocking
|
* @holb_drop: whether to drop packets to avoid head-of-line blocking
|
||||||
*
|
*
|
||||||
|
* The actual size of the receive buffer is rounded up if necessary
|
||||||
|
* to be a power-of-2 number of pages.
|
||||||
|
*
|
||||||
* With each packet it transfers, the IPA hardware can perform certain
|
* With each packet it transfers, the IPA hardware can perform certain
|
||||||
* transformations of its packet data. One of these is adding pad bytes
|
* transformations of its packet data. One of these is adding pad bytes
|
||||||
* to the end of the packet data so the result ends on a power-of-2 boundary.
|
* to the end of the packet data so the result ends on a power-of-2 boundary.
|
||||||
*
|
*
|
||||||
* It is also able to aggregate multiple packets into a single receive buffer.
|
* It is also able to aggregate multiple packets into a single receive buffer.
|
||||||
* Aggregation is "open" while a buffer is being filled, and "closes" when
|
* Aggregation is "open" while a buffer is being filled, and "closes" when
|
||||||
* certain criteria are met. One of those criteria is the sender indicating
|
* certain criteria are met.
|
||||||
* a "frame" consisting of several transfers has ended.
|
*
|
||||||
|
* Insufficient space available in the receive buffer can close aggregation.
|
||||||
|
* The aggregation byte limit defines the point (in units of 1024 bytes) in
|
||||||
|
* the buffer where aggregation closes. With a "soft" aggregation limit,
|
||||||
|
* aggregation closes when a packet written to the buffer *crosses* that
|
||||||
|
* aggregation limit. With a "hard" aggregation limit, aggregation will
|
||||||
|
* close *before* writing a packet that would cross that boundary.
|
||||||
*/
|
*/
|
||||||
struct ipa_endpoint_rx {
|
struct ipa_endpoint_rx {
|
||||||
u32 buffer_size;
|
u32 buffer_size;
|
||||||
u32 pad_align;
|
u32 pad_align;
|
||||||
|
bool aggr_hard_limit;
|
||||||
bool aggr_close_eof;
|
bool aggr_close_eof;
|
||||||
bool holb_drop;
|
bool holb_drop;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user