Unverified Commit 059ee86e authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2881 soc: hisilicon: kunpeng_hccs: Support the platform with PCC type3 and interrupt ack

Merge Pull Request from: @li-huisong 
 
Support the platform with PCC type3 and interrupt ack. 
 
Link:https://gitee.com/openeuler/kernel/pulls/2881

 

Reviewed-by: default avatarFred Kimmy <xweikong@163.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 74d2d8c9 5a22bcd2
Loading
Loading
Loading
Loading
+117 −36
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@
#define HCCS_PCC_CMD_WAIT_RETRIES_NUM		500ULL
#define HCCS_POLL_STATUS_TIME_INTERVAL_US	3

enum hccs_hw_device_version {
	HCCS_HW_DEVICE_V1 = 0,
	HCCS_HW_DEVICE_V2 = 1,
};

static struct hccs_port_info *kobj_to_port_info(struct kobject *k)
{
	return container_of(k, struct hccs_port_info, kobj);
@@ -85,8 +90,10 @@ static int hccs_get_pcc_chan_id(struct hccs_dev *hdev)
	struct hccs_register_ctx ctx = {0};
	acpi_status status;

	if (!acpi_has_method(handle, METHOD_NAME__CRS))
	if (!acpi_has_method(handle, METHOD_NAME__CRS)) {
		dev_err(hdev->dev, "No _CRS method.\n");
		return -ENODEV;
	}

	ctx.dev = hdev->dev;
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
@@ -98,6 +105,21 @@ static int hccs_get_pcc_chan_id(struct hccs_dev *hdev)
	return 0;
}

static int hccs_get_device_version(struct hccs_dev *hdev)
{
	const struct acpi_device_id *acpi_id;

	acpi_id = acpi_match_device(hdev->dev->driver->acpi_match_table,
				    hdev->dev);
	if (!acpi_id) {
		dev_err(hdev->dev, "get device version failed.");
		return -EINVAL;
	}

	hdev->dev_ver = (u8)acpi_id->driver_data;
	return 0;
}

static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
{
	if (ret < 0)
@@ -108,6 +130,14 @@ static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
			 *(u8 *)msg, ret);
}

static void hccs_pcc_rx_callback(struct mbox_client *cl, void *m)
{
	struct hccs_mbox_client_info *cl_info =
			container_of(cl, struct hccs_mbox_client_info, client);

	complete(&cl_info->done);
}

static void hccs_unregister_pcc_channel(struct hccs_dev *hdev)
{
	struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
@@ -129,6 +159,11 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev)
	cl->tx_block = false;
	cl->knows_txdone = true;
	cl->tx_done = hccs_chan_tx_done;
	if (hdev->dev_ver == HCCS_HW_DEVICE_V2) {
		cl->rx_callback = hccs_pcc_rx_callback;
		init_completion(&cl_info->done);
	}

	pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id);
	if (IS_ERR(pcc_chan)) {
		dev_err(dev, "PPC channel request failed.\n");
@@ -145,17 +180,23 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev)
	 */
	cl_info->deadline_us =
			HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency;
	if (cl_info->mbox_chan->mbox->txdone_irq) {
	if (hdev->dev_ver == HCCS_HW_DEVICE_V1 &&
	    cl_info->mbox_chan->mbox->txdone_irq) {
		dev_err(dev, "PCC IRQ in PCCT is enabled.\n");
		rc = -EINVAL;
		goto err_mbx_channel_free;
	} else if (hdev->dev_ver == HCCS_HW_DEVICE_V2 &&
		   !cl_info->mbox_chan->mbox->txdone_irq) {
		dev_err(dev, "PCC IRQ in PCCT isn't supported.\n");
		rc = -EINVAL;
		goto err_mbx_channel_free;
	}

	if (pcc_chan->shmem_base_addr) {
		cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr,
						 pcc_chan->shmem_size);
		if (!cl_info->pcc_comm_addr) {
			dev_err(dev, "Failed to ioremap PCC communication region for channel-%d.\n",
			dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n",
				hdev->chan_id);
			rc = -ENOMEM;
			goto err_mbx_channel_free;
@@ -173,49 +214,81 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev)
static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev)
{
	struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
	struct acpi_pcct_shared_memory __iomem *comm_base =
							cl_info->pcc_comm_addr;
	struct acpi_pcct_shared_memory __iomem *comm_base;
	int ret = 0;
	u16 status;
	int ret;

	/*
	 * Poll PCC status register every 3us(delay_us) for maximum of
	 * deadline_us(timeout_us) until PCC command complete bit is set(cond)
	 */
	if (hdev->dev_ver == HCCS_HW_DEVICE_V1) {
		comm_base = cl_info->pcc_comm_addr;
		ret = readw_poll_timeout(&comm_base->status, status,
					status & PCC_STATUS_CMD_COMPLETE,
					HCCS_POLL_STATUS_TIME_INTERVAL_US,
					cl_info->deadline_us);
		if (unlikely(ret))
			dev_err(hdev->dev, "poll PCC status failed, ret = %d.\n", ret);
	} else {
		if (!wait_for_completion_timeout(&cl_info->done,
				usecs_to_jiffies(cl_info->deadline_us))) {
			dev_err(hdev->dev, "PCC command executed timeout!\n");
			ret = -ETIMEDOUT;
		}
	}

	return ret;
}

