From 63e5afc86aeb1a55bdfd8fe6dd5f6fb5fb90ed1a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 30 Nov 2020 17:37:12 -0600 Subject: [PATCH] net: ipa: use Qtime for IPA v4.5 head-of-line time limit Extend ipa_reg_init_hol_block_timer_val() so it properly calculates the head-of-line block timeout to use for IPA v4.5. Introduce hol_block_timer_qtime_val() to compute the value to use for IPA v4.5, where Qtime is used as the basis of the timer. Call that function from hol_block_timer_val() for IPA v4.5. Both of these are private functions, so shorten their names a bit so they don't take up so much space on the line. Signed-off-by: Alex Elder Signed-off-by: Jakub Kicinski --- drivers/net/ipa/ipa_endpoint.c | 48 +++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index b4c884ccb77d..9f4be9812a1f 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -724,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; @@ -741,6 +774,9 @@ 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); @@ -786,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); }