diff options
Diffstat (limited to 'drivers/net/ipa/ipa_endpoint.c')
-rw-r--r-- | drivers/net/ipa/ipa_endpoint.c | 258 |
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; |