lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251110150825.3548819-1-andrea.tomassetti@sipearl.com>
Date: Mon, 10 Nov 2025 16:08:21 +0100
From: Andrea Tomassetti <andrea.tomassetti@...earl.com>
To: <sudeep.holla@....com>, <jassisinghbrar@...il.com>, <rafael@...nel.org>
CC: Andrea Tomassetti <andrea.tomassetti@...earl.com>, <lenb@...nel.org>,
	<linux-acpi@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
	<olivierdautricourt@...il.com>, Thibault Cantori
	<thibault.cantori@...earl.com>, Olivier Dautricourt
	<olivier.dautricourt@...earl.com>
Subject: [PATCH] mailbox: pcc: support polling mode when there is no platform IRQ

The goal is to allow clients to submit a message in both irq and polling
mode of the pcc mailbox. The ACPI specification does not require a
platform irq for pcc channels. Let's implement the case where it is not
available.

peek_data is mapped to pcc_mbox_error_check_and_clear, so that it
returns true if no error occurred while the platform processed last
message, and therefore clients can fetch response data provided by the
platform.

Tested-by: Thibault Cantori <thibault.cantori@...earl.com>
Co-developed-by: Olivier Dautricourt <olivier.dautricourt@...earl.com>
Signed-off-by: Olivier Dautricourt <olivier.dautricourt@...earl.com>
Signed-off-by: Andrea Tomassetti <andrea.tomassetti@...earl.com>
---
 drivers/acpi/acpi_pcc.c | 77 ++++++++++++++++++++++++++++-------------
 drivers/mailbox/pcc.c   | 12 ++++++-
 2 files changed, 63 insertions(+), 26 deletions(-)

diff --git a/drivers/acpi/acpi_pcc.c b/drivers/acpi/acpi_pcc.c
index 97064e943768..ef5d7eae150b 100644
--- a/drivers/acpi/acpi_pcc.c
+++ b/drivers/acpi/acpi_pcc.c
@@ -51,7 +51,6 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
 {
 	struct pcc_data *data;
 	struct acpi_pcc_info *ctx = handler_context;
-	struct pcc_mbox_chan *pcc_chan;
 	static acpi_status ret;

 	data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -59,7 +58,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
 		return AE_NO_MEMORY;

 	data->cl.rx_callback = pcc_rx_callback;
-	data->cl.knows_txdone = true;
+	data->cl.knows_txdone = false;
 	data->ctx.length = ctx->length;
 	data->ctx.subspace_id = ctx->subspace_id;
 	data->ctx.internal_buffer = ctx->internal_buffer;
@@ -73,61 +72,89 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
 		goto err_free_data;
 	}

-	pcc_chan = data->pcc_chan;
-	if (!pcc_chan->mchan->mbox->txdone_irq) {
-		pr_err("This channel-%d does not support interrupt.\n",
-		       ctx->subspace_id);
-		ret = AE_SUPPORT;
-		goto err_free_channel;
-	}
-
 	*region_context = data;
 	return AE_OK;

-err_free_channel:
-	pcc_mbox_free_channel(data->pcc_chan);
 err_free_data:
 	kfree(data);

 	return ret;
 }

+static acpi_status
+acpi_pcc_send_msg_polling(struct pcc_data *data)
+{
+	int ret;
+
+	ret = mbox_send_message(data->pcc_chan->mchan, data->pcc_chan->shmem);
+	if (ret == -ETIME) {
+		pr_err("PCC command executed timeout!\n");
+		return AE_TIME;
+	}
+
+	if (ret < 0)
+		return AE_ERROR;
+
+	if (!mbox_client_peek_data(data->pcc_chan->mchan))
+		return AE_ERROR;
+
+	return AE_OK;
+}
+
+static acpi_status
+acpi_pcc_send_msg_irq(struct pcc_data *data)
+{
+	int ret;
+
+	ret = mbox_send_message(data->pcc_chan->mchan, NULL);
+	if (ret < 0)
+		return AE_ERROR;
+
+	ret = wait_for_completion_timeout(&data->done,
+					  usecs_to_jiffies(data->cl.tx_tout * USEC_PER_MSEC));
+	if (ret == 0) {
+		pr_err("PCC command executed timeout!\n");
+		return AE_TIME;
+	}
+
+	mbox_chan_txdone(data->pcc_chan->mchan, ret);
+
+	return AE_OK;
+}
+
 static acpi_status
 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
 			       u32 bits, acpi_integer *value,
 			       void *handler_context, void *region_context)
 {
-	int ret;
+	acpi_status ret;
 	struct pcc_data *data = region_context;
 	u64 usecs_lat;
+	bool use_polling = data->pcc_chan->mchan->mbox->txdone_poll;

 	reinit_completion(&data->done);

 	/* Write to Shared Memory */
 	memcpy_toio(data->pcc_chan->shmem, (void *)value, data->ctx.length);

-	ret = mbox_send_message(data->pcc_chan->mchan, NULL);
-	if (ret < 0)
-		return AE_ERROR;
-
 	/*
 	 * pcc_chan->latency is just a Nominal value. In reality the remote
 	 * processor could be much slower to reply. So add an arbitrary
 	 * amount of wait on top of Nominal.
 	 */
 	usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
-	ret = wait_for_completion_timeout(&data->done,
-						usecs_to_jiffies(usecs_lat));
-	if (ret == 0) {
-		pr_err("PCC command executed timeout!\n");
-		return AE_TIME;
-	}

-	mbox_chan_txdone(data->pcc_chan->mchan, ret);
+	data->cl.tx_block = use_polling;
+	data->cl.tx_tout = usecs_lat / USEC_PER_MSEC;
+
+	if (use_polling)
+		ret = acpi_pcc_send_msg_polling(data);
+	else
+		ret = acpi_pcc_send_msg_irq(data);

 	memcpy_fromio(value, data->pcc_chan->shmem, data->ctx.length);

-	return AE_OK;
+	return ret;
 }

 void __init acpi_init_pcc(void)
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 0a00719b2482..e4e744669f81 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -579,11 +579,17 @@ static void pcc_shutdown(struct mbox_chan *chan)
 		devm_free_irq(chan->mbox->dev, pchan->plat_irq, chan);
 }

+static bool pcc_peek_data(struct mbox_chan *chan)
+{
+	return pcc_mbox_error_check_and_clear(chan->con_priv) == 0;
+}
+
 static const struct mbox_chan_ops pcc_chan_ops = {
 	.send_data = pcc_send_data,
 	.startup = pcc_startup,
 	.shutdown = pcc_shutdown,
 	.last_tx_done = pcc_last_tx_done,
+	.peek_data = pcc_peek_data,
 };

 /**
@@ -877,8 +883,12 @@ static int pcc_mbox_probe(struct platform_device *pdev)
 		(unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));

 	acpi_pcct_tbl = (struct acpi_table_pcct *) pcct_tbl;
-	if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL)
+	if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) {
 		pcc_mbox_ctrl->txdone_irq = true;
+	} else {
+		pcc_mbox_ctrl->txdone_poll = true;
+		pcc_mbox_ctrl->txpoll_period = 1;
+	}

 	for (i = 0; i < count; i++) {
 		struct pcc_chan_info *pchan = chan_info + i;
--
2.25.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