Skip to content

Commit 8e41bfa

Browse files
Vedashree Vidwansnvmochs
authored andcommitted
NVIDIA: VR: SAUCE: firmware: smccc: lfa: handle LFA_BUSY and improve SMC retry pacing
Align LFA_PRIME and LFA_ACTIVATE polling with DEN0147 and reduce long udelay-based busy-waiting where the calling context allows it. LFA_BUSY: - PRIME (§2.5): unexpected for this driver; log with pr_warn and return (concurrent LFA_PRIME on another CPU). No retry loop. - ACTIVATE (§2.6): activation was postponed; retry within the time budget using an implementation-defined delay. Use udelay (LFA_SMC_RETRY_SLEEP_MIN_US) for every attempt so the same path is valid under stop_machine / IRQs off (usleep_range would not be). On budget expiry, return -ETIMEDOUT. LFA_ACTIVATE call_again: - drop udelay between SMC calls; progress is driven by re-invoking LFA_ACTIVATE. Use cpu_relax() between attempts (include linux/preempt.h). LFA_PRIME call_again: - replace tight udelay polling with usleep_range() over LFA_SMC_RETRY_SLEEP_{MIN,MAX}_US so multi-second priming does not burn CPU. Consolidate timing: - one 20s wall-clock budget (LFA_SMC_BUDGET_US) for both PRIME and ACTIVATE retry loops; shared min/max for PRIME usleep_range and ACTIVATE LFA_BUSY udelay length. Fix prime_fw_image() success path returning an uninitialized value; return 0 on success. Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com> Signed-off-by: Nirmoy Das <nirmoyd@nvidia.com> Acked-by: Matthew R. Ochs <mochs@nvidia.com> Acked-by: Carol L. Soto <csoto@nvidia.com> Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
1 parent 93cd522 commit 8e41bfa

1 file changed

Lines changed: 48 additions & 13 deletions

File tree

drivers/firmware/smccc/lfa_fw.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/nmi.h>
2121
#include <linux/ktime.h>
2222
#include <linux/delay.h>
23+
#include <linux/preempt.h>
2324
#include <linux/acpi.h>
2425
#include <linux/platform_device.h>
2526

@@ -43,13 +44,16 @@
4344
#define LFA_PRIME_CALL_AGAIN BIT(0)
4445
#define LFA_ACTIVATE_CALL_AGAIN BIT(0)
4546

46-
/* Prime loop limits, TODO: tune after testing */
47-
#define LFA_PRIME_BUDGET_US 30000000 /* 30s cap */
48-
#define LFA_PRIME_POLL_DELAY_US 10 /* 10us between polls */
49-
50-
/* Activation loop limits, TODO: tune after testing */
51-
#define LFA_ACTIVATE_BUDGET_US 20000000 /* 20s cap */
52-
#define LFA_ACTIVATE_POLL_DELAY_US 10 /* 10us between polls */
47+
/*
48+
* SMC retry timeouts and pacing.
49+
*
50+
* Budget: max wall time for PRIME call_again and for ACTIVATE (call_again + LFA_BUSY).
51+
* PRIME call_again: usleep_range(min, max). ACTIVATE LFA_BUSY: udelay(min) in all
52+
* contexts (including stop_machine with IRQs off). ACTIVATE call_again: cpu_relax().
53+
*/
54+
#define LFA_SMC_BUDGET_US 20000000 /* 20s */
55+
#define LFA_SMC_RETRY_SLEEP_MIN_US 100
56+
#define LFA_SMC_RETRY_SLEEP_MAX_US 200
5357

5458
/* LFA return values */
5559
#define LFA_SUCCESS 0
@@ -111,6 +115,7 @@ struct image_props {
111115
struct kobject *image_dir;
112116
struct kobj_attribute image_attrs[LFA_ATTR_NR_IMAGES];
113117
};
118+
114119
static LIST_HEAD(lfa_fw_images);
115120

116121
/* A UUID split over two 64-bit registers */
@@ -233,7 +238,7 @@ static int call_lfa_activate(void *data)
233238
struct image_props *attrs = data;
234239
struct arm_smccc_1_2_regs args = { 0 };
235240
struct arm_smccc_1_2_regs res = { 0 };
236-
ktime_t end = ktime_add_us(ktime_get(), LFA_ACTIVATE_BUDGET_US);
241+
ktime_t end = ktime_add_us(ktime_get(), LFA_SMC_BUDGET_US);
237242