static void hccs_fill_pcc_shared_mem_region(struct hccs_dev *hdev, u8 cmd,
					    struct hccs_desc *desc,
					    void __iomem *comm_space,
					    u16 space_size)
{
	struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
	struct acpi_pcct_ext_pcc_shared_memory tmp1 = {0};
	struct acpi_pcct_shared_memory tmp2 = {0};

	if (hdev->dev_ver == HCCS_HW_DEVICE_V1) {
		tmp2.signature = PCC_SIGNATURE | hdev->chan_id;
		tmp2.command = cmd;
		tmp2.status = 0;
		memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp2,
			    sizeof(struct acpi_pcct_shared_memory));
	} else {
		tmp1.signature = PCC_SIGNATURE | hdev->chan_id;
		tmp1.command = cmd;
		tmp1.flags = PCC_CMD_COMPLETION_NOTIFY;
		tmp1.length = HCCS_PCC_SHARE_MEM_BYTES;
		memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp1,
			    sizeof(struct acpi_pcct_ext_pcc_shared_memory));
	}

	/* Copy the message to the PCC comm space */
	memcpy_toio(comm_space, (void *)desc, space_size);
}

static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd,
			     struct hccs_desc *desc)
{
	struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
	void __iomem *comm_space = cl_info->pcc_comm_addr +
					sizeof(struct acpi_pcct_shared_memory);
	struct hccs_fw_inner_head *fw_inner_head;
	struct acpi_pcct_shared_memory tmp = {0};
	u16 comm_space_size;
	void __iomem *comm_space;
	u16 shared_mem_size;
	u16 space_size;
	int ret;

	/* Write signature for this subspace */
	tmp.signature = PCC_SIGNATURE | hdev->chan_id;
	/* Write to the shared command region */
	tmp.command = cmd;
	/* Clear cmd complete bit */
	tmp.status = 0;
	memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp,
			sizeof(struct acpi_pcct_shared_memory));
	shared_mem_size = hdev->dev_ver == HCCS_HW_DEVICE_V1 ?
			sizeof(struct acpi_pcct_shared_memory) :
			sizeof(struct acpi_pcct_ext_pcc_shared_memory);
	comm_space = cl_info->pcc_comm_addr + shared_mem_size;
	space_size = HCCS_PCC_SHARE_MEM_BYTES - shared_mem_size;

	/* Copy the message to the PCC comm space */
	comm_space_size = HCCS_PCC_SHARE_MEM_BYTES -
				sizeof(struct acpi_pcct_shared_memory);
	memcpy_toio(comm_space, (void *)desc, comm_space_size);
	hccs_fill_pcc_shared_mem_region(hdev, cmd, desc,
					comm_space, space_size);
	if (cl_info->mbox_chan->mbox->txdone_irq)
		reinit_completion(&cl_info->done);

	/* Ring doorbell */
	ret = mbox_send_message(cl_info->mbox_chan, &cmd);
