diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index e4c9a1ccd38a0..f6866af32adae 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -45,6 +45,8 @@ #include "nvme.h" #define APPLE_ANS_BOOT_TIMEOUT USEC_PER_SEC +/* RTKit handshake timeout for the T6050 ANS, see apple_nvme_alloc() */ +#define APPLE_NVME_T6050_HANDSHAKE_TIMEOUT_MS 10000 #define APPLE_ANS_COPROC_CPU_CONTROL 0x44 #define APPLE_ANS_COPROC_CPU_CONTROL_RUN BIT(4) @@ -2470,6 +2472,14 @@ static struct apple_nvme *apple_nvme_alloc(struct platform_device *pdev) goto out_detach_genpd; } + /* + * The T6050 ANS firmware handed over by iBoot can take about 3 s to + * answer the power-state and endpoint-map handshake. + */ + if (of_device_is_compatible(dev->of_node, "apple,t6050-nvme-ans2")) + apple_rtkit_set_handshake_timeout(anv->rtk, + APPLE_NVME_T6050_HANDSHAKE_TIMEOUT_MS); + ret = devm_add_action_or_reset(dev, apple_nvme_free_rtkit, anv); if (ret) goto out_detach_genpd; diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h index 0c5acb7fc7090..2ad4d96bec768 100644 --- a/drivers/soc/apple/rtkit-internal.h +++ b/drivers/soc/apple/rtkit-internal.h @@ -48,6 +48,8 @@ struct apple_rtkit { int boot_result; int version; + /* How long to wait for each handshake reply from the co-processor. */ + unsigned int handshake_timeout_ms; unsigned int iop_power_state; unsigned int ap_power_state; diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index 536ba515f826f..3b821415d54d8 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -118,6 +118,9 @@ enum { #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 +/* Default wait for each handshake reply, see apple_rtkit_set_handshake_timeout() */ +#define APPLE_RTKIT_HANDSHAKE_TIMEOUT_MS 1000 + struct apple_rtkit_rx_work { struct apple_rtkit *rtk; u8 ep; @@ -1401,6 +1404,7 @@ static struct apple_rtkit *__apple_rtkit_init(struct device *dev, void *cookie, rtk->dev = dev; rtk->cookie = cookie; rtk->ops = ops; + rtk->handshake_timeout_ms = APPLE_RTKIT_HANDSHAKE_TIMEOUT_MS; rtk->sync_syslog_ack = of_property_read_bool(dev->of_node, "apple,sync-syslog-ack"); INIT_KFIFO(rtk->sync_ack_fifo); @@ -1480,7 +1484,8 @@ struct apple_rtkit *apple_rtkit_init_adopted(struct device *dev, void *cookie, } EXPORT_SYMBOL_GPL(apple_rtkit_init_adopted); -static int apple_rtkit_wait_for_completion(struct completion *c); +static int apple_rtkit_wait_for_completion(struct apple_rtkit *rtk, + struct completion *c); /* * apple,sync-syslog-ack (AsahiLinux/linux#607): the mailbox can leave @@ -1494,9 +1499,9 @@ static int apple_rtkit_wait(struct apple_rtkit *rtk, struct completion *c) int ret; if (!rtk->sync_syslog_ack) - return apple_rtkit_wait_for_completion(c); + return apple_rtkit_wait_for_completion(rtk, c); - timeout = jiffies + msecs_to_jiffies(1000); + timeout = jiffies + msecs_to_jiffies(rtk->handshake_timeout_ms); do { ret = apple_rtkit_poll(rtk); if (ret < 0) @@ -1524,12 +1529,13 @@ struct apple_rtkit *apple_rtkit_init_adopted_with_buffers( } EXPORT_SYMBOL_GPL(apple_rtkit_init_adopted_with_buffers); -static int apple_rtkit_wait_for_completion(struct completion *c) +static int apple_rtkit_wait_for_completion(struct apple_rtkit *rtk, + struct completion *c) { + unsigned long timeout = msecs_to_jiffies(rtk->handshake_timeout_ms); long t; - t = wait_for_completion_interruptible_timeout(c, - msecs_to_jiffies(1000)); + t = wait_for_completion_interruptible_timeout(c, timeout); if (t < 0) return t; else if (t == 0) @@ -1538,6 +1544,13 @@ static int apple_rtkit_wait_for_completion(struct completion *c) return 0; } +void apple_rtkit_set_handshake_timeout(struct apple_rtkit *rtk, + unsigned int timeout_ms) +{ + rtk->handshake_timeout_ms = timeout_ms ?: APPLE_RTKIT_HANDSHAKE_TIMEOUT_MS; +} +EXPORT_SYMBOL_GPL(apple_rtkit_set_handshake_timeout); + int apple_rtkit_reinit(struct apple_rtkit *rtk) { unsigned long flags; @@ -1661,7 +1674,8 @@ static int apple_rtkit_boot_common(struct apple_rtkit *rtk, bool early_ap_power) /* PMP waits for CoreAnalytics setup before acknowledging IOP power. */ if (apple_rtkit_needs_coreanalytics(rtk) && test_bit(APPLE_RTKIT_EP_COREANALYTICS, rtk->endpoints)) { - ret = apple_rtkit_wait_for_completion(&rtk->coreanalytics_completion); + ret = apple_rtkit_wait_for_completion(rtk, + &rtk->coreanalytics_completion); if (ret) { dev_err(rtk->dev, "RTKit: CoreAnalytics readiness failed: %d\n", ret); return ret; diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h index 35508001fbea4..86cdb8426488d 100644 --- a/include/linux/soc/apple/rtkit.h +++ b/include/linux/soc/apple/rtkit.h @@ -197,6 +197,18 @@ void apple_rtkit_free_retaining_buffers(struct apple_rtkit *rtk); */ int apple_rtkit_reinit(struct apple_rtkit *rtk); +/* + * Set how long each handshake step (power state and endpoint map replies) + * waits for the co-processor, for one that is known to answer slowly. Call + * before apple_rtkit_boot() or apple_rtkit_wake(). Zero restores the default + * of 1000 ms. + * + * @rtk: Internal RTKit state initialized by apple_rtkit_init() + * @timeout_ms: Timeout in milliseconds + */ +void apple_rtkit_set_handshake_timeout(struct apple_rtkit *rtk, + unsigned int timeout_ms); + /* * Handle RTKit's boot process. Should be called after the CPU of the * co-processor has been started.