From 40eaa8c0cbba4a27668c7e01373ccd5b38381e2f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 23 Jan 2023 15:53:54 +0900 Subject: [PATCH 1/5] soc: apple: rtkit: Add apple_rtkit_idle() function This is yet another low power mode, used by DCP. Reviewed-by: Eric Curtin Reviewed-by: Sven Peter Signed-off-by: Hector Martin --- drivers/soc/apple/rtkit.c | 21 +++++++++++++++++++++ include/linux/soc/apple/rtkit.h | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index 8ec74d7539eb..efb1fa77dff2 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -9,6 +9,7 @@ enum { APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */ APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */ + APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */ APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */ APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */ }; @@ -881,6 +882,26 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk) } EXPORT_SYMBOL_GPL(apple_rtkit_shutdown); +int apple_rtkit_idle(struct apple_rtkit *rtk) +{ + int ret; + + /* if OFF is used here the co-processor will not wake up again */ + ret = apple_rtkit_set_ap_power_state(rtk, + APPLE_RTKIT_PWR_STATE_IDLE); + if (ret) + return ret; + + ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE); + if (ret) + return ret; + + rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE; + rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE; + return 0; +} +EXPORT_SYMBOL_GPL(apple_rtkit_idle); + int apple_rtkit_quiesce(struct apple_rtkit *rtk) { int ret; diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h index c9cabb679cd1..a2446b45ed7f 100644 --- a/include/linux/soc/apple/rtkit.h +++ b/include/linux/soc/apple/rtkit.h @@ -104,6 +104,11 @@ int apple_rtkit_wake(struct apple_rtkit *rtk); */ int apple_rtkit_shutdown(struct apple_rtkit *rtk); +/* + * Put the co-processor into idle mode + */ +int apple_rtkit_idle(struct apple_rtkit *rtk); + /* * Checks if RTKit is running and ready to handle messages. */ From c289d5bce8521352a596f3ad27cd6d70b9f9f821 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 23 Jan 2023 15:51:25 +0900 Subject: [PATCH 2/5] soc: apple: apple-pmgr-pwrstate: Switch to IRQ-safe mode This requires changing the reset path locking primitives to the spinlock path in genpd, instead of the mutex path. Reviewed-by: Eric Curtin Reviewed-by: Sven Peter Signed-off-by: Hector Martin --- drivers/soc/apple/apple-pmgr-pwrstate.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c index e1122288409a..a3e2bc1d2686 100644 --- a/drivers/soc/apple/apple-pmgr-pwrstate.c +++ b/drivers/soc/apple/apple-pmgr-pwrstate.c @@ -116,8 +116,9 @@ static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd) static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + unsigned long flags; - mutex_lock(&ps->genpd.mlock); + spin_lock_irqsave(&ps->genpd.slock, flags); if (ps->genpd.status == GENPD_STATE_OFF) dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset); @@ -129,7 +130,7 @@ static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, APPLE_PMGR_RESET); - mutex_unlock(&ps->genpd.mlock); + spin_unlock_irqrestore(&ps->genpd.slock, flags); return 0; } @@ -137,8 +138,9 @@ static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + unsigned long flags; - mutex_lock(&ps->genpd.mlock); + spin_lock_irqsave(&ps->genpd.slock, flags); dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset); regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0); @@ -147,7 +149,7 @@ static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigne if (ps->genpd.status == GENPD_STATE_OFF) dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset); - mutex_unlock(&ps->genpd.mlock); + spin_unlock_irqrestore(&ps->genpd.slock, flags); return 0; } @@ -222,6 +224,7 @@ static int apple_pmgr_ps_probe(struct platform_device *pdev) return ret; } + ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE; ps->genpd.name = name; ps->genpd.power_on = apple_pmgr_ps_power_on; ps->genpd.power_off = apple_pmgr_ps_power_off; From 4435d63f172851b57a6a0943b73a6b8055a9356f Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 21 Jan 2023 16:42:53 +0900 Subject: [PATCH 3/5] soc: apple: rtkit: Add a private pointer to apple_rtkit_shmem This allows downstream consumers to keep track of private data for shmem mappings. In particular, the Rust abstraction will use this to safely drop data associated with a mapping when it is unmapped. Signed-off-by: Asahi Lina Reviewed-by: Sven Peter Reviewed-by: Eric Curtin Signed-off-by: Hector Martin --- include/linux/soc/apple/rtkit.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h index a2446b45ed7f..927b214ef1c6 100644 --- a/include/linux/soc/apple/rtkit.h +++ b/include/linux/soc/apple/rtkit.h @@ -22,6 +22,7 @@ * @size: Size of the shared memory buffer. * @iova: Device VA of shared memory buffer. * @is_mapped: Shared memory buffer is managed by the co-processor. + * @private: Private data pointer for the parent driver. */ struct apple_rtkit_shmem { @@ -30,6 +31,7 @@ struct apple_rtkit_shmem { size_t size; dma_addr_t iova; bool is_mapped; + void *private; }; /* From b3892860f50920ea46342d32bf51323877365082 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 21 Jan 2023 16:41:35 +0900 Subject: [PATCH 4/5] soc: apple: rtkit: Export non-devm init/free functions While we normally encourage devm usage by drivers, some consumers (and in particular the upcoming Rust abstractions) might want to manually manage memory. Export the raw functions to make this possible. Signed-off-by: Asahi Lina Reviewed-by: Sven Peter Reviewed-by: Eric Curtin Signed-off-by: Hector Martin --- drivers/soc/apple/rtkit.c | 15 ++++++++++----- include/linux/soc/apple/rtkit.h | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index efb1fa77dff2..35ec35aa500d 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -699,7 +699,7 @@ static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk) return 0; } -static struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, +struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops) { @@ -751,6 +751,7 @@ free_rtk: kfree(rtk); return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(apple_rtkit_init); static int apple_rtkit_wait_for_completion(struct completion *c) { @@ -947,10 +948,8 @@ int apple_rtkit_wake(struct apple_rtkit *rtk) } EXPORT_SYMBOL_GPL(apple_rtkit_wake); -static void apple_rtkit_free(void *data) +void apple_rtkit_free(struct apple_rtkit *rtk) { - struct apple_rtkit *rtk = data; - mbox_free_channel(rtk->mbox_chan); destroy_workqueue(rtk->wq); @@ -961,6 +960,12 @@ static void apple_rtkit_free(void *data) kfree(rtk->syslog_msg_buffer); kfree(rtk); } +EXPORT_SYMBOL_GPL(apple_rtkit_free); + +static void apple_rtkit_free_wrapper(void *data) +{ + apple_rtkit_free(data); +} struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie, const char *mbox_name, int mbox_idx, @@ -973,7 +978,7 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie, if (IS_ERR(rtk)) return rtk; - ret = devm_add_action_or_reset(dev, apple_rtkit_free, rtk); + ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk); if (ret) return ERR_PTR(ret); diff --git a/include/linux/soc/apple/rtkit.h b/include/linux/soc/apple/rtkit.h index 927b214ef1c6..fc456f75c131 100644 --- a/include/linux/soc/apple/rtkit.h +++ b/include/linux/soc/apple/rtkit.h @@ -79,6 +79,25 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie, const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops); +/* + * Non-devm version of devm_apple_rtkit_init. Must be freed with + * apple_rtkit_free. + * + * @dev: Pointer to the device node this coprocessor is assocated with + * @cookie: opaque cookie passed to all functions defined in rtkit_ops + * @mbox_name: mailbox name used to communicate with the co-processor + * @mbox_idx: mailbox index to be used if mbox_name is NULL + * @ops: pointer to rtkit_ops to be used for this co-processor + */ +struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie, + const char *mbox_name, int mbox_idx, + const struct apple_rtkit_ops *ops); + +/* + * Free an instance of apple_rtkit. + */ +void apple_rtkit_free(struct apple_rtkit *rtk); + /* * Reinitialize internal structures. Must only be called with the co-processor * is held in reset. From 22991d8d57251509b8ee5c0b3dac04506fe5ed7a Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Mon, 23 Jan 2023 12:17:28 +0900 Subject: [PATCH 5/5] soc: apple: rtkit: Add register dump decoding to crashlog When the coprocessor crashes, it's useful to get a proper register dump so we can find out what the firmware was doing. Add a decoder for this. Originally this had ESR decoding by reusing the ARM64 arch header for this, but that introduces some module linking and cross-arch compilation issues, so let's leave that out for now. Reviewed-by: Sven Peter Reviewed-by: Eric Curtin Signed-off-by: Asahi Lina Signed-off-by: Hector Martin --- drivers/soc/apple/rtkit-crashlog.c | 93 ++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/soc/apple/rtkit-crashlog.c b/drivers/soc/apple/rtkit-crashlog.c index 732deed64660..dfa74b32eda2 100644 --- a/drivers/soc/apple/rtkit-crashlog.c +++ b/drivers/soc/apple/rtkit-crashlog.c @@ -13,6 +13,17 @@ #define APPLE_RTKIT_CRASHLOG_VERSION FOURCC('C', 'v', 'e', 'r') #define APPLE_RTKIT_CRASHLOG_MBOX FOURCC('C', 'm', 'b', 'x') #define APPLE_RTKIT_CRASHLOG_TIME FOURCC('C', 't', 'i', 'm') +#define APPLE_RTKIT_CRASHLOG_REGS FOURCC('C', 'r', 'g', '8') + +/* For COMPILE_TEST on non-ARM64 architectures */ +#ifndef PSR_MODE_EL0t +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_MASK 0x0000000f +#endif struct apple_rtkit_crashlog_header { u32 fourcc; @@ -31,6 +42,24 @@ struct apple_rtkit_crashlog_mbox_entry { }; static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18); +struct apple_rtkit_crashlog_regs { + u32 unk_0; + u32 unk_4; + u64 regs[31]; + u64 sp; + u64 pc; + u64 psr; + u64 cpacr; + u64 fpsr; + u64 fpcr; + u64 unk[64]; + u64 far; + u64 unk_X; + u64 esr; + u64 unk_Z; +}; +static_assert(sizeof(struct apple_rtkit_crashlog_regs) == 0x350); + static void apple_rtkit_crashlog_dump_str(struct apple_rtkit *rtk, u8 *bfr, size_t size) { @@ -94,6 +123,66 @@ static void apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit *rtk, u8 *bfr, } } +static void apple_rtkit_crashlog_dump_regs(struct apple_rtkit *rtk, u8 *bfr, + size_t size) +{ + struct apple_rtkit_crashlog_regs regs; + const char *el; + int i; + + if (size < sizeof(regs)) { + dev_warn(rtk->dev, "RTKit: Regs section too small: 0x%zx", size); + return; + } + + memcpy(®s, bfr, sizeof(regs)); + + switch (regs.psr & PSR_MODE_MASK) { + case PSR_MODE_EL0t: + el = "EL0t"; + break; + case PSR_MODE_EL1t: + el = "EL1t"; + break; + case PSR_MODE_EL1h: + el = "EL1h"; + break; + case PSR_MODE_EL2t: + el = "EL2t"; + break; + case PSR_MODE_EL2h: + el = "EL2h"; + break; + default: + el = "unknown"; + break; + } + + dev_warn(rtk->dev, "RTKit: Exception dump:"); + dev_warn(rtk->dev, " == Exception taken from %s ==", el); + dev_warn(rtk->dev, " PSR = 0x%llx", regs.psr); + dev_warn(rtk->dev, " PC = 0x%llx\n", regs.pc); + dev_warn(rtk->dev, " ESR = 0x%llx\n", regs.esr); + dev_warn(rtk->dev, " FAR = 0x%llx\n", regs.far); + dev_warn(rtk->dev, " SP = 0x%llx\n", regs.sp); + dev_warn(rtk->dev, "\n"); + + for (i = 0; i < 31; i += 4) { + if (i < 28) + dev_warn(rtk->dev, + " x%02d-x%02d = %016llx %016llx %016llx %016llx\n", + i, i + 3, + regs.regs[i], regs.regs[i + 1], + regs.regs[i + 2], regs.regs[i + 3]); + else + dev_warn(rtk->dev, + " x%02d-x%02d = %016llx %016llx %016llx\n", i, i + 3, + regs.regs[i], regs.regs[i + 1], regs.regs[i + 2]); + } + + dev_warn(rtk->dev, "\n"); +} + void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size) { size_t offset; @@ -140,6 +229,10 @@ void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size) apple_rtkit_crashlog_dump_time(rtk, bfr + offset + 16, section_size); break; + case APPLE_RTKIT_CRASHLOG_REGS: + apple_rtkit_crashlog_dump_regs(rtk, bfr + offset + 16, + section_size); + break; default: dev_warn(rtk->dev, "RTKit: Unknown crashlog section: %x",