diff --git a/drivers/net/ipa/data/ipa_data-v3.1.c b/drivers/net/ipa/data/ipa_data-v3.1.c index 1c1895aea8118..e0d71f6092729 100644 --- a/drivers/net/ipa/data/ipa_data-v3.1.c +++ b/drivers/net/ipa/data/ipa_data-v3.1.c @@ -526,7 +526,7 @@ static const struct ipa_power_data ipa_power_data = { /* Configuration data for an SoC having IPA v3.1 */ const struct ipa_data ipa_data_v3_1 = { .version = IPA_VERSION_3_1, - .backward_compat = BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK, + .backward_compat = BIT(BCR_CMDQ_L_LACK_ONE_ENTRY), .qsb_count = ARRAY_SIZE(ipa_qsb_data), .qsb_data = ipa_qsb_data, .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data), diff --git a/drivers/net/ipa/data/ipa_data-v3.5.1.c b/drivers/net/ipa/data/ipa_data-v3.5.1.c index 58b708d2fc75d..383ef18900654 100644 --- a/drivers/net/ipa/data/ipa_data-v3.5.1.c +++ b/drivers/net/ipa/data/ipa_data-v3.5.1.c @@ -407,11 +407,11 @@ static const struct ipa_power_data ipa_power_data = { /* Configuration data for an SoC having IPA v3.5.1 */ const struct ipa_data ipa_data_v3_5_1 = { .version = IPA_VERSION_3_5_1, - .backward_compat = BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK | - BCR_TX_NOT_USING_BRESP_FMASK | - BCR_SUSPEND_L2_IRQ_FMASK | - BCR_HOLB_DROP_L2_IRQ_FMASK | - BCR_DUAL_TX_FMASK, + .backward_compat = BIT(BCR_CMDQ_L_LACK_ONE_ENTRY) | + BIT(BCR_TX_NOT_USING_BRESP) | + BIT(BCR_SUSPEND_L2_IRQ) | + BIT(BCR_HOLB_DROP_L2_IRQ) | + BIT(BCR_DUAL_TX), .qsb_count = ARRAY_SIZE(ipa_qsb_data), .qsb_data = ipa_qsb_data, .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data), diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index fe0eb882104ee..6db62b6fb6632 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -725,45 +725,65 @@ static u32 aggr_byte_limit_encoded(enum ipa_version version, u32 limit) return u32_encode_bits(limit, aggr_byte_limit_fmask(false)); } +/* For IPA v4.5+, times are expressed using Qtime. The AP uses one of two + * pulse generators (0 and 1) to measure elapsed time. In ipa_qtime_config() + * they're configured to have granularity 100 usec and 1 msec, respectively. + * + * The return value is the positive or negative Qtime value to use to + * express the (microsecond) time provided. A positive return value + * means pulse generator 0 can be used; otherwise use pulse generator 1. + */ +static int ipa_qtime_val(u32 microseconds, u32 max) +{ + u32 val; + + /* Use 100 microsecond granularity if possible */ + val = DIV_ROUND_CLOSEST(microseconds, 100); + if (val <= max) + return (int)val; + + /* Have to use pulse generator 1 (millisecond granularity) */ + val = DIV_ROUND_CLOSEST(microseconds, 1000); + WARN_ON(val > max); + + return (int)-val; +} + /* Encode the aggregation timer limit (microseconds) based on IPA version */ -static u32 aggr_time_limit_encoded(enum ipa_version version, u32 limit) +static u32 aggr_time_limit_encode(enum ipa_version version, u32 microseconds) { - u32 gran_sel; u32 fmask; u32 val; - if (version < IPA_VERSION_4_5) { - /* We set aggregation granularity in ipa_hardware_config() */ - fmask = aggr_time_limit_fmask(true); - val = DIV_ROUND_CLOSEST(limit, IPA_AGGR_GRANULARITY); - WARN(val > field_max(fmask), - "aggr_time_limit too large (%u > %u usec)\n", - val, field_max(fmask) * IPA_AGGR_GRANULARITY); - - return u32_encode_bits(val, fmask); - } + if (!microseconds) + return 0; /* Nothing to compute if time limit is 0 */ + + if (version >= IPA_VERSION_4_5) { + u32 gran_sel; + int ret; + + /* Compute the Qtime limit value to use */ + fmask = aggr_time_limit_fmask(false); + ret = ipa_qtime_val(microseconds, field_max(fmask)); + if (ret < 0) { + val = -ret; + gran_sel = AGGR_GRAN_SEL_FMASK; + } else { + val = ret; + gran_sel = 0; + } - /* 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); - WARN(val > field_max(fmask), - "aggr_time_limit too large (%u > %u usec)\n", - limit, field_max(fmask) * 1000); - } else { - /* We can use pulse generator 0 (100 usec granularity) */ - gran_sel = 0; + return gran_sel | u32_encode_bits(val, fmask); } - return gran_sel | u32_encode_bits(val, fmask); + /* We set aggregation granularity in ipa_hardware_config() */ + fmask = aggr_time_limit_fmask(true); + val = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY); + WARN(val > field_max(fmask), + "aggr_time_limit too large (%u > %u usec)\n", + val, field_max(fmask) * IPA_AGGR_GRANULARITY); + + return u32_encode_bits(val, fmask); } static u32 aggr_sw_eof_active_encoded(enum ipa_version version, bool enabled) @@ -799,7 +819,7 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint) val |= aggr_byte_limit_encoded(version, limit); limit = rx_config->aggr_time_limit; - val |= aggr_time_limit_encoded(version, limit); + val |= aggr_time_limit_encode(version, limit); /* AGGR_PKT_LIMIT is 0 (unlimited) */ @@ -821,45 +841,15 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint) iowrite32(val, endpoint->ipa->reg_virt + offset); } -/* 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 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. + * 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_val(struct ipa *ipa, u32 microseconds) +static u32 hol_block_timer_encode(struct ipa *ipa, u32 microseconds) { u32 width; u32 scale; @@ -871,8 +861,22 @@ static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds) if (!microseconds) return 0; /* Nothing to compute if timer period is 0 */ - if (ipa->version >= IPA_VERSION_4_5) - return hol_block_timer_qtime_val(ipa, microseconds); + if (ipa->version >= IPA_VERSION_4_5) { + u32 gran_sel; + int ret; + + /* Compute the Qtime limit value to use */ + ret = ipa_qtime_val(microseconds, field_max(TIME_LIMIT_FMASK)); + if (ret < 0) { + val = -ret; + gran_sel = GRAN_SEL_FMASK; + } else { + val = ret; + gran_sel = 0; + } + + return gran_sel | u32_encode_bits(val, TIME_LIMIT_FMASK); + } /* Use 64 bit arithmetic to avoid overflow... */ rate = ipa_core_clock_rate(ipa); @@ -920,7 +924,7 @@ static void ipa_endpoint_init_hol_block_timer(struct ipa_endpoint *endpoint, /* This should only be changed when HOL_BLOCK_EN is disabled */ offset = IPA_REG_ENDP_INIT_HOL_BLOCK_TIMER_N_OFFSET(endpoint_id); - val = hol_block_timer_val(ipa, microseconds); + val = hol_block_timer_encode(ipa, microseconds); iowrite32(val, ipa->reg_virt + offset); } diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 9dfa7f58a207f..a552d6edb702d 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -183,6 +183,56 @@ static void ipa_teardown(struct ipa *ipa) gsi_teardown(&ipa->gsi); } +static void +ipa_hardware_config_bcr(struct ipa *ipa, const struct ipa_data *data) +{ + u32 val; + + /* IPA v4.5+ has no backward compatibility register */ + if (ipa->version >= IPA_VERSION_4_5) + return; + + val = data->backward_compat; + iowrite32(val, ipa->reg_virt + IPA_REG_BCR_OFFSET); +} + +static void ipa_hardware_config_tx(struct ipa *ipa) +{ + enum ipa_version version = ipa->version; + u32 val; + + if (version <= IPA_VERSION_4_0 || version >= IPA_VERSION_4_5) + return; + + /* Disable PA mask to allow HOLB drop */ + val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); + + val &= ~PA_MASK_EN_FMASK; + + iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); +} + +static void ipa_hardware_config_clkon(struct ipa *ipa) +{ + enum ipa_version version = ipa->version; + u32 val; + + if (version < IPA_VERSION_3_1 || version >= IPA_VERSION_4_5) + return; + + /* Implement some hardware workarounds */ + if (version >= IPA_VERSION_4_0) { + /* Enable open global clocks in the CLKON configuration */ + val = GLOBAL_FMASK | GLOBAL_2X_CLK_FMASK; + } else if (version == IPA_VERSION_3_1) { + val = MISC_FMASK; /* Disable MISC clock gating */ + } else { + return; + } + + iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET); +} + /* Configure bus access behavior for IPA components */ static void ipa_hardware_config_comp(struct ipa *ipa) { @@ -306,6 +356,39 @@ static void ipa_qtime_config(struct ipa *ipa) iowrite32(val, ipa->reg_virt + IPA_REG_TIMERS_XO_CLK_DIV_CFG_OFFSET); } +/* Before IPA v4.5 timing is controlled by a counter register */ +static void ipa_hardware_config_counter(struct ipa *ipa) +{ + u32 granularity; + u32 val; + + granularity = ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY); + + val = u32_encode_bits(granularity, AGGR_GRANULARITY_FMASK); + + iowrite32(val, ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET); +} + +static void ipa_hardware_config_timing(struct ipa *ipa) +{ + if (ipa->version < IPA_VERSION_4_5) + ipa_hardware_config_counter(ipa); + else + ipa_qtime_config(ipa); +} + +static void ipa_hardware_config_hashing(struct ipa *ipa) +{ + u32 offset; + + if (ipa->version != IPA_VERSION_4_2) + return; + + /* IPA v4.2 does not support hashed tables, so disable them */ + offset = ipa_reg_filt_rout_hash_en_offset(IPA_VERSION_4_2); + iowrite32(0, ipa->reg_virt + offset); +} + static void ipa_idle_indication_cfg(struct ipa *ipa, u32 enter_idle_debounce_thresh, bool const_non_idle_enable) @@ -349,55 +432,13 @@ static void ipa_hardware_dcd_deconfig(struct ipa *ipa) */ static void ipa_hardware_config(struct ipa *ipa, const struct ipa_data *data) { - enum ipa_version version = ipa->version; - u32 granularity; - u32 val; - - /* IPA v4.5+ has no backward compatibility register */ - if (version < IPA_VERSION_4_5) { - val = data->backward_compat; - iowrite32(val, ipa->reg_virt + IPA_REG_BCR_OFFSET); - } - - /* Implement some hardware workarounds */ - if (version >= IPA_VERSION_4_0 && version < IPA_VERSION_4_5) { - /* Disable PA mask to allow HOLB drop */ - val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); - val &= ~PA_MASK_EN_FMASK; - iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); - - /* Enable open global clocks in the CLKON configuration */ - val = GLOBAL_FMASK | GLOBAL_2X_CLK_FMASK; - } else if (version == IPA_VERSION_3_1) { - val = MISC_FMASK; /* Disable MISC clock gating */ - } else { - val = 0; /* No CLKON configuration needed */ - } - if (val) - iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET); - + ipa_hardware_config_bcr(ipa, data); + ipa_hardware_config_tx(ipa); + ipa_hardware_config_clkon(ipa); ipa_hardware_config_comp(ipa); - - /* Configure system bus limits */ ipa_hardware_config_qsb(ipa, data); - - if (version < IPA_VERSION_4_5) { - /* Configure aggregation timer granularity */ - granularity = ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY); - val = u32_encode_bits(granularity, AGGR_GRANULARITY_FMASK); - iowrite32(val, ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET); - } else { - ipa_qtime_config(ipa); - } - - /* IPA v4.2 does not support hashed tables, so disable them */ - if (version == IPA_VERSION_4_2) { - u32 offset = ipa_reg_filt_rout_hash_en_offset(version); - - iowrite32(0, ipa->reg_virt + offset); - } - - /* Enable dynamic clock division */ + ipa_hardware_config_timing(ipa); + ipa_hardware_config_hashing(ipa); ipa_hardware_dcd_config(ipa); } diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index 3e24bddc682ef..f593cf3187950 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -220,20 +220,18 @@ static inline u32 ipa_reg_state_aggr_active_offset(enum ipa_version version) /* The next register is not present for IPA v4.5+ */ #define IPA_REG_BCR_OFFSET 0x000001d0 -/* The next two fields are not present for IPA v4.2+ */ -#define BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK GENMASK(0, 0) -#define BCR_TX_NOT_USING_BRESP_FMASK GENMASK(1, 1) -/* The next field is invalid for IPA v4.0+ */ -#define BCR_TX_SUSPEND_IRQ_ASSERT_ONCE_FMASK GENMASK(2, 2) -/* The next two fields are not present for IPA v4.2+ */ -#define BCR_SUSPEND_L2_IRQ_FMASK GENMASK(3, 3) -#define BCR_HOLB_DROP_L2_IRQ_FMASK GENMASK(4, 4) -/* The next five fields are present for IPA v3.5+ */ -#define BCR_DUAL_TX_FMASK GENMASK(5, 5) -#define BCR_ENABLE_FILTER_DATA_CACHE_FMASK GENMASK(6, 6) -#define BCR_NOTIF_PRIORITY_OVER_ZLT_FMASK GENMASK(7, 7) -#define BCR_FILTER_PREFETCH_EN_FMASK GENMASK(8, 8) -#define BCR_ROUTER_PREFETCH_EN_FMASK GENMASK(9, 9) +enum ipa_bcr_compat { + BCR_CMDQ_L_LACK_ONE_ENTRY = 0x0, /* Not IPA v4.2+ */ + BCR_TX_NOT_USING_BRESP = 0x1, /* Not IPA v4.2+ */ + BCR_TX_SUSPEND_IRQ_ASSERT_ONCE = 0x2, /* Not IPA v4.0+ */ + BCR_SUSPEND_L2_IRQ = 0x3, /* Not IPA v4.2+ */ + BCR_HOLB_DROP_L2_IRQ = 0x4, /* Not IPA v4.2+ */ + BCR_DUAL_TX = 0x5, /* IPA v3.5+ */ + BCR_ENABLE_FILTER_DATA_CACHE = 0x6, /* IPA v3.5+ */ + BCR_NOTIF_PRIORITY_OVER_ZLT = 0x7, /* IPA v3.5+ */ + BCR_FILTER_PREFETCH_EN = 0x8, /* IPA v3.5+ */ + BCR_ROUTER_PREFETCH_EN = 0x9, /* IPA v3.5+ */ +}; /* The value of the next register must be a multiple of 8 (bottom 3 bits 0) */ #define IPA_REG_LOCAL_PKT_PROC_CNTXT_OFFSET 0x000001e8 @@ -365,10 +363,10 @@ enum ipa_pulse_gran { /** enum ipa_cs_offload_en - ENDP_INIT_CFG register CS_OFFLOAD_EN field value */ enum ipa_cs_offload_en { - IPA_CS_OFFLOAD_NONE = 0x0, - IPA_CS_OFFLOAD_UL = 0x1, /* Before IPA v4.5 (TX) */ - IPA_CS_OFFLOAD_DL = 0x2, /* Before IPA v4.5 (RX) */ - IPA_CS_OFFLOAD_INLINE = 0x1, /* IPA v4.5 (TX and RX) */ + IPA_CS_OFFLOAD_NONE = 0x0, + IPA_CS_OFFLOAD_UL /* TX */ = 0x1, /* Not IPA v4.5+ */ + IPA_CS_OFFLOAD_DL /* RX */ = 0x2, /* Not IPA v4.5+ */ + IPA_CS_OFFLOAD_INLINE /* TX and RX */ = 0x1, /* IPA v4.5+ */ }; /* Valid only for TX (IPA consumer) endpoints */ @@ -378,9 +376,9 @@ enum ipa_cs_offload_en { /** enum ipa_nat_en - ENDP_INIT_NAT register NAT_EN field value */ enum ipa_nat_en { - IPA_NAT_BYPASS = 0x0, - IPA_NAT_SRC = 0x1, - IPA_NAT_DST = 0x2, + IPA_NAT_BYPASS = 0x0, + IPA_NAT_SRC = 0x1, + IPA_NAT_DST = 0x2, }; #define IPA_REG_ENDP_INIT_HDR_N_OFFSET(ep) \ @@ -474,10 +472,10 @@ static inline u32 ipa_metadata_offset_encoded(enum ipa_version version, /** enum ipa_mode - ENDP_INIT_MODE register MODE field value */ enum ipa_mode { - IPA_BASIC = 0x0, - IPA_ENABLE_FRAMING_HDLC = 0x1, - IPA_ENABLE_DEFRAMING_HDLC = 0x2, - IPA_DMA = 0x3, + IPA_BASIC = 0x0, + IPA_ENABLE_FRAMING_HDLC = 0x1, + IPA_ENABLE_DEFRAMING_HDLC = 0x2, + IPA_DMA = 0x3, }; #define IPA_REG_ENDP_INIT_AGGR_N_OFFSET(ep) \ @@ -526,20 +524,20 @@ static inline u32 aggr_hard_byte_limit_enable_fmask(bool legacy) /** enum ipa_aggr_en - ENDP_INIT_AGGR register AGGR_EN field value */ enum ipa_aggr_en { - IPA_BYPASS_AGGR = 0x0, /* (TX, RX) */ - IPA_ENABLE_AGGR = 0x1, /* (RX) */ - IPA_ENABLE_DEAGGR = 0x2, /* (TX) */ + IPA_BYPASS_AGGR /* TX and RX */ = 0x0, + IPA_ENABLE_AGGR /* RX */ = 0x1, + IPA_ENABLE_DEAGGR /* TX */ = 0x2, }; /** enum ipa_aggr_type - ENDP_INIT_AGGR register AGGR_TYPE field value */ enum ipa_aggr_type { - IPA_MBIM_16 = 0x0, - IPA_HDLC = 0x1, - IPA_TLP = 0x2, - IPA_RNDIS = 0x3, - IPA_GENERIC = 0x4, - IPA_COALESCE = 0x5, - IPA_QCMAP = 0x6, + IPA_MBIM_16 = 0x0, + IPA_HDLC = 0x1, + IPA_TLP = 0x2, + IPA_RNDIS = 0x3, + IPA_GENERIC = 0x4, + IPA_COALESCE = 0x5, + IPA_QCMAP = 0x6, }; /* Valid only for RX (IPA producer) endpoints */ diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c index 69efe672ca528..037cec2fd5942 100644 --- a/drivers/net/ipa/ipa_table.c +++ b/drivers/net/ipa/ipa_table.c @@ -524,7 +524,7 @@ static void ipa_filter_tuple_zero(struct ipa_endpoint *endpoint) val = ioread32(endpoint->ipa->reg_virt + offset); /* Zero all filter-related fields, preserving the rest */ - u32p_replace_bits(&val, 0, IPA_REG_ENDP_FILTER_HASH_MSK_ALL); + val &= ~IPA_REG_ENDP_FILTER_HASH_MSK_ALL; iowrite32(val, endpoint->ipa->reg_virt + offset); } @@ -571,7 +571,7 @@ static void ipa_route_tuple_zero(struct ipa *ipa, u32 route_id) val = ioread32(ipa->reg_virt + offset); /* Zero all route-related fields, preserving the rest */ - u32p_replace_bits(&val, 0, IPA_REG_ENDP_ROUTER_HASH_MSK_ALL); + val &= ~IPA_REG_ENDP_ROUTER_HASH_MSK_ALL; iowrite32(val, ipa->reg_virt + offset); }