From 60c40b06fa68694dd08a1a0038ea8b9de3f3b1ca Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Tue, 1 Aug 2023 14:38:26 +0800 Subject: [PATCH 1/6] mailbox: pcc: Add support for platform notification handling Currently, PCC driver doesn't support the processing of platform notification for type 4 PCC subspaces. According to ACPI specification, if platform sends a notification to OSPM, it must clear the command complete bit and trigger platform interrupt. OSPM needs to check whether the command complete bit is cleared, clear platform interrupt, process command, and then set the command complete and ring doorbell to the Platform. Let us stash the value of the pcc type and use the same while processing the interrupt of the channel. We also need to set the command complete bit and ring doorbell in the interrupt handler for the type 4 channel to complete the communication flow after processing the notification from the Platform. Signed-off-by: Huisong Li Reviewed-by: Hanjun Guo Link: https://lore.kernel.org/r/20230801063827.25336-2-lihuisong@huawei.com Signed-off-by: Sudeep Holla --- drivers/mailbox/pcc.c | 50 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index a44d4b3e5beb..80310b48bfb6 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -91,6 +91,7 @@ struct pcc_chan_reg { * @cmd_update: PCC register bundle for the command complete update register * @error: PCC register bundle for the error status register * @plat_irq: platform interrupt + * @type: PCC subspace type */ struct pcc_chan_info { struct pcc_mbox_chan chan; @@ -100,12 +101,15 @@ struct pcc_chan_info { struct pcc_chan_reg cmd_update; struct pcc_chan_reg error; int plat_irq; + u8 type; }; #define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan) static struct pcc_chan_info *chan_info; static int pcc_chan_count; +static int pcc_send_data(struct mbox_chan *chan, void *data); + /* * PCC can be used with perf critical drivers such as CPPC * So it makes sense to locally cache the virtual address and @@ -221,6 +225,34 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags) return acpi_register_gsi(NULL, interrupt, trigger, polarity); } +static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) +{ + u64 val; + int ret; + + ret = pcc_chan_reg_read(&pchan->cmd_complete, &val); + if (ret) + return false; + + if (!pchan->cmd_complete.gas) + return true; + + /* + * Judge if the channel respond the interrupt based on the value of + * command complete. + */ + val &= pchan->cmd_complete.status_mask; + /* + * If this is PCC slave subspace channel, and the command complete + * bit 0 indicates that Platform is sending a notification and OSPM + * needs to respond this interrupt to process this command. + */ + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) + return !val; + + return !!val; +} + /** * pcc_mbox_irq - PCC mailbox interrupt handler * @irq: interrupt number @@ -236,17 +268,9 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) int ret; pchan = chan->con_priv; - - ret = pcc_chan_reg_read(&pchan->cmd_complete, &val); - if (ret) + if (!pcc_mbox_cmd_complete_check(pchan)) return IRQ_NONE; - if (val) { /* Ensure GAS exists and value is non-zero */ - val &= pchan->cmd_complete.status_mask; - if (!val) - return IRQ_NONE; - } - ret = pcc_chan_reg_read(&pchan->error, &val); if (ret) return IRQ_NONE; @@ -262,6 +286,13 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) mbox_chan_received_data(chan, NULL); + /* + * The PCC slave subspace channel needs to set the command complete bit + * and ring doorbell after processing message. + */ + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) + pcc_send_data(chan, NULL); + return IRQ_HANDLED; } @@ -698,6 +729,7 @@ static int pcc_mbox_probe(struct platform_device *pdev) pcc_parse_subspace_shmem(pchan, pcct_entry); + pchan->type = pcct_entry->type; pcct_entry = (struct acpi_subtable_header *) ((unsigned long) pcct_entry + pcct_entry->length); } From 3db174e478cb0bb34888c20a531608b70aec9c1f Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Tue, 1 Aug 2023 14:38:27 +0800 Subject: [PATCH 2/6] mailbox: pcc: Support shared interrupt for multiple subspaces If the platform acknowledge interrupt is level triggered, then it can be shared by multiple subspaces provided each one has a unique platform interrupt ack preserve and ack set masks. If it can be shared, then we can request the irq with IRQF_SHARED and IRQF_ONESHOT flags. The first one indicating it can be shared and the latter one to keep the interrupt disabled until the hardirq handler finished. Further, since there is no way to detect if the interrupt is for a given channel as the interrupt ack preserve and ack set masks are for clearing the interrupt and not for reading the status(in case Irq Ack register may be write-only on some platforms), we need a way to identify if the given channel is in use and expecting the interrupt. PCC type0, type1 and type5 do not support shared level triggered interrupt. The methods of determining whether a given channel for remaining types should respond to an interrupt are as follows: - type2: Whether the interrupt belongs to a given channel is only determined by the status field in Generic Communications Channel Shared Memory Region, which is done in rx_callback of PCC client. - type3: This channel checks chan_in_use flag first and then checks the command complete bit(value '1' indicates that the command has been completed). - type4: Platform ensure that the default value of the command complete bit corresponding to the type4 channel is '1'. This command complete bit is '0' when receive a platform notification. The new field, 'chan_in_use' is used by the type only support the communication from OSPM to Platform (like type3) and should be completely ignored by other types so as to avoid too many type unnecessary checks in IRQ handler. Signed-off-by: Huisong Li Reviewed-by: Hanjun Guo Link: https://lore.kernel.org/r/20230801063827.25336-3-lihuisong@huawei.com Signed-off-by: Sudeep Holla --- drivers/mailbox/pcc.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 80310b48bfb6..94885e411085 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -92,6 +92,13 @@ struct pcc_chan_reg { * @error: PCC register bundle for the error status register * @plat_irq: platform interrupt * @type: PCC subspace type + * @plat_irq_flags: platform interrupt flags + * @chan_in_use: this flag is used just to check if the interrupt needs + * handling when it is shared. Since only one transfer can occur + * at a time and mailbox takes care of locking, this flag can be + * accessed without a lock. Note: the type only support the + * communication from OSPM to Platform, like type3, use it, and + * other types completely ignore it. */ struct pcc_chan_info { struct pcc_mbox_chan chan; @@ -102,6 +109,8 @@ struct pcc_chan_info { struct pcc_chan_reg error; int plat_irq; u8 type; + unsigned int plat_irq_flags; + bool chan_in_use; }; #define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan) @@ -225,6 +234,12 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags) return acpi_register_gsi(NULL, interrupt, trigger, polarity); } +static bool pcc_chan_plat_irq_can_be_shared(struct pcc_chan_info *pchan) +{ + return (pchan->plat_irq_flags & ACPI_PCCT_INTERRUPT_MODE) == + ACPI_LEVEL_SENSITIVE; +} + static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) { u64 val; @@ -242,6 +257,7 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) * command complete. */ val &= pchan->cmd_complete.status_mask; + /* * If this is PCC slave subspace channel, and the command complete * bit 0 indicates that Platform is sending a notification and OSPM @@ -268,6 +284,10 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) int ret; pchan = chan->con_priv; + if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE && + !pchan->chan_in_use) + return IRQ_NONE; + if (!pcc_mbox_cmd_complete_check(pchan)) return IRQ_NONE; @@ -289,9 +309,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) /* * The PCC slave subspace channel needs to set the command complete bit * and ring doorbell after processing message. + * + * The PCC master subspace channel clears chan_in_use to free channel. */ if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) pcc_send_data(chan, NULL); + pchan->chan_in_use = false; return IRQ_HANDLED; } @@ -371,7 +394,11 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) if (ret) return ret; - return pcc_chan_reg_read_modify_write(&pchan->db); + ret = pcc_chan_reg_read_modify_write(&pchan->db); + if (!ret && pchan->plat_irq > 0) + pchan->chan_in_use = true; + + return ret; } /** @@ -384,11 +411,14 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) static int pcc_startup(struct mbox_chan *chan) { struct pcc_chan_info *pchan = chan->con_priv; + unsigned long irqflags; int rc; if (pchan->plat_irq > 0) { - rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq, 0, - MBOX_IRQ_NAME, chan); + irqflags = pcc_chan_plat_irq_can_be_shared(pchan) ? + IRQF_SHARED | IRQF_ONESHOT : 0; + rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq, + irqflags, MBOX_IRQ_NAME, chan); if (unlikely(rc)) { dev_err(chan->mbox->dev, "failed to register PCC interrupt %d\n", pchan->plat_irq); @@ -494,6 +524,7 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan, pcct_ss->platform_interrupt); return -EINVAL; } + pchan->plat_irq_flags = pcct_ss->flags; if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss; @@ -515,6 +546,12 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan, "PLAT IRQ ACK"); } + if (pcc_chan_plat_irq_can_be_shared(pchan) && + !pchan->plat_irq_ack.gas) { + pr_err("PCC subspace has level IRQ with no ACK register\n"); + return -EINVAL; + } + return ret; } From 55d235ebb684b993b3247740c1c8e273f8af4a54 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 27 Sep 2023 17:26:10 +0100 Subject: [PATCH 3/6] ACPI: PCC: Add PCC shared memory region command and status bitfields Define the common macros to use when referring to various bitfields in the PCC generic communications channel command and status fields. Currently different drivers that need to use these bitfields have defined these locally. This common macro is intended to consolidate and replace those. Cc: "Rafael J. Wysocki" Link: https://lore.kernel.org/r/20230927-pcc_defines-v2-1-0b8ffeaef2e5@arm.com Signed-off-by: Sudeep Holla --- include/acpi/pcc.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/acpi/pcc.h b/include/acpi/pcc.h index 73e806fe7ce7..9b373d172a77 100644 --- a/include/acpi/pcc.h +++ b/include/acpi/pcc.h @@ -18,7 +18,20 @@ struct pcc_mbox_chan { u16 min_turnaround_time; }; +/* Generic Communications Channel Shared Memory Region */ +#define PCC_SIGNATURE 0x50434300 +/* Generic Communications Channel Command Field */ +#define PCC_CMD_GENERATE_DB_INTR BIT(15) +/* Generic Communications Channel Status Field */ +#define PCC_STATUS_CMD_COMPLETE BIT(0) +#define PCC_STATUS_SCI_DOORBELL BIT(1) +#define PCC_STATUS_ERROR BIT(2) +#define PCC_STATUS_PLATFORM_NOTIFY BIT(3) +/* Initiator Responder Communications Channel Flags */ +#define PCC_CMD_COMPLETION_NOTIFY BIT(0) + #define MAX_PCC_SUBSPACES 256 + #ifdef CONFIG_PCC extern struct pcc_mbox_chan * pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id); From 89a4ad1f437c049534891c3d83cd96d7c7debd2a Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 27 Sep 2023 17:26:11 +0100 Subject: [PATCH 4/6] i2c: xgene-slimpro: Migrate to use generic PCC shmem related macros Use the newly defined common and generic PCC shared memory region related macros in this driver to replace the locally defined ones. Reviewed-by: Andi Shyti Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/20230927-pcc_defines-v2-2-0b8ffeaef2e5@arm.com Signed-off-by: Sudeep Holla --- drivers/i2c/busses/i2c-xgene-slimpro.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index fbc1ffbd2fa7..658396c9eeab 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -91,14 +91,6 @@ #define SLIMPRO_IIC_MSG_DWORD_COUNT 3 -/* PCC related defines */ -#define PCC_SIGNATURE 0x50424300 -#define PCC_STS_CMD_COMPLETE BIT(0) -#define PCC_STS_SCI_DOORBELL BIT(1) -#define PCC_STS_ERR BIT(2) -#define PCC_STS_PLAT_NOTIFY BIT(3) -#define PCC_CMD_GENERATE_DB_INT BIT(15) - struct slimpro_i2c_dev { struct i2c_adapter adapter; struct device *dev; @@ -160,11 +152,11 @@ static void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg) /* Check if platform sends interrupt */ if (!xgene_word_tst_and_clr(&generic_comm_base->status, - PCC_STS_SCI_DOORBELL)) + PCC_STATUS_SCI_DOORBELL)) return; if (xgene_word_tst_and_clr(&generic_comm_base->status, - PCC_STS_CMD_COMPLETE)) { + PCC_STATUS_CMD_COMPLETE)) { msg = generic_comm_base + 1; /* Response message msg[1] contains the return value. */ @@ -186,10 +178,10 @@ static void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg) cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); WRITE_ONCE(generic_comm_base->command, - cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INT)); + cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR)); status = le16_to_cpu(READ_ONCE(generic_comm_base->status)); - status &= ~PCC_STS_CMD_COMPLETE; + status &= ~PCC_STATUS_CMD_COMPLETE; WRITE_ONCE(generic_comm_base->status, cpu_to_le16(status)); /* Copy the message to the PCC comm space */ From 2cf39b806be74661cc347e99796c97d9f54b7c42 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 27 Sep 2023 17:26:12 +0100 Subject: [PATCH 5/6] hwmon: (xgene) Migrate to use generic PCC shmem related macros Use the newly defined common and generic PCC shared memory region related macros in this driver to replace the locally defined ones. Cc: Jean Delvare Acked-by: Guenter Roeck Link: https://lore.kernel.org/r/20230927-pcc_defines-v2-3-0b8ffeaef2e5@arm.com Signed-off-by: Sudeep Holla --- drivers/hwmon/xgene-hwmon.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c index 78d9f52e2a71..1ccdd61b6d13 100644 --- a/drivers/hwmon/xgene-hwmon.c +++ b/drivers/hwmon/xgene-hwmon.c @@ -57,12 +57,6 @@ (MSG_TYPE_SET(MSG_TYPE_PWRMGMT) | \ MSG_SUBTYPE_SET(hndl) | TPC_CMD_SET(cmd) | type) -/* PCC defines */ -#define PCC_SIGNATURE_MASK 0x50424300 -#define PCCC_GENERATE_DB_INT BIT(15) -#define PCCS_CMD_COMPLETE BIT(0) -#define PCCS_SCI_DOORBEL BIT(1) -#define PCCS_PLATFORM_NOTIFICATION BIT(3) /* * Arbitrary retries in case the remote processor is slow to respond * to PCC commands @@ -142,15 +136,15 @@ static int xgene_hwmon_pcc_rd(struct xgene_hwmon_dev *ctx, u32 *msg) /* Write signature for subspace */ WRITE_ONCE(generic_comm_base->signature, - cpu_to_le32(PCC_SIGNATURE_MASK | ctx->mbox_idx)); + cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); /* Write to the shared command region */ WRITE_ONCE(generic_comm_base->command, - cpu_to_le16(MSG_TYPE(msg[0]) | PCCC_GENERATE_DB_INT)); + cpu_to_le16(MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR)); /* Flip CMD COMPLETE bit */ val = le16_to_cpu(READ_ONCE(generic_comm_base->status)); - val &= ~PCCS_CMD_COMPLETE; + val &= ~PCC_STATUS_CMD_COMPLETE; WRITE_ONCE(generic_comm_base->status, cpu_to_le16(val)); /* Copy the message to the PCC comm space */ @@ -544,7 +538,7 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg) msg = generic_comm_base + 1; /* Check if platform sends interrupt */ if (!xgene_word_tst_and_clr(&generic_comm_base->status, - PCCS_SCI_DOORBEL)) + PCC_STATUS_SCI_DOORBELL)) return; /* @@ -566,7 +560,7 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg) TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) { /* Check if platform completes command */ if (xgene_word_tst_and_clr(&generic_comm_base->status, - PCCS_CMD_COMPLETE)) { + PCC_STATUS_CMD_COMPLETE)) { ctx->sync_msg.msg = ((u32 *)msg)[0]; ctx->sync_msg.param1 = ((u32 *)msg)[1]; ctx->sync_msg.param2 = ((u32 *)msg)[2]; From a46e42c097982e258f89c64c5f52f30994bcfeda Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 27 Sep 2023 17:26:13 +0100 Subject: [PATCH 6/6] soc: kunpeng_hccs: Migrate to use generic PCC shmem related macros Use the newly defined common and generic PCC shared memory region related macros in this driver to replace the locally defined ones. Cc: Huisong Li Reviewed-by: Huisong Li Link: https://lore.kernel.org/r/20230927-pcc_defines-v2-4-0b8ffeaef2e5@arm.com Signed-off-by: Sudeep Holla --- drivers/soc/hisilicon/kunpeng_hccs.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index f3810d9d1caa..27a96cafd1ea 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -31,10 +31,6 @@ #include "kunpeng_hccs.h" -/* PCC defines */ -#define HCCS_PCC_SIGNATURE_MASK 0x50434300 -#define HCCS_PCC_STATUS_CMD_COMPLETE BIT(0) - /* * Arbitrary retries in case the remote processor is slow to respond * to PCC commands @@ -187,7 +183,7 @@ static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) * deadline_us(timeout_us) until PCC command complete bit is set(cond) */ ret = readw_poll_timeout(&comm_base->status, status, - status & HCCS_PCC_STATUS_CMD_COMPLETE, + status & PCC_STATUS_CMD_COMPLETE, HCCS_POLL_STATUS_TIME_INTERVAL_US, cl_info->deadline_us); if (unlikely(ret)) @@ -208,7 +204,7 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, int ret; /* Write signature for this subspace */ - tmp.signature = HCCS_PCC_SIGNATURE_MASK | hdev->chan_id; + tmp.signature = PCC_SIGNATURE | hdev->chan_id; /* Write to the shared command region */ tmp.command = cmd; /* Clear cmd complete bit */