summaryrefslogtreecommitdiff
path: root/drivers/net/ipa/ipa_endpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ipa/ipa_endpoint.c')
-rw-r--r--drivers/net/ipa/ipa_endpoint.c258
1 files changed, 192 insertions, 66 deletions
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c
index b40b711cf4bd..9f4be9812a1f 100644
--- a/drivers/net/ipa/ipa_endpoint.c
+++ b/drivers/net/ipa/ipa_endpoint.c
@@ -37,7 +37,7 @@
#define IPA_ENDPOINT_QMAP_METADATA_MASK 0x000000ff /* host byte order */
#define IPA_ENDPOINT_RESET_AGGR_RETRY_MAX 3
-#define IPA_AGGR_TIME_LIMIT_DEFAULT 500 /* microseconds */
+#define IPA_AGGR_TIME_LIMIT 500 /* microseconds */
/** enum ipa_status_opcode - status element opcode hardware values */
enum ipa_status_opcode {
@@ -74,31 +74,6 @@ struct ipa_status {
#ifdef IPA_VALIDATE
-static void ipa_endpoint_validate_build(void)
-{
- /* The aggregation byte limit defines the point at which an
- * aggregation window will close. It is programmed into the
- * IPA hardware as a number of KB. We don't use "hard byte
- * limit" aggregation, which means that we need to supply
- * enough space in a receive buffer to hold a complete MTU
- * plus normal skb overhead *after* that aggregation byte
- * limit has been crossed.
- *
- * This check just ensures we don't define a receive buffer
- * size that would exceed what we can represent in the field
- * that is used to program its size.
- */
- BUILD_BUG_ON(IPA_RX_BUFFER_SIZE >
- field_max(AGGR_BYTE_LIMIT_FMASK) * SZ_1K +
- IPA_MTU + IPA_RX_BUFFER_OVERHEAD);
-
- /* I honestly don't know where this requirement comes from. But
- * it holds, and if we someday need to loosen the constraint we
- * can try to track it down.
- */
- BUILD_BUG_ON(sizeof(struct ipa_status) % 4);
-}
-
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 *data)
@@ -180,14 +155,24 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
return true;
}
+static u32 aggr_byte_limit_max(enum ipa_version version)
+{
+ if (version < IPA_VERSION_4_5)
+ return field_max(aggr_byte_limit_fmask(true));
+
+ return field_max(aggr_byte_limit_fmask(false));
+}
+
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;
struct device *dev = &ipa->pdev->dev;
enum ipa_endpoint_name name;
+ u32 limit;
- ipa_endpoint_validate_build();
+ /* Not sure where this constraint come from... */
+ BUILD_BUG_ON(sizeof(struct ipa_status) % 4);
if (count > IPA_ENDPOINT_COUNT) {
dev_err(dev, "too many endpoints specified (%u > %u)\n",
@@ -195,6 +180,26 @@ static bool ipa_endpoint_data_valid(struct ipa *ipa, u32 count,
return false;
}
+ /* The aggregation byte limit defines the point at which an
+ * aggregation window will close. It is programmed into the
+ * IPA hardware as a number of KB. We don't use "hard byte
+ * limit" aggregation, which means that we need to supply
+ * enough space in a receive buffer to hold a complete MTU
+ * plus normal skb overhead *after* that aggregation byte
+ * limit has been crossed.
+ *
+ * This check ensures we don't define a receive buffer size
+ * that would exceed what we can represent in the field that
+ * is used to program its size.
+ */
+ limit = aggr_byte_limit_max(ipa->version) * SZ_1K;
+ limit += IPA_MTU + IPA_RX_BUFFER_OVERHEAD;
+ if (limit < IPA_RX_BUFFER_SIZE) {
+ dev_err(dev, "buffer size too big for aggregation (%u > %u)\n",
+ IPA_RX_BUFFER_SIZE, limit);
+ return false;
+ }
+
/* Make sure needed endpoints have defined data */
if (ipa_gsi_endpoint_data_empty(&data[IPA_ENDPOINT_AP_COMMAND_TX])) {
dev_err(dev, "command TX endpoint not defined\n");
@@ -485,28 +490,34 @@ static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint)
static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
{
u32 offset = IPA_REG_ENDP_INIT_HDR_N_OFFSET(endpoint->endpoint_id);
+ struct ipa *ipa = endpoint->ipa;
u32 val = 0;
if (endpoint->data->qmap) {
size_t header_size = sizeof(struct rmnet_map_header);
+ enum ipa_version version = ipa->version;
/* We might supply a checksum header after the QMAP header */
if (endpoint->toward_ipa && endpoint->data->checksum)
header_size += sizeof(struct rmnet_map_ul_csum_header);
- val |= u32_encode_bits(header_size, HDR_LEN_FMASK);
+ val |= ipa_header_size_encoded(version, header_size);
/* Define how to fill fields in a received QMAP header */
if (!endpoint->toward_ipa) {
- u32 off; /* Field offset within header */
+ u32 offset; /* Field offset within header */
/* Where IPA will write the metadata value */
- off = offsetof(struct rmnet_map_header, mux_id);
- val |= u32_encode_bits(off, HDR_OFST_METADATA_FMASK);
+ offset = offsetof(struct rmnet_map_header, mux_id);
+ val |= ipa_metadata_offset_encoded(version, offset);
/* Where IPA will write the length */
- off = offsetof(struct rmnet_map_header, pkt_len);
+ 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)
+ offset &= field_mask(HDR_OFST_PKT_SIZE_FMASK);
+
val |= HDR_OFST_PKT_SIZE_VALID_FMASK;
- val |= u32_encode_bits(off, HDR_OFST_PKT_SIZE_FMASK);
+ val |= u32_encode_bits(offset, HDR_OFST_PKT_SIZE_FMASK);
}
/* For QMAP TX, metadata offset is 0 (modem assumes this) */
val |= HDR_OFST_METADATA_VALID_FMASK;
@@ -514,16 +525,17 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
/* HDR_ADDITIONAL_CONST_LEN is 0; (RX only) */
/* HDR_A5_MUX is 0 */
/* HDR_LEN_INC_DEAGG_HDR is 0 */
- /* HDR_METADATA_REG_VALID is 0 (TX only) */
+ /* HDR_METADATA_REG_VALID is 0 (TX only, version < v4.5) */
}
- iowrite32(val, endpoint->ipa->reg_virt + offset);
+ iowrite32(val, ipa->reg_virt + offset);
}
static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint)
{
u32 offset = IPA_REG_ENDP_INIT_HDR_EXT_N_OFFSET(endpoint->endpoint_id);
u32 pad_align = endpoint->data->rx.pad_align;
+ struct ipa *ipa = endpoint->ipa;
u32 val = 0;
val |= HDR_ENDIANNESS_FMASK; /* big endian */
@@ -545,10 +557,24 @@ static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint)
if (!endpoint->toward_ipa)
val |= u32_encode_bits(pad_align, HDR_PAD_TO_ALIGNMENT_FMASK);
- iowrite32(val, endpoint->ipa->reg_virt + offset);
+ /* 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) {
+ /* HDR_TOTAL_LEN_OR_PAD_OFFSET is 0, so MSB is 0 */
+ if (endpoint->data->qmap && !endpoint->toward_ipa) {
+ u32 offset;
+
+ offset = offsetof(struct rmnet_map_header, pkt_len);
+ offset >>= hweight32(HDR_OFST_PKT_SIZE_FMASK);
+ val |= u32_encode_bits(offset,
+ HDR_OFST_PKT_SIZE_MSB_FMASK);
+ /* HDR_ADDITIONAL_CONST_LEN is 0 so MSB is 0 */
+ }
+ }
+ iowrite32(val, ipa->reg_virt + offset);
}
-
static void ipa_endpoint_init_hdr_metadata_mask(struct ipa_endpoint *endpoint)
{
u32 endpoint_id = endpoint->endpoint_id;
@@ -603,29 +629,84 @@ static u32 ipa_aggr_size_kb(u32 rx_buffer_size)
return rx_buffer_size / SZ_1K;
}
+/* Encoded values for AGGR endpoint register fields */
+static u32 aggr_byte_limit_encoded(enum ipa_version version, u32 limit)
+{
+ if (version < IPA_VERSION_4_5)
+ return u32_encode_bits(limit, aggr_byte_limit_fmask(true));
+
+ return u32_encode_bits(limit, aggr_byte_limit_fmask(false));
+}
+
+/* Encode the aggregation timer limit (microseconds) based on IPA version */
+static u32 aggr_time_limit_encoded(enum ipa_version version, u32 limit)
+{
+ u32 gran_sel;
+ u32 fmask;
+ u32 val;
+
+ if (version < IPA_VERSION_4_5) {
+ /* We set aggregation granularity in ipa_hardware_config() */
+ limit = DIV_ROUND_CLOSEST(limit, IPA_AGGR_GRANULARITY);
+
+ return u32_encode_bits(limit, aggr_time_limit_fmask(true));
+ }
+
+ /* IPA v4.5 expresses the time limit using Qtime. The AP has
+ * pulse generators 0 and 1 available, which were configured
+ * in ipa_qtime_config() to have granularity 100 usec and
+ * 1 msec, respectively. Use pulse generator 0 if possible,
+ * otherwise fall back to pulse generator 1.
+ */
+ fmask = aggr_time_limit_fmask(false);
+ val = DIV_ROUND_CLOSEST(limit, 100);
+ if (val > field_max(fmask)) {
+ /* Have to use pulse generator 1 (millisecond granularity) */
+ gran_sel = AGGR_GRAN_SEL_FMASK;
+ val = DIV_ROUND_CLOSEST(limit, 1000);
+ } else {
+ /* We can use pulse generator 0 (100 usec granularity) */
+ gran_sel = 0;
+ }
+
+ return gran_sel | u32_encode_bits(val, fmask);
+}
+
+static u32 aggr_sw_eof_active_encoded(enum ipa_version version, bool enabled)
+{
+ u32 val = enabled ? 1 : 0;
+
+ if (version < IPA_VERSION_4_5)
+ return u32_encode_bits(val, aggr_sw_eof_active_fmask(true));
+
+ return u32_encode_bits(val, aggr_sw_eof_active_fmask(false));
+}
+
static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
{
u32 offset = IPA_REG_ENDP_INIT_AGGR_N_OFFSET(endpoint->endpoint_id);
+ enum ipa_version version = endpoint->ipa->version;
u32 val = 0;
if (endpoint->data->aggregation) {
if (!endpoint->toward_ipa) {
+ bool close_eof;
u32 limit;
val |= u32_encode_bits(IPA_ENABLE_AGGR, AGGR_EN_FMASK);
val |= u32_encode_bits(IPA_GENERIC, AGGR_TYPE_FMASK);
limit = ipa_aggr_size_kb(IPA_RX_BUFFER_SIZE);
- val |= u32_encode_bits(limit, AGGR_BYTE_LIMIT_FMASK);
+ val |= aggr_byte_limit_encoded(version, limit);
- limit = IPA_AGGR_TIME_LIMIT_DEFAULT;
- limit = DIV_ROUND_CLOSEST(limit, IPA_AGGR_GRANULARITY);
- val |= u32_encode_bits(limit, AGGR_TIME_LIMIT_FMASK);
+ limit = IPA_AGGR_TIME_LIMIT;
+ val |= aggr_time_limit_encoded(version, limit);
/* AGGR_PKT_LIMIT is 0 (unlimited) */
- if (endpoint->data->rx.aggr_close_eof)
- val |= AGGR_SW_EOF_ACTIVE_FMASK;
+ close_eof = endpoint->data->rx.aggr_close_eof;
+ val |= aggr_sw_eof_active_encoded(version, close_eof);
+
/* AGGR_HARD_BYTE_LIMIT_ENABLE is 0 */
} else {
val |= u32_encode_bits(IPA_ENABLE_DEAGGR,
@@ -634,6 +715,7 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
/* other fields ignored */
}
/* AGGR_FORCE_CLOSE is 0 */
+ /* AGGR_GRAN_SEL is 0 for IPA v4.5 */
} else {
val |= u32_encode_bits(IPA_BYPASS_AGGR, AGGR_EN_FMASK);
/* other fields ignored */
@@ -642,12 +724,45 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
iowrite32(val, endpoint->ipa->reg_virt + offset);
}
-/* The head-of-line blocking timer is defined as a tick count, where each
- * tick represents 128 cycles of the IPA core clock. Return the value
- * that should be written to that register that represents the timeout
- * period provided.
+/* Return the Qtime-based head-of-line blocking timer value that
+ * represents the given number of microseconds. The result
+ * includes both the timer value and the selected timer granularity.
*/
-static u32 ipa_reg_init_hol_block_timer_val(struct ipa *ipa, u32 microseconds)
+static u32 hol_block_timer_qtime_val(struct ipa *ipa, u32 microseconds)
+{
+ u32 gran_sel;
+ u32 val;
+
+ /* IPA v4.5 expresses time limits using Qtime. The AP has
+ * pulse generators 0 and 1 available, which were configured
+ * in ipa_qtime_config() to have granularity 100 usec and
+ * 1 msec, respectively. Use pulse generator 0 if possible,
+ * otherwise fall back to pulse generator 1.
+ */
+ val = DIV_ROUND_CLOSEST(microseconds, 100);
+ if (val > field_max(TIME_LIMIT_FMASK)) {
+ /* Have to use pulse generator 1 (millisecond granularity) */
+ gran_sel = GRAN_SEL_FMASK;
+ val = DIV_ROUND_CLOSEST(microseconds, 1000);
+ } else {
+ /* We can use pulse generator 0 (100 usec granularity) */
+ gran_sel = 0;
+ }
+
+ return gran_sel | u32_encode_bits(val, TIME_LIMIT_FMASK);
+}
+
+/* The head-of-line blocking timer is defined as a tick count. For
+ * IPA version 4.5 the tick count is based on the Qtimer, which is
+ * derived from the 19.2 MHz SoC XO clock. For older IPA versions
+ * each tick represents 128 cycles of the IPA core clock.
+ *
+ * Return the encoded value that should be written to that register
+ * that represents the timeout period provided. For IPA v4.2 this
+ * encodes a base and scale value, while for earlier versions the
+ * value is a simple tick count.
+ */
+static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds)
{
u32 width;
u32 scale;
@@ -659,14 +774,17 @@ static u32 ipa_reg_init_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)
+ return hol_block_timer_qtime_val(ipa, microseconds);
+
/* Use 64 bit arithmetic to avoid overflow... */
rate = ipa_clock_rate(ipa);
ticks = DIV_ROUND_CLOSEST(microseconds * rate, 128 * USEC_PER_SEC);
/* ...but we still need to fit into a 32-bit register */
WARN_ON(ticks > U32_MAX);
- /* IPA v3.5.1 just records the tick count */
- if (ipa->version == IPA_VERSION_3_5_1)
+ /* IPA v3.5.1 through v4.1 just record the tick count */
+ if (ipa->version < IPA_VERSION_4_2)
return (u32)ticks;
/* For IPA v4.2, the tick count is represented by base and
@@ -704,7 +822,7 @@ static void ipa_endpoint_init_hol_block_timer(struct ipa_endpoint *endpoint,
u32 val;
offset = IPA_REG_ENDP_INIT_HOL_BLOCK_TIMER_N_OFFSET(endpoint_id);
- val = ipa_reg_init_hol_block_timer_val(ipa, microseconds);
+ val = hol_block_timer_val(ipa, microseconds);
iowrite32(val, ipa->reg_virt + offset);
}
@@ -751,6 +869,16 @@ static void ipa_endpoint_init_deaggr(struct ipa_endpoint *endpoint)
iowrite32(val, endpoint->ipa->reg_virt + offset);
}
+static void ipa_endpoint_init_rsrc_grp(struct ipa_endpoint *endpoint)
+{
+ u32 offset = IPA_REG_ENDP_INIT_RSRC_GRP_N_OFFSET(endpoint->endpoint_id);
+ struct ipa *ipa = endpoint->ipa;
+ u32 val;
+
+ val = rsrc_grp_encoded(ipa->version, endpoint->data->resource_group);
+ iowrite32(val, ipa->reg_virt + offset);
+}
+
static void ipa_endpoint_init_seq(struct ipa_endpoint *endpoint)
{
u32 offset = IPA_REG_ENDP_INIT_SEQ_N_OFFSET(endpoint->endpoint_id);
@@ -834,9 +962,10 @@ static void ipa_endpoint_status(struct ipa_endpoint *endpoint)
val |= u32_encode_bits(status_endpoint_id,
STATUS_ENDP_FMASK);
}
- /* STATUS_LOCATION is 0 (status element precedes packet) */
- /* The next field is present for IPA v4.0 and above */
- /* STATUS_PKT_SUPPRESS_FMASK is 0 */
+ /* STATUS_LOCATION is 0, meaning status element precedes
+ * packet (not present for IPA v4.5)
+ */
+ /* STATUS_PKT_SUPPRESS_FMASK is 0 (not present for v3.5.1) */
}
iowrite32(val, ipa->reg_virt + offset);
@@ -1207,7 +1336,6 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
struct gsi *gsi = &ipa->gsi;
bool suspended = false;
dma_addr_t addr;
- bool legacy;
u32 retries;
u32 len = 1;
void *virt;
@@ -1269,8 +1397,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
* complete the channel reset sequence. Finish by suspending the
* channel again (if necessary).
*/
- legacy = ipa->version == IPA_VERSION_3_5_1;
- gsi_channel_reset(gsi, endpoint->channel_id, legacy);
+ gsi_channel_reset(gsi, endpoint->channel_id, true);
msleep(1);
@@ -1293,21 +1420,19 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint)
u32 channel_id = endpoint->channel_id;
struct ipa *ipa = endpoint->ipa;
bool special;
- bool legacy;
int ret = 0;
/* On IPA v3.5.1, if an RX endpoint is reset while aggregation
* is active, we need to handle things specially to recover.
* All other cases just need to reset the underlying GSI channel.
- *
- * IPA v3.5.1 enables the doorbell engine. Newer versions do not.
*/
- legacy = ipa->version == IPA_VERSION_3_5_1;
- special = !endpoint->toward_ipa && endpoint->data->aggregation;
+ special = ipa->version == IPA_VERSION_3_5_1 &&
+ !endpoint->toward_ipa &&
+ endpoint->data->aggregation;
if (special && ipa_endpoint_aggr_active(endpoint))
ret = ipa_endpoint_reset_rx_aggr(endpoint);
else
- gsi_channel_reset(&ipa->gsi, channel_id, legacy);
+ gsi_channel_reset(&ipa->gsi, channel_id, true);
if (ret)
dev_err(&ipa->pdev->dev,
@@ -1328,6 +1453,7 @@ static void ipa_endpoint_program(struct ipa_endpoint *endpoint)
ipa_endpoint_init_mode(endpoint);
ipa_endpoint_init_aggr(endpoint);
ipa_endpoint_init_deaggr(endpoint);
+ ipa_endpoint_init_rsrc_grp(endpoint);
ipa_endpoint_init_seq(endpoint);
ipa_endpoint_status(endpoint);
}
@@ -1538,8 +1664,8 @@ int ipa_endpoint_config(struct ipa *ipa)
val = ioread32(ipa->reg_virt + IPA_REG_FLAVOR_0_OFFSET);
/* Our RX is an IPA producer */
- rx_base = u32_get_bits(val, BAM_PROD_LOWEST_FMASK);
- max = rx_base + u32_get_bits(val, BAM_MAX_PROD_PIPES_FMASK);
+ rx_base = u32_get_bits(val, IPA_PROD_LOWEST_FMASK);
+ max = rx_base + u32_get_bits(val, IPA_MAX_PROD_PIPES_FMASK);
if (max > IPA_ENDPOINT_MAX) {
dev_err(dev, "too many endpoints (%u > %u)\n",
max, IPA_ENDPOINT_MAX);
@@ -1548,7 +1674,7 @@ int ipa_endpoint_config(struct ipa *ipa)
rx_mask = GENMASK(max - 1, rx_base);
/* Our TX is an IPA consumer */
- max = u32_get_bits(val, BAM_MAX_CONS_PIPES_FMASK);
+ max = u32_get_bits(val, IPA_MAX_CONS_PIPES_FMASK);
tx_mask = GENMASK(max - 1, 0);
ipa->available = rx_mask | tx_mask;