238243
args.a0 = LFA_1_0_FN_ACTIVATE;
239244
args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
@@ -252,16 +257,32 @@ static int call_lfa_activate(void *data)
252257
arm_smccc_1_2_invoke(&args, &res);
253258

254259
if ((long)res.a0 < 0) {
260+
/*
261+
* DEN0147 §2.6: LFA_BUSY means live activation was
262+
* postponed and must be attempted again later; prime
263+
* status is unchanged. Inter-attempt delay is
264+
* IMPLEMENTATION DEFINED — udelay works here even under
265+
* stop_machine (usleep_range would not).
266+
*/
267+
if ((long)res.a0 == -LFA_BUSY) {
268+
if (ktime_before(ktime_get(), end)) {
269+
udelay(LFA_SMC_RETRY_SLEEP_MIN_US);
270+
continue;
271+
}
272+
pr_err("ACTIVATE for image %s timed out while LFA_BUSY\n",
273+
attrs->image_name);
274+
return -ETIMEDOUT;
275+
}
255276
pr_err("ACTIVATE for image %s failed: %s\n",
256277
attrs->image_name, lfa_error_strings[-res.a0]);
257278
return res.a0;
258279
}
259280
if (!(res.a1 & LFA_ACTIVATE_CALL_AGAIN))
260281
break; /* ACTIVATE successful */
261282

262-
/* SMC returned with call_again flag set */
283+
/* SMC returned with call_again flag set — re-enter ACTIVATE soon */
263284
if (ktime_before(ktime_get(), end)) {
264-
udelay(LFA_ACTIVATE_POLL_DELAY_US);
285+
cpu_relax();
265286
continue;
266287
}
267288

@@ -297,7 +318,7 @@ static int prime_fw_image(struct image_props *attrs)
297318
{
298319
struct arm_smccc_1_2_regs args = { 0 };
299320
struct arm_smccc_1_2_regs res = { 0 };
300-
ktime_t end = ktime_add_us(ktime_get(), LFA_PRIME_BUDGET_US);
321+
ktime_t end = ktime_add_us(ktime_get(), LFA_SMC_BUDGET_US);
301322
int ret;
302323

303324
mutex_lock(&lfa_lock);
@@ -330,6 +351,19 @@ static int prime_fw_image(struct image_props *attrs)
330351
arm_smccc_1_2_invoke(&args, &res);
331352

332353
if ((long)res.a0 < 0) {
354+
if ((long)res.a0 == -LFA_BUSY) {
355+
/*
356+
* DEN0147 §2.5: LFA_BUSY means LFA_PRIME is executing
357+
* concurrently on another CPU. This driver does not
358+
* issue PRIME for multiple components in parallel and
359+
* does not expect concurrent PRIME from elsewhere.
360+
*/
361+
pr_warn("LFA_PRIME returned LFA_BUSY for image %s (another CPU may be in LFA_PRIME; unexpected for this driver)\n",
362+
attrs->image_name);
363+
mutex_unlock(&lfa_lock);
364+
365+
return res.a0;
366+
}
333367
pr_err("LFA_PRIME for image %s failed: %s\n",
334368
attrs->image_name, lfa_error_strings[-res.a0]);
335369
mutex_unlock(&lfa_lock);
@@ -341,7 +375,8 @@ static int prime_fw_image(struct image_props *attrs)
341375

342376
/* SMC returned with call_again flag set */
343377
if (ktime_before(ktime_get(), end)) {
344-
udelay(LFA_PRIME_POLL_DELAY_US);
378+
usleep_range(LFA_SMC_RETRY_SLEEP_MIN_US,
379+
LFA_SMC_RETRY_SLEEP_MAX_US);
345380
continue;
346381
}
347382

@@ -355,7 +390,7 @@ static int prime_fw_image(struct image_props *attrs)
355390
}
356391

357392
mutex_unlock(&lfa_lock);
358-
return ret;
393+
return 0;
359394
}
360395

361396
static ssize_t name_show(struct kobject *kobj, struct kobj_attribute *attr,

0 commit comments

Comments
 (0)