Commit aa2e505c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'acpi-pcc-updates-6.7' of...

Merge tag 'acpi-pcc-updates-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux

Merge ACPI PCC changes for v6.7 from Sudeep Holla:

"ACPI: PCC: Mailbox and generic updates for v6.7

 Main updates include:
 1. Addition of support for Type 4 PCC subspace that enables platform
    notification handling (Huisong Li).
 2. Support for the shared interrupt amongst multiple PCC subspaces/
    channels (Huisong Li).
 3. Consolidation of PCC shared memory region command and status
    bitfields definitions that were duplicated and scattered across
    multiple PCC client drivers (Sudeep Holla)."

* tag 'acpi-pcc-updates-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  soc: kunpeng_hccs: Migrate to use generic PCC shmem related macros
  hwmon: (xgene) Migrate to use generic PCC shmem related macros
  i2c: xgene-slimpro: Migrate to use generic PCC shmem related macros
  ACPI: PCC: Add PCC shared memory region command and status bitfields
  mailbox: pcc: Support shared interrupt for multiple subspaces
  mailbox: pcc: Add support for platform notification handling
parents 8a749fd1 a46e42c0
Loading
Loading
Loading
Loading
+5 −11
Original line number Diff line number Diff line
@@ -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];
+4 −12
Original line number Diff line number Diff line
@@ -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 */
+80 −11
Original line number Diff line number Diff line
@@ -91,6 +91,14 @@ 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
 * @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;
@@ -100,12 +108,17 @@ struct pcc_chan_info {
	struct pcc_chan_reg cmd_update;
	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)
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 +234,41 @@ 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;
	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,16 +284,12 @@ 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 (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE &&
	    !pchan->chan_in_use)
		return IRQ_NONE;

	if (val) { /* Ensure GAS exists and value is non-zero */
		val &= pchan->cmd_complete.status_mask;
		if (!val)
	if (!pcc_mbox_cmd_complete_check(pchan))
		return IRQ_NONE;
	}

	ret = pcc_chan_reg_read(&pchan->error, &val);
	if (ret)
@@ -262,6 +306,16 @@ 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.
	 *
	 * 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;
}

@@ -340,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;
}

/**
@@ -353,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);
@@ -463,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;
@@ -484,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;
}

@@ -698,6 +766,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);
	}
+2 −6
Original line number Diff line number Diff line
@@ -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 */
+13 −0
Original line number Diff line number Diff line
@@ -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);