diff options
Diffstat (limited to 'drivers/net/ipa/ipa_endpoint.c')
-rw-r--r-- | drivers/net/ipa/ipa_endpoint.c | 2196 |
1 files changed, 2196 insertions, 0 deletions
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c new file mode 100644 index 0000000000..afa1d56d90 --- /dev/null +++ b/drivers/net/ipa/ipa_endpoint.c @@ -0,0 +1,2196 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2019-2023 Linaro Ltd. + */ + +#include <linux/types.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/bitfield.h> +#include <linux/if_rmnet.h> +#include <linux/dma-direction.h> + +#include "gsi.h" +#include "gsi_trans.h" +#include "ipa.h" +#include "ipa_data.h" +#include "ipa_endpoint.h" +#include "ipa_cmd.h" +#include "ipa_mem.h" +#include "ipa_modem.h" +#include "ipa_table.h" +#include "ipa_gsi.h" +#include "ipa_power.h" + +/* Hardware is told about receive buffers once a "batch" has been queued */ +#define IPA_REPLENISH_BATCH 16 /* Must be non-zero */ + +/* The amount of RX buffer space consumed by standard skb overhead */ +#define IPA_RX_BUFFER_OVERHEAD (PAGE_SIZE - SKB_MAX_ORDER(NET_SKB_PAD, 0)) + +/* Where to find the QMAP mux_id for a packet within modem-supplied metadata */ +#define IPA_ENDPOINT_QMAP_METADATA_MASK 0x000000ff /* host byte order */ + +#define IPA_ENDPOINT_RESET_AGGR_RETRY_MAX 3 + +/** enum ipa_status_opcode - IPA status opcode field hardware values */ +enum ipa_status_opcode { /* *Not* a bitmask */ + IPA_STATUS_OPCODE_PACKET = 1, + IPA_STATUS_OPCODE_NEW_RULE_PACKET = 2, + IPA_STATUS_OPCODE_DROPPED_PACKET = 4, + IPA_STATUS_OPCODE_SUSPENDED_PACKET = 8, + IPA_STATUS_OPCODE_LOG = 16, + IPA_STATUS_OPCODE_DCMP = 32, + IPA_STATUS_OPCODE_PACKET_2ND_PASS = 64, +}; + +/** enum ipa_status_exception - IPA status exception field hardware values */ +enum ipa_status_exception { /* *Not* a bitmask */ + /* 0 means no exception */ + IPA_STATUS_EXCEPTION_DEAGGR = 1, + IPA_STATUS_EXCEPTION_IPTYPE = 4, + IPA_STATUS_EXCEPTION_PACKET_LENGTH = 8, + IPA_STATUS_EXCEPTION_FRAG_RULE_MISS = 16, + IPA_STATUS_EXCEPTION_SW_FILTER = 32, + IPA_STATUS_EXCEPTION_NAT = 64, /* IPv4 */ + IPA_STATUS_EXCEPTION_IPV6_CONN_TRACK = 64, /* IPv6 */ + IPA_STATUS_EXCEPTION_UC = 128, + IPA_STATUS_EXCEPTION_INVALID_ENDPOINT = 129, + IPA_STATUS_EXCEPTION_HEADER_INSERT = 136, + IPA_STATUS_EXCEPTION_CHEKCSUM = 229, +}; + +/** enum ipa_status_mask - IPA status mask field bitmask hardware values */ +enum ipa_status_mask { + IPA_STATUS_MASK_FRAG_PROCESS = BIT(0), + IPA_STATUS_MASK_FILT_PROCESS = BIT(1), + IPA_STATUS_MASK_NAT_PROCESS = BIT(2), + IPA_STATUS_MASK_ROUTE_PROCESS = BIT(3), + IPA_STATUS_MASK_TAG_VALID = BIT(4), + IPA_STATUS_MASK_FRAGMENT = BIT(5), + IPA_STATUS_MASK_FIRST_FRAGMENT = BIT(6), + IPA_STATUS_MASK_V4 = BIT(7), + IPA_STATUS_MASK_CKSUM_PROCESS = BIT(8), + IPA_STATUS_MASK_AGGR_PROCESS = BIT(9), + IPA_STATUS_MASK_DEST_EOT = BIT(10), + IPA_STATUS_MASK_DEAGGR_PROCESS = BIT(11), + IPA_STATUS_MASK_DEAGG_FIRST = BIT(12), + IPA_STATUS_MASK_SRC_EOT = BIT(13), + IPA_STATUS_MASK_PREV_EOT = BIT(14), + IPA_STATUS_MASK_BYTE_LIMIT = BIT(15), +}; + +/* Special IPA filter/router rule field value indicating "rule miss" */ +#define IPA_STATUS_RULE_MISS 0x3ff /* 10-bit filter/router rule fields */ + +/** The IPA status nat_type field uses enum ipa_nat_type hardware values */ + +/* enum ipa_status_field_id - IPA packet status structure field identifiers */ +enum ipa_status_field_id { + STATUS_OPCODE, /* enum ipa_status_opcode */ + STATUS_EXCEPTION, /* enum ipa_status_exception */ + STATUS_MASK, /* enum ipa_status_mask (bitmask) */ + STATUS_LENGTH, + STATUS_SRC_ENDPOINT, + STATUS_DST_ENDPOINT, + STATUS_METADATA, + STATUS_FILTER_LOCAL, /* Boolean */ + STATUS_FILTER_HASH, /* Boolean */ + STATUS_FILTER_GLOBAL, /* Boolean */ + STATUS_FILTER_RETAIN, /* Boolean */ + STATUS_FILTER_RULE_INDEX, + STATUS_ROUTER_LOCAL, /* Boolean */ + STATUS_ROUTER_HASH, /* Boolean */ + STATUS_UCP, /* Boolean */ + STATUS_ROUTER_TABLE, + STATUS_ROUTER_RULE_INDEX, + STATUS_NAT_HIT, /* Boolean */ + STATUS_NAT_INDEX, + STATUS_NAT_TYPE, /* enum ipa_nat_type */ + STATUS_TAG_LOW32, /* Low-order 32 bits of 48-bit tag */ + STATUS_TAG_HIGH16, /* High-order 16 bits of 48-bit tag */ + STATUS_SEQUENCE, + STATUS_TIME_OF_DAY, + STATUS_HEADER_LOCAL, /* Boolean */ + STATUS_HEADER_OFFSET, + STATUS_FRAG_HIT, /* Boolean */ + STATUS_FRAG_RULE_INDEX, +}; + +/* Size in bytes of an IPA packet status structure */ +#define IPA_STATUS_SIZE sizeof(__le32[8]) + +/* IPA status structure decoder; looks up field values for a structure */ +static u32 ipa_status_extract(struct ipa *ipa, const void *data, + enum ipa_status_field_id field) +{ + enum ipa_version version = ipa->version; + const __le32 *word = data; + + switch (field) { + case STATUS_OPCODE: + return le32_get_bits(word[0], GENMASK(7, 0)); + case STATUS_EXCEPTION: + return le32_get_bits(word[0], GENMASK(15, 8)); + case STATUS_MASK: + return le32_get_bits(word[0], GENMASK(31, 16)); + case STATUS_LENGTH: + return le32_get_bits(word[1], GENMASK(15, 0)); + case STATUS_SRC_ENDPOINT: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[1], GENMASK(20, 16)); + return le32_get_bits(word[1], GENMASK(23, 16)); + /* Status word 1, bits 21-23 are reserved (not IPA v5.0+) */ + /* Status word 1, bits 24-26 are reserved (IPA v5.0+) */ + case STATUS_DST_ENDPOINT: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[1], GENMASK(28, 24)); + return le32_get_bits(word[7], GENMASK(23, 16)); + /* Status word 1, bits 29-31 are reserved */ + case STATUS_METADATA: + return le32_to_cpu(word[2]); + case STATUS_FILTER_LOCAL: + return le32_get_bits(word[3], GENMASK(0, 0)); + case STATUS_FILTER_HASH: + return le32_get_bits(word[3], GENMASK(1, 1)); + case STATUS_FILTER_GLOBAL: + return le32_get_bits(word[3], GENMASK(2, 2)); + case STATUS_FILTER_RETAIN: + return le32_get_bits(word[3], GENMASK(3, 3)); + case STATUS_FILTER_RULE_INDEX: + return le32_get_bits(word[3], GENMASK(13, 4)); + /* ROUTER_TABLE is in word 3, bits 14-21 (IPA v5.0+) */ + case STATUS_ROUTER_LOCAL: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(14, 14)); + return le32_get_bits(word[1], GENMASK(27, 27)); + case STATUS_ROUTER_HASH: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(15, 15)); + return le32_get_bits(word[1], GENMASK(28, 28)); + case STATUS_UCP: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(16, 16)); + return le32_get_bits(word[7], GENMASK(31, 31)); + case STATUS_ROUTER_TABLE: + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(21, 17)); + return le32_get_bits(word[3], GENMASK(21, 14)); + case STATUS_ROUTER_RULE_INDEX: + return le32_get_bits(word[3], GENMASK(31, 22)); + case STATUS_NAT_HIT: + return le32_get_bits(word[4], GENMASK(0, 0)); + case STATUS_NAT_INDEX: + return le32_get_bits(word[4], GENMASK(13, 1)); + case STATUS_NAT_TYPE: + return le32_get_bits(word[4], GENMASK(15, 14)); + case STATUS_TAG_LOW32: + return le32_get_bits(word[4], GENMASK(31, 16)) | + (le32_get_bits(word[5], GENMASK(15, 0)) << 16); + case STATUS_TAG_HIGH16: + return le32_get_bits(word[5], GENMASK(31, 16)); + case STATUS_SEQUENCE: + return le32_get_bits(word[6], GENMASK(7, 0)); + case STATUS_TIME_OF_DAY: + return le32_get_bits(word[6], GENMASK(31, 8)); + case STATUS_HEADER_LOCAL: + return le32_get_bits(word[7], GENMASK(0, 0)); + case STATUS_HEADER_OFFSET: + return le32_get_bits(word[7], GENMASK(10, 1)); + case STATUS_FRAG_HIT: + return le32_get_bits(word[7], GENMASK(11, 11)); + case STATUS_FRAG_RULE_INDEX: + return le32_get_bits(word[7], GENMASK(15, 12)); + /* Status word 7, bits 16-30 are reserved */ + /* Status word 7, bit 31 is reserved (not IPA v5.0+) */ + default: + WARN(true, "%s: bad field_id %u\n", __func__, field); + return 0; + } +} + +/* 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, + const struct ipa_gsi_endpoint_data *all_data, + const struct ipa_gsi_endpoint_data *data) +{ + const struct ipa_gsi_endpoint_data *other_data; + struct device *dev = &ipa->pdev->dev; + enum ipa_endpoint_name other_name; + + if (ipa_gsi_endpoint_data_empty(data)) + return true; + + if (!data->toward_ipa) { + const struct ipa_endpoint_rx *rx_config; + const struct reg *reg; + u32 buffer_size; + u32 aggr_size; + u32 limit; + + if (data->endpoint.filter_support) { + dev_err(dev, "filtering not supported for " + "RX endpoint %u\n", + data->endpoint_id); + return false; + } + + /* Nothing more to check for non-AP RX */ + if (data->ee_id != GSI_EE_AP) + return true; + + rx_config = &data->endpoint.config.rx; + + /* The buffer size must hold an MTU plus overhead */ + buffer_size = rx_config->buffer_size; + limit = IPA_MTU + IPA_RX_BUFFER_OVERHEAD; + if (buffer_size < limit) { + dev_err(dev, "RX buffer size too small for RX endpoint %u (%u < %u)\n", + data->endpoint_id, buffer_size, limit); + return false; + } + + if (!data->endpoint.config.aggregation) { + bool result = true; + + /* No aggregation; check for bogus aggregation data */ + if (rx_config->aggr_time_limit) { + dev_err(dev, + "time limit with no aggregation for RX endpoint %u\n", + data->endpoint_id); + result = false; + } + + if (rx_config->aggr_hard_limit) { + dev_err(dev, "hard limit with no aggregation for RX endpoint %u\n", + data->endpoint_id); + result = false; + } + + 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. + */ + aggr_size = ipa_aggr_size_kb(buffer_size - NET_SKB_PAD, + rx_config->aggr_hard_limit); + reg = ipa_reg(ipa, ENDP_INIT_AGGR); + + limit = reg_field_max(reg, BYTE_LIMIT); + if (aggr_size > limit) { + dev_err(dev, "aggregated size too large for RX endpoint %u (%u KB > %u KB)\n", + data->endpoint_id, aggr_size, limit); + + return false; + } + + return true; /* Nothing more to check for RX */ + } + + /* Starting with IPA v4.5 sequencer replication is obsolete */ + if (ipa->version >= IPA_VERSION_4_5) { + if (data->endpoint.config.tx.seq_rep_type) { + dev_err(dev, "no-zero seq_rep_type TX endpoint %u\n", + data->endpoint_id); + return false; + } + } + + if (data->endpoint.config.status_enable) { + other_name = data->endpoint.config.tx.status_endpoint; + if (other_name >= count) { + dev_err(dev, "status endpoint name %u out of range " + "for endpoint %u\n", + other_name, data->endpoint_id); + return false; + } + + /* Status endpoint must be defined... */ + other_data = &all_data[other_name]; + if (ipa_gsi_endpoint_data_empty(other_data)) { + dev_err(dev, "DMA endpoint name %u undefined " + "for endpoint %u\n", + other_name, data->endpoint_id); + return false; + } + + /* ...and has to be an RX endpoint... */ + if (other_data->toward_ipa) { + dev_err(dev, + "status endpoint for endpoint %u not RX\n", + data->endpoint_id); + return false; + } + + /* ...and if it's to be an AP endpoint... */ + if (other_data->ee_id == GSI_EE_AP) { + /* ...make sure it has status enabled. */ + if (!other_data->endpoint.config.status_enable) { + dev_err(dev, + "status not enabled for endpoint %u\n", + other_data->endpoint_id); + return false; + } + } + } + + if (data->endpoint.config.dma_mode) { + other_name = data->endpoint.config.dma_endpoint; + if (other_name >= count) { + dev_err(dev, "DMA endpoint name %u out of range " + "for endpoint %u\n", + other_name, data->endpoint_id); + return false; + } + + other_data = &all_data[other_name]; + if (ipa_gsi_endpoint_data_empty(other_data)) { + dev_err(dev, "DMA endpoint name %u undefined " + "for endpoint %u\n", + other_name, data->endpoint_id); + return false; + } + } + + return true; +} + +/* Validate endpoint configuration data. Return max defined endpoint ID */ +static u32 ipa_endpoint_max(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 max; + + if (count > IPA_ENDPOINT_COUNT) { + dev_err(dev, "too many endpoints specified (%u > %u)\n", + count, IPA_ENDPOINT_COUNT); + return 0; + } + + /* 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"); + return 0; + } + if (ipa_gsi_endpoint_data_empty(&data[IPA_ENDPOINT_AP_LAN_RX])) { + dev_err(dev, "LAN RX endpoint not defined\n"); + return 0; + } + if (ipa_gsi_endpoint_data_empty(&data[IPA_ENDPOINT_AP_MODEM_TX])) { + dev_err(dev, "AP->modem TX endpoint not defined\n"); + return 0; + } + if (ipa_gsi_endpoint_data_empty(&data[IPA_ENDPOINT_AP_MODEM_RX])) { + dev_err(dev, "AP<-modem RX endpoint not defined\n"); + return 0; + } + + max = 0; + for (name = 0; name < count; name++, dp++) { + if (!ipa_endpoint_data_valid_one(ipa, count, data, dp)) + return 0; + max = max_t(u32, max, dp->endpoint_id); + } + + return max; +} + +/* Allocate a transaction to use on a non-command endpoint */ +static struct gsi_trans *ipa_endpoint_trans_alloc(struct ipa_endpoint *endpoint, + u32 tre_count) +{ + struct gsi *gsi = &endpoint->ipa->gsi; + u32 channel_id = endpoint->channel_id; + enum dma_data_direction direction; + + direction = endpoint->toward_ipa ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + return gsi_channel_trans_alloc(gsi, channel_id, tre_count, direction); +} + +/* suspend_delay represents suspend for RX, delay for TX endpoints. + * Note that suspend is not supported starting with IPA v4.0, and + * delay mode should not be used starting with IPA v4.2. + */ +static bool +ipa_endpoint_init_ctrl(struct ipa_endpoint *endpoint, bool suspend_delay) +{ + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 field_id; + u32 offset; + bool state; + u32 mask; + u32 val; + + if (endpoint->toward_ipa) + WARN_ON(ipa->version >= IPA_VERSION_4_2); + else + WARN_ON(ipa->version >= IPA_VERSION_4_0); + + reg = ipa_reg(ipa, ENDP_INIT_CTRL); + offset = reg_n_offset(reg, endpoint->endpoint_id); + val = ioread32(ipa->reg_virt + offset); + + field_id = endpoint->toward_ipa ? ENDP_DELAY : ENDP_SUSPEND; + mask = reg_bit(reg, field_id); + + state = !!(val & mask); + + /* Don't bother if it's already in the requested state */ + if (suspend_delay != state) { + val ^= mask; + iowrite32(val, ipa->reg_virt + offset); + } + + return state; +} + +/* We don't care what the previous state was for delay mode */ +static void +ipa_endpoint_program_delay(struct ipa_endpoint *endpoint, bool enable) +{ + /* Delay mode should not be used for IPA v4.2+ */ + WARN_ON(endpoint->ipa->version >= IPA_VERSION_4_2); + WARN_ON(!endpoint->toward_ipa); + + (void)ipa_endpoint_init_ctrl(endpoint, enable); +} + +static bool ipa_endpoint_aggr_active(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + u32 unit = endpoint_id / 32; + const struct reg *reg; + u32 val; + + WARN_ON(!test_bit(endpoint_id, ipa->available)); + + reg = ipa_reg(ipa, STATE_AGGR_ACTIVE); + val = ioread32(ipa->reg_virt + reg_n_offset(reg, unit)); + + return !!(val & BIT(endpoint_id % 32)); +} + +static void ipa_endpoint_force_close(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + u32 mask = BIT(endpoint_id % 32); + struct ipa *ipa = endpoint->ipa; + u32 unit = endpoint_id / 32; + const struct reg *reg; + + WARN_ON(!test_bit(endpoint_id, ipa->available)); + + reg = ipa_reg(ipa, AGGR_FORCE_CLOSE); + iowrite32(mask, ipa->reg_virt + reg_n_offset(reg, unit)); +} + +/** + * ipa_endpoint_suspend_aggr() - Emulate suspend interrupt + * @endpoint: 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->config.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_4_0) + return enable; /* For IPA v4.0+, no change made */ + + WARN_ON(endpoint->toward_ipa); + + 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; +} + +/* Put all modem RX endpoints into suspend mode, and stop transmission + * on all modem TX endpoints. Prior to IPA v4.2, endpoint DELAY mode is + * used for TX endpoints; starting with IPA v4.2 we use GSI channel flow + * control instead. + */ +void ipa_endpoint_modem_pause_all(struct ipa *ipa, bool enable) +{ + u32 endpoint_id = 0; + + while (endpoint_id < ipa->endpoint_count) { + struct ipa_endpoint *endpoint = &ipa->endpoint[endpoint_id++]; + + if (endpoint->ee_id != GSI_EE_MODEM) + continue; + + if (!endpoint->toward_ipa) + (void)ipa_endpoint_program_suspend(endpoint, enable); + else if (ipa->version < IPA_VERSION_4_2) + ipa_endpoint_program_delay(endpoint, enable); + else + gsi_modem_channel_flow_control(&ipa->gsi, + endpoint->channel_id, + enable); + } +} + +/* Reset all modem endpoints to use the default exception endpoint */ +int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa) +{ + struct gsi_trans *trans; + u32 endpoint_id; + u32 count; + + /* We need one command per modem TX endpoint, plus the commands + * that clear the pipeline. + */ + count = ipa->modem_tx_count + ipa_cmd_pipeline_clear_count(); + trans = ipa_cmd_trans_alloc(ipa, count); + if (!trans) { + dev_err(&ipa->pdev->dev, + "no transaction to reset modem exception endpoints\n"); + return -EBUSY; + } + + for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count) { + struct ipa_endpoint *endpoint; + const struct reg *reg; + u32 offset; + + /* We only reset modem TX endpoints */ + endpoint = &ipa->endpoint[endpoint_id]; + if (!(endpoint->ee_id == GSI_EE_MODEM && endpoint->toward_ipa)) + continue; + + reg = ipa_reg(ipa, ENDP_STATUS); + offset = reg_n_offset(reg, endpoint_id); + + /* Value written is 0, and all bits are updated. That + * means status is disabled on the endpoint, and as a + * result all other fields in the register are ignored. + */ + ipa_cmd_register_write_add(trans, offset, 0, ~0, false); + } + + ipa_cmd_pipeline_clear_add(trans); + + gsi_trans_commit_wait(trans); + + ipa_cmd_pipeline_clear_wait(ipa); + + return 0; +} + +static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + enum ipa_cs_offload_en enabled; + const struct reg *reg; + u32 val = 0; + + reg = ipa_reg(ipa, ENDP_INIT_CFG); + /* FRAG_OFFLOAD_EN is 0 */ + if (endpoint->config.checksum) { + enum ipa_version version = ipa->version; + + if (endpoint->toward_ipa) { + u32 off; + + /* Checksum header offset is in 4-byte units */ + off = sizeof(struct rmnet_map_header) / sizeof(u32); + val |= reg_encode(reg, CS_METADATA_HDR_OFFSET, off); + + enabled = version < IPA_VERSION_4_5 + ? IPA_CS_OFFLOAD_UL + : IPA_CS_OFFLOAD_INLINE; + } else { + enabled = version < IPA_VERSION_4_5 + ? IPA_CS_OFFLOAD_DL + : IPA_CS_OFFLOAD_INLINE; + } + } else { + enabled = IPA_CS_OFFLOAD_NONE; + } + val |= reg_encode(reg, CS_OFFLOAD_EN, enabled); + /* CS_GEN_QMB_MASTER_SEL is 0 */ + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val; + + if (!endpoint->toward_ipa) + return; + + reg = ipa_reg(ipa, ENDP_INIT_NAT); + val = reg_encode(reg, NAT_EN, IPA_NAT_TYPE_BYPASS); + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static u32 +ipa_qmap_header_size(enum ipa_version version, struct ipa_endpoint *endpoint) +{ + u32 header_size = sizeof(struct rmnet_map_header); + + /* Without checksum offload, we just have the MAP header */ + if (!endpoint->config.checksum) + return header_size; + + if (version < IPA_VERSION_4_5) { + /* Checksum header inserted for AP TX endpoints only */ + if (endpoint->toward_ipa) + header_size += sizeof(struct rmnet_map_ul_csum_header); + } else { + /* Checksum header is used in both directions */ + header_size += sizeof(struct rmnet_map_v5_csum_header); + } + + return header_size; +} + +/* Encoded value for ENDP_INIT_HDR register HDR_LEN* field(s) */ +static u32 ipa_header_size_encode(enum ipa_version version, + const struct reg *reg, u32 header_size) +{ + u32 field_max = reg_field_max(reg, HDR_LEN); + u32 val; + + /* We know field_max can be used as a mask (2^n - 1) */ + val = reg_encode(reg, HDR_LEN, header_size & field_max); + if (version < IPA_VERSION_4_5) { + WARN_ON(header_size > field_max); + return val; + } + + /* IPA v4.5 adds a few more most-significant bits */ + header_size >>= hweight32(field_max); + WARN_ON(header_size > reg_field_max(reg, HDR_LEN_MSB)); + val |= reg_encode(reg, HDR_LEN_MSB, header_size); + + return val; +} + +/* Encoded value for ENDP_INIT_HDR register OFST_METADATA* field(s) */ +static u32 ipa_metadata_offset_encode(enum ipa_version version, + const struct reg *reg, u32 offset) +{ + u32 field_max = reg_field_max(reg, HDR_OFST_METADATA); + u32 val; + + /* We know field_max can be used as a mask (2^n - 1) */ + val = reg_encode(reg, HDR_OFST_METADATA, offset); + if (version < IPA_VERSION_4_5) { + WARN_ON(offset > field_max); + return val; + } + + /* IPA v4.5 adds a few more most-significant bits */ + offset >>= hweight32(field_max); + WARN_ON(offset > reg_field_max(reg, HDR_OFST_METADATA_MSB)); + val |= reg_encode(reg, HDR_OFST_METADATA_MSB, offset); + + return val; +} + +/** + * ipa_endpoint_init_hdr() - Initialize HDR endpoint configuration register + * @endpoint: Endpoint pointer + * + * We program QMAP endpoints so each packet received is preceded by a QMAP + * header structure. The QMAP header contains a 1-byte mux_id and 2-byte + * packet size field, and we have the IPA hardware populate both for each + * received packet. The header is configured (in the HDR_EXT register) + * to use big endian format. + * + * The packet size is written into the QMAP header's pkt_len field. That + * location is defined here using the HDR_OFST_PKT_SIZE field. + * + * The mux_id comes from a 4-byte metadata value supplied with each packet + * by the modem. It is *not* a QMAP header, but it does contain the mux_id + * value that we want, in its low-order byte. A bitmask defined in the + * endpoint's METADATA_MASK register defines which byte within the modem + * metadata contains the mux_id. And the OFST_METADATA field programmed + * here indicates where the extracted byte should be placed within the QMAP + * header. + */ +static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + + reg = ipa_reg(ipa, ENDP_INIT_HDR); + if (endpoint->config.qmap) { + enum ipa_version version = ipa->version; + size_t header_size; + + header_size = ipa_qmap_header_size(version, endpoint); + val = ipa_header_size_encode(version, reg, header_size); + + /* Define how to fill fields in a received QMAP header */ + if (!endpoint->toward_ipa) { + u32 off; /* Field offset within header */ + + /* Where IPA will write the metadata value */ + off = offsetof(struct rmnet_map_header, mux_id); + val |= ipa_metadata_offset_encode(version, reg, off); + + /* Where IPA will write the length */ + off = offsetof(struct rmnet_map_header, pkt_len); + /* Upper bits are stored in HDR_EXT with IPA v4.5 */ + if (version >= IPA_VERSION_4_5) + off &= reg_field_max(reg, HDR_OFST_PKT_SIZE); + + val |= reg_bit(reg, HDR_OFST_PKT_SIZE_VALID); + val |= reg_encode(reg, HDR_OFST_PKT_SIZE, off); + } + /* For QMAP TX, metadata offset is 0 (modem assumes this) */ + val |= reg_bit(reg, HDR_OFST_METADATA_VALID); + + /* 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, version < v4.5) */ + } + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint) +{ + u32 pad_align = endpoint->config.rx.pad_align; + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + + reg = ipa_reg(ipa, ENDP_INIT_HDR_EXT); + if (endpoint->config.qmap) { + /* We have a header, so we must specify its endianness */ + val |= reg_bit(reg, HDR_ENDIANNESS); /* big endian */ + + /* A QMAP header contains a 6 bit pad field at offset 0. + * The RMNet driver assumes this field is meaningful in + * packets it receives, and assumes the header's payload + * length includes that padding. The RMNet driver does + * *not* pad packets it sends, however, so the pad field + * (although 0) should be ignored. + */ + if (!endpoint->toward_ipa) { + val |= reg_bit(reg, HDR_TOTAL_LEN_OR_PAD_VALID); + /* HDR_TOTAL_LEN_OR_PAD is 0 (pad, not total_len) */ + val |= reg_bit(reg, HDR_PAYLOAD_LEN_INC_PADDING); + /* HDR_TOTAL_LEN_OR_PAD_OFFSET is 0 */ + } + } + + /* HDR_PAYLOAD_LEN_INC_PADDING is 0 */ + if (!endpoint->toward_ipa) + val |= reg_encode(reg, HDR_PAD_TO_ALIGNMENT, pad_align); + + /* 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->config.qmap && !endpoint->toward_ipa) { + u32 mask = reg_field_max(reg, HDR_OFST_PKT_SIZE); + u32 off; /* Field offset within header */ + + off = offsetof(struct rmnet_map_header, pkt_len); + /* Low bits are in the ENDP_INIT_HDR register */ + off >>= hweight32(mask); + val |= reg_encode(reg, HDR_OFST_PKT_SIZE_MSB, off); + /* HDR_ADDITIONAL_CONST_LEN is 0 so MSB is 0 */ + } + } + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void ipa_endpoint_init_hdr_metadata_mask(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + u32 offset; + + if (endpoint->toward_ipa) + return; /* Register not valid for TX endpoints */ + + reg = ipa_reg(ipa, ENDP_INIT_HDR_METADATA_MASK); + offset = reg_n_offset(reg, endpoint_id); + + /* Note that HDR_ENDIANNESS indicates big endian header fields */ + if (endpoint->config.qmap) + val = (__force u32)cpu_to_be32(IPA_ENDPOINT_QMAP_METADATA_MASK); + + iowrite32(val, ipa->reg_virt + offset); +} + +static void ipa_endpoint_init_mode(struct ipa_endpoint *endpoint) +{ + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 offset; + u32 val; + + if (!endpoint->toward_ipa) + return; /* Register not valid for RX endpoints */ + + reg = ipa_reg(ipa, ENDP_INIT_MODE); + if (endpoint->config.dma_mode) { + enum ipa_endpoint_name name = endpoint->config.dma_endpoint; + u32 dma_endpoint_id = ipa->name_map[name]->endpoint_id; + + val = reg_encode(reg, ENDP_MODE, IPA_DMA); + val |= reg_encode(reg, DEST_PIPE_INDEX, dma_endpoint_id); + } else { + val = reg_encode(reg, ENDP_MODE, IPA_BASIC); + } + /* All other bits unspecified (and 0) */ + + offset = reg_n_offset(reg, endpoint->endpoint_id); + iowrite32(val, ipa->reg_virt + offset); +} + +/* For IPA v4.5+, times are expressed using Qtime. A time is represented + * at one of several available granularities, which are configured in + * ipa_qtime_config(). Three (or, starting with IPA v5.0, four) pulse + * generators are set up with different "tick" periods. A Qtime value + * encodes a tick count along with an indication of a pulse generator + * (which has a fixed tick period). Two pulse generators are always + * available to the AP; a third is available starting with IPA v5.0. + * This function determines which pulse generator most accurately + * represents the time period provided, and returns the tick count to + * use to represent that time. + */ +static u32 +ipa_qtime_val(struct ipa *ipa, u32 microseconds, u32 max, u32 *select) +{ + u32 which = 0; + u32 ticks; + + /* Pulse generator 0 has 100 microsecond granularity */ + ticks = DIV_ROUND_CLOSEST(microseconds, 100); + if (ticks <= max) + goto out; + + /* Pulse generator 1 has millisecond granularity */ + which = 1; + ticks = DIV_ROUND_CLOSEST(microseconds, 1000); + if (ticks <= max) + goto out; + + if (ipa->version >= IPA_VERSION_5_0) { + /* Pulse generator 2 has 10 millisecond granularity */ + which = 2; + ticks = DIV_ROUND_CLOSEST(microseconds, 100); + } + WARN_ON(ticks > max); +out: + *select = which; + + return ticks; +} + +/* Encode the aggregation timer limit (microseconds) based on IPA version */ +static u32 aggr_time_limit_encode(struct ipa *ipa, const struct reg *reg, + u32 microseconds) +{ + u32 ticks; + u32 max; + + if (!microseconds) + return 0; /* Nothing to compute if time limit is 0 */ + + max = reg_field_max(reg, TIME_LIMIT); + if (ipa->version >= IPA_VERSION_4_5) { + u32 select; + + ticks = ipa_qtime_val(ipa, microseconds, max, &select); + + return reg_encode(reg, AGGR_GRAN_SEL, select) | + reg_encode(reg, TIME_LIMIT, ticks); + } + + /* We program aggregation granularity in ipa_hardware_config() */ + ticks = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY); + WARN(ticks > max, "aggr_time_limit too large (%u > %u usec)\n", + microseconds, max * IPA_AGGR_GRANULARITY); + + return reg_encode(reg, TIME_LIMIT, ticks); +} + +static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + + reg = ipa_reg(ipa, ENDP_INIT_AGGR); + if (endpoint->config.aggregation) { + if (!endpoint->toward_ipa) { + const struct ipa_endpoint_rx *rx_config; + u32 buffer_size; + u32 limit; + + rx_config = &endpoint->config.rx; + val |= reg_encode(reg, AGGR_EN, IPA_ENABLE_AGGR); + val |= reg_encode(reg, AGGR_TYPE, IPA_GENERIC); + + buffer_size = rx_config->buffer_size; + limit = ipa_aggr_size_kb(buffer_size - NET_SKB_PAD, + rx_config->aggr_hard_limit); + val |= reg_encode(reg, BYTE_LIMIT, limit); + + limit = rx_config->aggr_time_limit; + val |= aggr_time_limit_encode(ipa, reg, limit); + + /* AGGR_PKT_LIMIT is 0 (unlimited) */ + + if (rx_config->aggr_close_eof) + val |= reg_bit(reg, SW_EOF_ACTIVE); + } else { + val |= reg_encode(reg, AGGR_EN, IPA_ENABLE_DEAGGR); + val |= reg_encode(reg, AGGR_TYPE, IPA_QCMAP); + /* other fields ignored */ + } + /* AGGR_FORCE_CLOSE is 0 */ + /* AGGR_GRAN_SEL is 0 for IPA v4.5 */ + } else { + val |= reg_encode(reg, AGGR_EN, IPA_BYPASS_AGGR); + /* other fields ignored */ + } + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +/* 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 representing the timeout period provided + * that should be written to the ENDP_INIT_HOL_BLOCK_TIMER register. + */ +static u32 hol_block_timer_encode(struct ipa *ipa, const struct reg *reg, + u32 microseconds) +{ + u32 width; + u32 scale; + u64 ticks; + u64 rate; + u32 high; + u32 val; + + if (!microseconds) + return 0; /* Nothing to compute if timer period is 0 */ + + if (ipa->version >= IPA_VERSION_4_5) { + u32 max = reg_field_max(reg, TIMER_LIMIT); + u32 select; + u32 ticks; + + ticks = ipa_qtime_val(ipa, microseconds, max, &select); + + return reg_encode(reg, TIMER_GRAN_SEL, 1) | + reg_encode(reg, TIMER_LIMIT, ticks); + } + + /* Use 64 bit arithmetic to avoid overflow */ + rate = ipa_core_clock_rate(ipa); + ticks = DIV_ROUND_CLOSEST(microseconds * rate, 128 * USEC_PER_SEC); + + /* We still need the result to fit into the field */ + WARN_ON(ticks > reg_field_max(reg, TIMER_BASE_VALUE)); + + /* IPA v3.5.1 through v4.1 just record the tick count */ + if (ipa->version < IPA_VERSION_4_2) + return reg_encode(reg, TIMER_BASE_VALUE, (u32)ticks); + + /* For IPA v4.2, the tick count is represented by base and + * scale fields within the 32-bit timer register, where: + * ticks = base << scale; + * 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 high bit is included. + */ + high = fls(ticks); /* 1..32 (or warning above) */ + width = hweight32(reg_fmask(reg, TIMER_BASE_VALUE)); + scale = high > width ? high - width : 0; + if (scale) { + /* If we're scaling, round up to get a closer result */ + ticks += 1 << (scale - 1); + /* High bit was set, so rounding might have affected it */ + if (fls(ticks) != high) + scale++; + } + + val = reg_encode(reg, TIMER_SCALE, scale); + val |= reg_encode(reg, TIMER_BASE_VALUE, (u32)ticks >> scale); + + return val; +} + +/* If microseconds is 0, timeout is immediate */ +static void ipa_endpoint_init_hol_block_timer(struct ipa_endpoint *endpoint, + u32 microseconds) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val; + + /* This should only be changed when HOL_BLOCK_EN is disabled */ + reg = ipa_reg(ipa, ENDP_INIT_HOL_BLOCK_TIMER); + val = hol_block_timer_encode(ipa, reg, microseconds); + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void +ipa_endpoint_init_hol_block_en(struct ipa_endpoint *endpoint, bool enable) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 offset; + u32 val; + + reg = ipa_reg(ipa, ENDP_INIT_HOL_BLOCK_EN); + offset = reg_n_offset(reg, endpoint_id); + val = enable ? reg_bit(reg, HOL_BLOCK_EN) : 0; + + iowrite32(val, ipa->reg_virt + offset); + + /* When enabling, the register must be written twice for IPA v4.5+ */ + if (enable && ipa->version >= IPA_VERSION_4_5) + iowrite32(val, ipa->reg_virt + offset); +} + +/* Assumes HOL_BLOCK is in disabled state */ +static void ipa_endpoint_init_hol_block_enable(struct ipa_endpoint *endpoint, + u32 microseconds) +{ + ipa_endpoint_init_hol_block_timer(endpoint, microseconds); + ipa_endpoint_init_hol_block_en(endpoint, true); +} + +static void ipa_endpoint_init_hol_block_disable(struct ipa_endpoint *endpoint) +{ + ipa_endpoint_init_hol_block_en(endpoint, false); +} + +void ipa_endpoint_modem_hol_block_clear_all(struct ipa *ipa) +{ + u32 endpoint_id = 0; + + while (endpoint_id < ipa->endpoint_count) { + struct ipa_endpoint *endpoint = &ipa->endpoint[endpoint_id++]; + + if (endpoint->toward_ipa || endpoint->ee_id != GSI_EE_MODEM) + continue; + + ipa_endpoint_init_hol_block_disable(endpoint); + ipa_endpoint_init_hol_block_enable(endpoint, 0); + } +} + +static void ipa_endpoint_init_deaggr(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + + if (!endpoint->toward_ipa) + return; /* Register not valid for RX endpoints */ + + reg = ipa_reg(ipa, ENDP_INIT_DEAGGR); + /* DEAGGR_HDR_LEN is 0 */ + /* PACKET_OFFSET_VALID is 0 */ + /* PACKET_OFFSET_LOCATION is ignored (not valid) */ + /* MAX_PACKET_LEN is 0 (not enforced) */ + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void ipa_endpoint_init_rsrc_grp(struct ipa_endpoint *endpoint) +{ + u32 resource_group = endpoint->config.resource_group; + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val; + + reg = ipa_reg(ipa, ENDP_INIT_RSRC_GRP); + val = reg_encode(reg, ENDP_RSRC_GRP, resource_group); + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static void ipa_endpoint_init_seq(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val; + + if (!endpoint->toward_ipa) + return; /* Register not valid for RX endpoints */ + + reg = ipa_reg(ipa, ENDP_INIT_SEQ); + + /* Low-order byte configures primary packet processing */ + val = reg_encode(reg, SEQ_TYPE, endpoint->config.tx.seq_type); + + /* Second byte (if supported) configures replicated packet processing */ + if (ipa->version < IPA_VERSION_4_5) + val |= reg_encode(reg, SEQ_REP_TYPE, + endpoint->config.tx.seq_rep_type); + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +/** + * ipa_endpoint_skb_tx() - Transmit a socket buffer + * @endpoint: Endpoint pointer + * @skb: Socket buffer to send + * + * Returns: 0 if successful, or a negative error code + */ +int ipa_endpoint_skb_tx(struct ipa_endpoint *endpoint, struct sk_buff *skb) +{ + struct gsi_trans *trans; + u32 nr_frags; + int ret; + + /* Make sure source endpoint's TLV FIFO has enough entries to + * hold the linear portion of the skb and all its fragments. + * If not, see if we can linearize it before giving up. + */ + nr_frags = skb_shinfo(skb)->nr_frags; + if (nr_frags > endpoint->skb_frag_max) { + if (skb_linearize(skb)) + return -E2BIG; + nr_frags = 0; + } + + trans = ipa_endpoint_trans_alloc(endpoint, 1 + nr_frags); + if (!trans) + return -EBUSY; + + ret = gsi_trans_skb_add(trans, skb); + if (ret) + goto err_trans_free; + trans->data = skb; /* transaction owns skb now */ + + gsi_trans_commit(trans, !netdev_xmit_more()); + + return 0; + +err_trans_free: + gsi_trans_free(trans); + + return -ENOMEM; +} + +static void ipa_endpoint_status(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + const struct reg *reg; + u32 val = 0; + + reg = ipa_reg(ipa, ENDP_STATUS); + if (endpoint->config.status_enable) { + val |= reg_bit(reg, STATUS_EN); + if (endpoint->toward_ipa) { + enum ipa_endpoint_name name; + u32 status_endpoint_id; + + name = endpoint->config.tx.status_endpoint; + status_endpoint_id = ipa->name_map[name]->endpoint_id; + + val |= reg_encode(reg, STATUS_ENDP, status_endpoint_id); + } + /* STATUS_LOCATION is 0, meaning IPA packet status + * precedes the packet (not present for IPA v4.5+) + */ + /* STATUS_PKT_SUPPRESS_FMASK is 0 (not present for v4.0+) */ + } + + iowrite32(val, ipa->reg_virt + reg_n_offset(reg, endpoint_id)); +} + +static int ipa_endpoint_replenish_one(struct ipa_endpoint *endpoint, + struct gsi_trans *trans) +{ + struct page *page; + u32 buffer_size; + u32 offset; + u32 len; + int ret; + + buffer_size = endpoint->config.rx.buffer_size; + page = dev_alloc_pages(get_order(buffer_size)); + if (!page) + return -ENOMEM; + + /* Offset the buffer to make space for skb headroom */ + offset = NET_SKB_PAD; + len = buffer_size - offset; + + ret = gsi_trans_page_add(trans, page, len, offset); + if (ret) + put_page(page); + else + trans->data = page; /* transaction owns page now */ + + return ret; +} + +/** + * ipa_endpoint_replenish() - Replenish endpoint receive buffers + * @endpoint: Endpoint to be replenished + * + * The IPA hardware can hold a fixed number of receive buffers for an RX + * endpoint, based on the number of entries in the underlying channel ring + * buffer. If an endpoint's "backlog" is non-zero, it indicates how many + * more receive buffers can be supplied to the hardware. Replenishing for + * an endpoint can be disabled, in which case buffers are not queued to + * the hardware. + */ +static void ipa_endpoint_replenish(struct ipa_endpoint *endpoint) +{ + struct gsi_trans *trans; + + if (!test_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags)) + return; + + /* Skip it if it's already active */ + if (test_and_set_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags)) + return; + + while ((trans = ipa_endpoint_trans_alloc(endpoint, 1))) { + bool doorbell; + + if (ipa_endpoint_replenish_one(endpoint, trans)) + goto try_again_later; + + + /* Ring the doorbell if we've got a full batch */ + doorbell = !(++endpoint->replenish_count % IPA_REPLENISH_BATCH); + gsi_trans_commit(trans, doorbell); + } + + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); + + return; + +try_again_later: + gsi_trans_free(trans); + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); + + /* Whenever a receive buffer transaction completes we'll try to + * replenish again. It's unlikely, but if we fail to supply even + * one buffer, nothing will trigger another replenish attempt. + * If the hardware has no receive buffers queued, schedule work to + * try replenishing again. + */ + if (gsi_channel_trans_idle(&endpoint->ipa->gsi, endpoint->channel_id)) + schedule_delayed_work(&endpoint->replenish_work, + msecs_to_jiffies(1)); +} + +static void ipa_endpoint_replenish_enable(struct ipa_endpoint *endpoint) +{ + set_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); + + /* Start replenishing if hardware currently has no buffers */ + if (gsi_channel_trans_idle(&endpoint->ipa->gsi, endpoint->channel_id)) + ipa_endpoint_replenish(endpoint); +} + +static void ipa_endpoint_replenish_disable(struct ipa_endpoint *endpoint) +{ + clear_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); +} + +static void ipa_endpoint_replenish_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct ipa_endpoint *endpoint; + + endpoint = container_of(dwork, struct ipa_endpoint, replenish_work); + + ipa_endpoint_replenish(endpoint); +} + +static void ipa_endpoint_skb_copy(struct ipa_endpoint *endpoint, + void *data, u32 len, u32 extra) +{ + struct sk_buff *skb; + + if (!endpoint->netdev) + return; + + skb = __dev_alloc_skb(len, GFP_ATOMIC); + if (skb) { + /* Copy the data into the socket buffer and receive it */ + skb_put(skb, len); + memcpy(skb->data, data, len); + skb->truesize += extra; + } + + ipa_modem_skb_rx(endpoint->netdev, skb); +} + +static bool ipa_endpoint_skb_build(struct ipa_endpoint *endpoint, + struct page *page, u32 len) +{ + u32 buffer_size = endpoint->config.rx.buffer_size; + struct sk_buff *skb; + + /* Nothing to do if there's no netdev */ + if (!endpoint->netdev) + return false; + + WARN_ON(len > SKB_WITH_OVERHEAD(buffer_size - NET_SKB_PAD)); + + skb = build_skb(page_address(page), buffer_size); + if (skb) { + /* Reserve the headroom and account for the data */ + skb_reserve(skb, NET_SKB_PAD); + skb_put(skb, len); + } + + /* Receive the buffer (or record drop if unable to build it) */ + ipa_modem_skb_rx(endpoint->netdev, skb); + + return skb != NULL; +} + + /* The format of an IPA packet status structure is the same for several + * status types (opcodes). Other types aren't currently supported. + */ +static bool ipa_status_format_packet(enum ipa_status_opcode opcode) +{ + switch (opcode) { + case IPA_STATUS_OPCODE_PACKET: + case IPA_STATUS_OPCODE_DROPPED_PACKET: + case IPA_STATUS_OPCODE_SUSPENDED_PACKET: + case IPA_STATUS_OPCODE_PACKET_2ND_PASS: + return true; + default: + return false; + } +} + +static bool +ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, const void *data) +{ + struct ipa *ipa = endpoint->ipa; + enum ipa_status_opcode opcode; + u32 endpoint_id; + + opcode = ipa_status_extract(ipa, data, STATUS_OPCODE); + if (!ipa_status_format_packet(opcode)) + return true; + + endpoint_id = ipa_status_extract(ipa, data, STATUS_DST_ENDPOINT); + if (endpoint_id != endpoint->endpoint_id) + return true; + + return false; /* Don't skip this packet, process it */ +} + +static bool +ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) +{ + struct ipa_endpoint *command_endpoint; + enum ipa_status_mask status_mask; + struct ipa *ipa = endpoint->ipa; + u32 endpoint_id; + + status_mask = ipa_status_extract(ipa, data, STATUS_MASK); + if (!status_mask) + return false; /* No valid tag */ + + /* The status contains a valid tag. We know the packet was sent to + * this endpoint (already verified by ipa_endpoint_status_skip()). + * If the packet came from the AP->command TX endpoint we know + * this packet was sent as part of the pipeline clear process. + */ + endpoint_id = ipa_status_extract(ipa, data, STATUS_SRC_ENDPOINT); + command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; + if (endpoint_id == command_endpoint->endpoint_id) { + complete(&ipa->completion); + } else { + dev_err(&ipa->pdev->dev, + "unexpected tagged packet from endpoint %u\n", + endpoint_id); + } + + return true; +} + +/* Return whether the status indicates the packet should be dropped */ +static bool +ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const void *data) +{ + enum ipa_status_exception exception; + struct ipa *ipa = endpoint->ipa; + u32 rule; + + /* If the status indicates a tagged transfer, we'll drop the packet */ + if (ipa_endpoint_status_tag_valid(endpoint, data)) + return true; + + /* Deaggregation exceptions we drop; all other types we consume */ + exception = ipa_status_extract(ipa, data, STATUS_EXCEPTION); + if (exception) + return exception == IPA_STATUS_EXCEPTION_DEAGGR; + + /* Drop the packet if it fails to match a routing rule; otherwise no */ + rule = ipa_status_extract(ipa, data, STATUS_ROUTER_RULE_INDEX); + + return rule == IPA_STATUS_RULE_MISS; +} + +static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, + struct page *page, u32 total_len) +{ + u32 buffer_size = endpoint->config.rx.buffer_size; + void *data = page_address(page) + NET_SKB_PAD; + u32 unused = buffer_size - total_len; + struct ipa *ipa = endpoint->ipa; + u32 resid = total_len; + + while (resid) { + u32 length; + u32 align; + u32 len; + + if (resid < IPA_STATUS_SIZE) { + dev_err(&endpoint->ipa->pdev->dev, + "short message (%u bytes < %zu byte status)\n", + resid, IPA_STATUS_SIZE); + break; + } + + /* Skip over status packets that lack packet data */ + length = ipa_status_extract(ipa, data, STATUS_LENGTH); + if (!length || ipa_endpoint_status_skip(endpoint, data)) { + data += IPA_STATUS_SIZE; + resid -= IPA_STATUS_SIZE; + continue; + } + + /* Compute the amount of buffer space consumed by the packet, + * including the status. If the hardware is configured to + * pad packet data to an aligned boundary, account for that. + * And if checksum offload is enabled a trailer containing + * computed checksum information will be appended. + */ + align = endpoint->config.rx.pad_align ? : 1; + len = IPA_STATUS_SIZE + ALIGN(length, align); + if (endpoint->config.checksum) + len += sizeof(struct rmnet_map_dl_csum_trailer); + + if (!ipa_endpoint_status_drop(endpoint, data)) { + void *data2; + u32 extra; + + /* Client receives only packet data (no status) */ + data2 = data + IPA_STATUS_SIZE; + + /* Have the true size reflect the extra unused space in + * the original receive buffer. Distribute the "cost" + * proportionately across all aggregated packets in the + * buffer. + */ + extra = DIV_ROUND_CLOSEST(unused * len, total_len); + ipa_endpoint_skb_copy(endpoint, data2, length, extra); + } + + /* Consume status and the full packet it describes */ + data += len; + resid -= len; + } +} + +void ipa_endpoint_trans_complete(struct ipa_endpoint *endpoint, + struct gsi_trans *trans) +{ + struct page *page; + + if (endpoint->toward_ipa) + return; + + if (trans->cancelled) + goto done; + + /* Parse or build a socket buffer using the actual received length */ + page = trans->data; + if (endpoint->config.status_enable) + ipa_endpoint_status_parse(endpoint, page, trans->len); + else if (ipa_endpoint_skb_build(endpoint, page, trans->len)) + trans->data = NULL; /* Pages have been consumed */ +done: + ipa_endpoint_replenish(endpoint); +} + +void ipa_endpoint_trans_release(struct ipa_endpoint *endpoint, + struct gsi_trans *trans) +{ + if (endpoint->toward_ipa) { + struct ipa *ipa = endpoint->ipa; + + /* Nothing to do for command transactions */ + if (endpoint != ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]) { + struct sk_buff *skb = trans->data; + + if (skb) + dev_kfree_skb_any(skb); + } + } else { + struct page *page = trans->data; + + if (page) + put_page(page); + } +} + +void ipa_endpoint_default_route_set(struct ipa *ipa, u32 endpoint_id) +{ + const struct reg *reg; + u32 val; + + reg = ipa_reg(ipa, ROUTE); + /* ROUTE_DIS is 0 */ + val = reg_encode(reg, ROUTE_DEF_PIPE, endpoint_id); + val |= reg_bit(reg, ROUTE_DEF_HDR_TABLE); + /* ROUTE_DEF_HDR_OFST is 0 */ + val |= reg_encode(reg, ROUTE_FRAG_DEF_PIPE, endpoint_id); + val |= reg_bit(reg, ROUTE_DEF_RETAIN_HDR); + + iowrite32(val, ipa->reg_virt + reg_offset(reg)); +} + +void ipa_endpoint_default_route_clear(struct ipa *ipa) +{ + ipa_endpoint_default_route_set(ipa, 0); +} + +/** + * ipa_endpoint_reset_rx_aggr() - Reset RX endpoint with aggregation active + * @endpoint: Endpoint to be reset + * + * If aggregation is active on an RX endpoint when a reset is performed + * on its underlying GSI channel, a special sequence of actions must be + * taken to ensure the IPA pipeline is properly cleared. + * + * Return: 0 if successful, or a negative error code + */ +static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint) +{ + struct device *dev = &endpoint->ipa->pdev->dev; + struct ipa *ipa = endpoint->ipa; + struct gsi *gsi = &ipa->gsi; + bool suspended = false; + dma_addr_t addr; + u32 retries; + u32 len = 1; + void *virt; + int ret; + + virt = kzalloc(len, GFP_KERNEL); + if (!virt) + return -ENOMEM; + + addr = dma_map_single(dev, virt, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, addr)) { + ret = -ENOMEM; + goto out_kfree; + } + + /* Force close aggregation before issuing the reset */ + ipa_endpoint_force_close(endpoint); + + /* Reset and reconfigure the channel with the doorbell engine + * disabled. Then poll until we know aggregation is no longer + * active. We'll re-enable the doorbell (if appropriate) when + * we reset again below. + */ + gsi_channel_reset(gsi, endpoint->channel_id, false); + + /* Make sure the channel isn't suspended */ + suspended = ipa_endpoint_program_suspend(endpoint, false); + + /* Start channel and do a 1 byte read */ + ret = gsi_channel_start(gsi, endpoint->channel_id); + if (ret) + goto out_suspend_again; + + ret = gsi_trans_read_byte(gsi, endpoint->channel_id, addr); + if (ret) + goto err_endpoint_stop; + + /* Wait for aggregation to be closed on the channel */ + retries = IPA_ENDPOINT_RESET_AGGR_RETRY_MAX; + do { + if (!ipa_endpoint_aggr_active(endpoint)) + break; + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); + } while (retries--); + + /* Check one last time */ + if (ipa_endpoint_aggr_active(endpoint)) + dev_err(dev, "endpoint %u still active during reset\n", + endpoint->endpoint_id); + + gsi_trans_read_byte_done(gsi, endpoint->channel_id); + + ret = gsi_channel_stop(gsi, endpoint->channel_id); + if (ret) + goto out_suspend_again; + + /* 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). + */ + gsi_channel_reset(gsi, endpoint->channel_id, true); + + usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); + + goto out_suspend_again; + +err_endpoint_stop: + (void)gsi_channel_stop(gsi, endpoint->channel_id); +out_suspend_again: + if (suspended) + (void)ipa_endpoint_program_suspend(endpoint, true); + dma_unmap_single(dev, addr, len, DMA_FROM_DEVICE); +out_kfree: + kfree(virt); + + return ret; +} + +static void ipa_endpoint_reset(struct ipa_endpoint *endpoint) +{ + u32 channel_id = endpoint->channel_id; + struct ipa *ipa = endpoint->ipa; + bool special; + 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. + */ + special = ipa->version < IPA_VERSION_4_0 && !endpoint->toward_ipa && + endpoint->config.aggregation; + if (special && ipa_endpoint_aggr_active(endpoint)) + ret = ipa_endpoint_reset_rx_aggr(endpoint); + else + gsi_channel_reset(&ipa->gsi, channel_id, true); + + if (ret) + dev_err(&ipa->pdev->dev, + "error %d resetting channel %u for endpoint %u\n", + ret, endpoint->channel_id, endpoint->endpoint_id); +} + +static void ipa_endpoint_program(struct ipa_endpoint *endpoint) +{ + if (endpoint->toward_ipa) { + /* Newer versions of IPA use GSI channel flow control + * instead of endpoint DELAY mode to prevent sending data. + * Flow control is disabled for newly-allocated channels, + * and we can assume flow control is not (ever) enabled + * for AP TX channels. + */ + if (endpoint->ipa->version < IPA_VERSION_4_2) + ipa_endpoint_program_delay(endpoint, false); + } else { + /* Ensure suspend mode is off on all AP RX endpoints */ + (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); + ipa_endpoint_init_mode(endpoint); + ipa_endpoint_init_aggr(endpoint); + if (!endpoint->toward_ipa) { + if (endpoint->config.rx.holb_drop) + ipa_endpoint_init_hol_block_enable(endpoint, 0); + else + ipa_endpoint_init_hol_block_disable(endpoint); + } + ipa_endpoint_init_deaggr(endpoint); + ipa_endpoint_init_rsrc_grp(endpoint); + ipa_endpoint_init_seq(endpoint); + ipa_endpoint_status(endpoint); +} + +int ipa_endpoint_enable_one(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + struct gsi *gsi = &ipa->gsi; + int ret; + + ret = gsi_channel_start(gsi, endpoint->channel_id); + if (ret) { + dev_err(&ipa->pdev->dev, + "error %d starting %cX channel %u for endpoint %u\n", + ret, endpoint->toward_ipa ? 'T' : 'R', + endpoint->channel_id, endpoint_id); + return ret; + } + + if (!endpoint->toward_ipa) { + ipa_interrupt_suspend_enable(ipa->interrupt, endpoint_id); + ipa_endpoint_replenish_enable(endpoint); + } + + __set_bit(endpoint_id, ipa->enabled); + + return 0; +} + +void ipa_endpoint_disable_one(struct ipa_endpoint *endpoint) +{ + u32 endpoint_id = endpoint->endpoint_id; + struct ipa *ipa = endpoint->ipa; + struct gsi *gsi = &ipa->gsi; + int ret; + + if (!test_bit(endpoint_id, ipa->enabled)) + return; + + __clear_bit(endpoint_id, endpoint->ipa->enabled); + + if (!endpoint->toward_ipa) { + ipa_endpoint_replenish_disable(endpoint); + ipa_interrupt_suspend_disable(ipa->interrupt, endpoint_id); + } + + /* Note that if stop fails, the channel's state is not well-defined */ + ret = gsi_channel_stop(gsi, endpoint->channel_id); + if (ret) + dev_err(&ipa->pdev->dev, + "error %d attempting to stop endpoint %u\n", ret, + endpoint_id); +} + +void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint) +{ + struct device *dev = &endpoint->ipa->pdev->dev; + struct gsi *gsi = &endpoint->ipa->gsi; + int ret; + + if (!test_bit(endpoint->endpoint_id, endpoint->ipa->enabled)) + return; + + if (!endpoint->toward_ipa) { + ipa_endpoint_replenish_disable(endpoint); + (void)ipa_endpoint_program_suspend(endpoint, true); + } + + ret = gsi_channel_suspend(gsi, endpoint->channel_id); + if (ret) + dev_err(dev, "error %d suspending channel %u\n", ret, + endpoint->channel_id); +} + +void ipa_endpoint_resume_one(struct ipa_endpoint *endpoint) +{ + struct device *dev = &endpoint->ipa->pdev->dev; + struct gsi *gsi = &endpoint->ipa->gsi; + int ret; + + if (!test_bit(endpoint->endpoint_id, endpoint->ipa->enabled)) + return; + + if (!endpoint->toward_ipa) + (void)ipa_endpoint_program_suspend(endpoint, false); + + ret = gsi_channel_resume(gsi, endpoint->channel_id); + if (ret) + dev_err(dev, "error %d resuming channel %u\n", ret, + endpoint->channel_id); + else if (!endpoint->toward_ipa) + ipa_endpoint_replenish_enable(endpoint); +} + +void ipa_endpoint_suspend(struct ipa *ipa) +{ + if (!ipa->setup_complete) + return; + + if (ipa->modem_netdev) + ipa_modem_suspend(ipa->modem_netdev); + + ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]); + ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]); +} + +void ipa_endpoint_resume(struct ipa *ipa) +{ + if (!ipa->setup_complete) + return; + + ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]); + ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]); + + if (ipa->modem_netdev) + ipa_modem_resume(ipa->modem_netdev); +} + +static void ipa_endpoint_setup_one(struct ipa_endpoint *endpoint) +{ + struct gsi *gsi = &endpoint->ipa->gsi; + u32 channel_id = endpoint->channel_id; + + /* Only AP endpoints get set up */ + if (endpoint->ee_id != GSI_EE_AP) + return; + + endpoint->skb_frag_max = gsi->channel[channel_id].trans_tre_max - 1; + if (!endpoint->toward_ipa) { + /* RX transactions require a single TRE, so the maximum + * backlog is the same as the maximum outstanding TREs. + */ + clear_bit(IPA_REPLENISH_ENABLED, endpoint->replenish_flags); + clear_bit(IPA_REPLENISH_ACTIVE, endpoint->replenish_flags); + INIT_DELAYED_WORK(&endpoint->replenish_work, + ipa_endpoint_replenish_work); + } + + ipa_endpoint_program(endpoint); + + __set_bit(endpoint->endpoint_id, endpoint->ipa->set_up); +} + +static void ipa_endpoint_teardown_one(struct ipa_endpoint *endpoint) +{ + __clear_bit(endpoint->endpoint_id, endpoint->ipa->set_up); + + if (!endpoint->toward_ipa) + cancel_delayed_work_sync(&endpoint->replenish_work); + + ipa_endpoint_reset(endpoint); +} + +void ipa_endpoint_setup(struct ipa *ipa) +{ + u32 endpoint_id; + + for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count) + ipa_endpoint_setup_one(&ipa->endpoint[endpoint_id]); +} + +void ipa_endpoint_teardown(struct ipa *ipa) +{ + u32 endpoint_id; + + for_each_set_bit(endpoint_id, ipa->set_up, ipa->endpoint_count) + ipa_endpoint_teardown_one(&ipa->endpoint[endpoint_id]); +} + +void ipa_endpoint_deconfig(struct ipa *ipa) +{ + ipa->available_count = 0; + bitmap_free(ipa->available); + ipa->available = NULL; +} + +int ipa_endpoint_config(struct ipa *ipa) +{ + struct device *dev = &ipa->pdev->dev; + const struct reg *reg; + u32 endpoint_id; + u32 hw_limit; + u32 tx_count; + u32 rx_count; + u32 rx_base; + u32 limit; + u32 val; + + /* Prior to IPA v3.5, the FLAVOR_0 register was not supported. + * Furthermore, the endpoints were not grouped such that TX + * endpoint numbers started with 0 and RX endpoints had numbers + * higher than all TX endpoints, so we can't do the simple + * direction check used for newer hardware below. + * + * For hardware that doesn't support the FLAVOR_0 register, + * just set the available mask to support any endpoint, and + * assume the configuration is valid. + */ + if (ipa->version < IPA_VERSION_3_5) { + ipa->available = bitmap_zalloc(IPA_ENDPOINT_MAX, GFP_KERNEL); + if (!ipa->available) + return -ENOMEM; + ipa->available_count = IPA_ENDPOINT_MAX; + + bitmap_set(ipa->available, 0, IPA_ENDPOINT_MAX); + + return 0; + } + + /* Find out about the endpoints supplied by the hardware, and ensure + * the highest one doesn't exceed the number supported by software. + */ + reg = ipa_reg(ipa, FLAVOR_0); + val = ioread32(ipa->reg_virt + reg_offset(reg)); + + /* Our RX is an IPA producer; our TX is an IPA consumer. */ + tx_count = reg_decode(reg, MAX_CONS_PIPES, val); + rx_count = reg_decode(reg, MAX_PROD_PIPES, val); + rx_base = reg_decode(reg, PROD_LOWEST, val); + + limit = rx_base + rx_count; + if (limit > IPA_ENDPOINT_MAX) { + dev_err(dev, "too many endpoints, %u > %u\n", + limit, IPA_ENDPOINT_MAX); + return -EINVAL; + } + + /* Until IPA v5.0, the max endpoint ID was 32 */ + hw_limit = ipa->version < IPA_VERSION_5_0 ? 32 : U8_MAX + 1; + if (limit > hw_limit) { + dev_err(dev, "unexpected endpoint count, %u > %u\n", + limit, hw_limit); + return -EINVAL; + } + + /* Allocate and initialize the available endpoint bitmap */ + ipa->available = bitmap_zalloc(limit, GFP_KERNEL); + if (!ipa->available) + return -ENOMEM; + ipa->available_count = limit; + + /* Mark all supported RX and TX endpoints as available */ + bitmap_set(ipa->available, 0, tx_count); + bitmap_set(ipa->available, rx_base, rx_count); + + for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count) { + struct ipa_endpoint *endpoint; + + if (endpoint_id >= limit) { + dev_err(dev, "invalid endpoint id, %u > %u\n", + endpoint_id, limit - 1); + goto err_free_bitmap; + } + + if (!test_bit(endpoint_id, ipa->available)) { + dev_err(dev, "unavailable endpoint id %u\n", + endpoint_id); + goto err_free_bitmap; + } + + /* Make sure it's pointing in the right direction */ + endpoint = &ipa->endpoint[endpoint_id]; + if (endpoint->toward_ipa) { + if (endpoint_id < tx_count) + continue; + } else if (endpoint_id >= rx_base) { + continue; + } + + dev_err(dev, "endpoint id %u wrong direction\n", endpoint_id); + goto err_free_bitmap; + } + + return 0; + +err_free_bitmap: + ipa_endpoint_deconfig(ipa); + + return -EINVAL; +} + +static void ipa_endpoint_init_one(struct ipa *ipa, enum ipa_endpoint_name name, + const struct ipa_gsi_endpoint_data *data) +{ + struct ipa_endpoint *endpoint; + + endpoint = &ipa->endpoint[data->endpoint_id]; + + if (data->ee_id == GSI_EE_AP) + ipa->channel_map[data->channel_id] = endpoint; + ipa->name_map[name] = endpoint; + + endpoint->ipa = ipa; + endpoint->ee_id = data->ee_id; + endpoint->channel_id = data->channel_id; + endpoint->endpoint_id = data->endpoint_id; + endpoint->toward_ipa = data->toward_ipa; + endpoint->config = data->endpoint.config; + + __set_bit(endpoint->endpoint_id, ipa->defined); +} + +static void ipa_endpoint_exit_one(struct ipa_endpoint *endpoint) +{ + __clear_bit(endpoint->endpoint_id, endpoint->ipa->defined); + + memset(endpoint, 0, sizeof(*endpoint)); +} + +void ipa_endpoint_exit(struct ipa *ipa) +{ + u32 endpoint_id; + + ipa->filtered = 0; + + for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count) + ipa_endpoint_exit_one(&ipa->endpoint[endpoint_id]); + + bitmap_free(ipa->enabled); + ipa->enabled = NULL; + bitmap_free(ipa->set_up); + ipa->set_up = NULL; + bitmap_free(ipa->defined); + ipa->defined = NULL; + + memset(ipa->name_map, 0, sizeof(ipa->name_map)); + memset(ipa->channel_map, 0, sizeof(ipa->channel_map)); +} + +/* Returns a bitmask of endpoints that support filtering, or 0 on error */ +int ipa_endpoint_init(struct ipa *ipa, u32 count, + const struct ipa_gsi_endpoint_data *data) +{ + enum ipa_endpoint_name name; + u32 filtered; + + BUILD_BUG_ON(!IPA_REPLENISH_BATCH); + + /* Number of endpoints is one more than the maximum ID */ + ipa->endpoint_count = ipa_endpoint_max(ipa, count, data) + 1; + if (!ipa->endpoint_count) + return -EINVAL; + + /* Initialize endpoint state bitmaps */ + ipa->defined = bitmap_zalloc(ipa->endpoint_count, GFP_KERNEL); + if (!ipa->defined) + return -ENOMEM; + + ipa->set_up = bitmap_zalloc(ipa->endpoint_count, GFP_KERNEL); + if (!ipa->set_up) + goto err_free_defined; + + ipa->enabled = bitmap_zalloc(ipa->endpoint_count, GFP_KERNEL); + if (!ipa->enabled) + goto err_free_set_up; + + filtered = 0; + for (name = 0; name < count; name++, data++) { + if (ipa_gsi_endpoint_data_empty(data)) + continue; /* Skip over empty slots */ + + ipa_endpoint_init_one(ipa, name, data); + + if (data->endpoint.filter_support) + filtered |= BIT(data->endpoint_id); + if (data->ee_id == GSI_EE_MODEM && data->toward_ipa) + ipa->modem_tx_count++; + } + + /* Make sure the set of filtered endpoints is valid */ + if (!ipa_filtered_valid(ipa, filtered)) { + ipa_endpoint_exit(ipa); + + return -EINVAL; + } + + ipa->filtered = filtered; + + return 0; + +err_free_set_up: + bitmap_free(ipa->set_up); + ipa->set_up = NULL; +err_free_defined: + bitmap_free(ipa->defined); + ipa->defined = NULL; + + return -ENOMEM; +} |