@@ -231,7 +304,7 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd,
		goto end;

	/* Copy response data */
	memcpy_fromio((void *)desc, comm_space, comm_space_size);
	memcpy_fromio((void *)desc, comm_space, space_size);
	fw_inner_head = &desc->rsp.fw_inner_head;
	if (fw_inner_head->retStatus) {
		dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n",
@@ -240,6 +313,9 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd,
	}

end:
	if (cl_info->mbox_chan->mbox->txdone_irq)
		mbox_chan_txdone(cl_info->mbox_chan, ret);
	else
		mbox_client_txdone(cl_info->mbox_chan, ret);
	return ret;
}
@@ -1097,7 +1173,7 @@ static int hccs_create_hccs_dir(struct hccs_dev *hdev,
	int ret;

	ret = kobject_init_and_add(&port->kobj, &hccs_port_type,
				   &die->kobj, "hccs%d", port->port_id);
				   &die->kobj, "hccs%u", port->port_id);
	if (ret) {
		kobject_put(&port->kobj);
		return ret;
@@ -1115,7 +1191,7 @@ static int hccs_create_die_dir(struct hccs_dev *hdev,
	u16 i;

	ret = kobject_init_and_add(&die->kobj, &hccs_die_type,
				   &chip->kobj, "die%d", die->die_id);
				   &chip->kobj, "die%u", die->die_id);
	if (ret) {
		kobject_put(&die->kobj);
		return ret;
@@ -1125,7 +1201,7 @@ static int hccs_create_die_dir(struct hccs_dev *hdev,
		port = &die->ports[i];
		ret = hccs_create_hccs_dir(hdev, die, port);
		if (ret) {
			dev_err(hdev->dev, "create hccs%d dir failed.\n",
			dev_err(hdev->dev, "create hccs%u dir failed.\n",
				port->port_id);
			goto err;
		}
@@ -1147,7 +1223,7 @@ static int hccs_create_chip_dir(struct hccs_dev *hdev,
	u16 id;

	ret = kobject_init_and_add(&chip->kobj, &hccs_chip_type,
				   &hdev->dev->kobj, "chip%d", chip->chip_id);
				   &hdev->dev->kobj, "chip%u", chip->chip_id);
	if (ret) {
		kobject_put(&chip->kobj);
		return ret;
@@ -1178,7 +1254,7 @@ static int hccs_create_topo_dirs(struct hccs_dev *hdev)
		chip = &hdev->chips[id];
		ret = hccs_create_chip_dir(hdev, chip);
		if (ret) {
			dev_err(hdev->dev, "init chip%d dir failed!\n", id);
			dev_err(hdev->dev, "init chip%u dir failed!\n", id);
			goto err;
		}
	}
@@ -1212,6 +1288,10 @@ static int hccs_probe(struct platform_device *pdev)
	hdev->dev = &pdev->dev;
	platform_set_drvdata(pdev, hdev);

	rc = hccs_get_device_version(hdev);
	if (rc)
		return rc;

	mutex_init(&hdev->lock);
	rc = hccs_get_pcc_chan_id(hdev);
	if (rc)
@@ -1251,7 +1331,8 @@ static int hccs_remove(struct platform_device *pdev)
}

static const struct acpi_device_id hccs_acpi_match[] = {
	{ "HISI04B1"},
	{ "HISI04B1", HCCS_HW_DEVICE_V1},
	{ "HISI04B2", HCCS_HW_DEVICE_V2},
	{ ""},
};
MODULE_DEVICE_TABLE(acpi, hccs_acpi_match);
+2 −0
Original line number Diff line number Diff line
@@ -51,12 +51,14 @@ struct hccs_mbox_client_info {
	struct pcc_mbox_chan *pcc_chan;
	u64 deadline_us;
	void __iomem *pcc_comm_addr;
	struct completion done;
};

struct hccs_dev {
	struct device *dev;
	struct acpi_device *acpi_dev;
	u64 caps;
	u8 dev_ver;
	u8 chip_num;
	struct hccs_chip_info *chips;
	u8 chan_id;