diff options
Diffstat (limited to 'drivers/soc/hisilicon/kunpeng_hccs.c')
-rw-r--r-- | drivers/soc/hisilicon/kunpeng_hccs.c | 152 |
1 files changed, 119 insertions, 33 deletions
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index e317916595..9ff70b38e5 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -85,8 +85,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, @@ -108,6 +110,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 *mssg) +{ + 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 +139,9 @@ 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; + cl->rx_callback = hdev->verspec_data->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 +158,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->verspec_data->has_txdone_irq && + 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->verspec_data->has_txdone_irq && + !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; @@ -170,7 +189,7 @@ out: return rc; } -static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) +static int hccs_wait_cmd_complete_by_poll(struct hccs_dev *hdev) { struct hccs_mbox_client_info *cl_info = &hdev->cl_info; struct acpi_pcct_shared_memory __iomem *comm_base = @@ -192,30 +211,74 @@ static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) return ret; } +static int hccs_wait_cmd_complete_by_irq(struct hccs_dev *hdev) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + + if (!wait_for_completion_timeout(&cl_info->done, + usecs_to_jiffies(cl_info->deadline_us))) { + dev_err(hdev->dev, "PCC command executed timeout!\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static inline 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 acpi_pcct_shared_memory tmp = { + .signature = PCC_SIGNATURE | hdev->chan_id, + .command = cmd, + .status = 0, + }; + + memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, + sizeof(struct acpi_pcct_shared_memory)); + + /* Copy the message to the PCC comm space */ + memcpy_toio(comm_space, (void *)desc, space_size); +} + +static inline void hccs_fill_ext_pcc_shared_mem_region(struct hccs_dev *hdev, + u8 cmd, + struct hccs_desc *desc, + void __iomem *comm_space, + u16 space_size) +{ + struct acpi_pcct_ext_pcc_shared_memory tmp = { + .signature = PCC_SIGNATURE | hdev->chan_id, + .flags = PCC_CMD_COMPLETION_NOTIFY, + .length = HCCS_PCC_SHARE_MEM_BYTES, + .command = cmd, + }; + + memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, + 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) { + const struct hccs_verspecific_data *verspec_data = hdev->verspec_data; 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 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)); - - /* 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); + comm_space = cl_info->pcc_comm_addr + verspec_data->shared_mem_size; + space_size = HCCS_PCC_SHARE_MEM_BYTES - verspec_data->shared_mem_size; + verspec_data->fill_pcc_shared_mem(hdev, cmd, desc, + comm_space, space_size); + if (verspec_data->has_txdone_irq) + reinit_completion(&cl_info->done); /* Ring doorbell */ ret = mbox_send_message(cl_info->mbox_chan, &cmd); @@ -225,13 +288,12 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, goto end; } - /* Wait for completion */ - ret = hccs_check_chan_cmd_complete(hdev); + ret = verspec_data->wait_cmd_complete(hdev); if (ret) 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,7 +302,10 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, } end: - mbox_client_txdone(cl_info->mbox_chan, ret); + if (verspec_data->has_txdone_irq) + mbox_chan_txdone(cl_info->mbox_chan, ret); + else + mbox_client_txdone(cl_info->mbox_chan, ret); return ret; } @@ -527,7 +592,6 @@ out: static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) { - struct device *dev = hdev->dev; struct hccs_chip_info *chip; struct hccs_die_info *die; @@ -1097,7 +1161,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 +1179,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 +1189,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 +1211,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 +1242,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 +1276,11 @@ static int hccs_probe(struct platform_device *pdev) hdev->dev = &pdev->dev; platform_set_drvdata(pdev, hdev); + /* + * Here would never be failure as the driver and device has been matched. + */ + hdev->verspec_data = acpi_device_get_match_data(hdev->dev); + mutex_init(&hdev->lock); rc = hccs_get_pcc_chan_id(hdev); if (rc) @@ -1248,9 +1317,26 @@ static void hccs_remove(struct platform_device *pdev) hccs_unregister_pcc_channel(hdev); } +static const struct hccs_verspecific_data hisi04b1_verspec_data = { + .rx_callback = NULL, + .wait_cmd_complete = hccs_wait_cmd_complete_by_poll, + .fill_pcc_shared_mem = hccs_fill_pcc_shared_mem_region, + .shared_mem_size = sizeof(struct acpi_pcct_shared_memory), + .has_txdone_irq = false, +}; + +static const struct hccs_verspecific_data hisi04b2_verspec_data = { + .rx_callback = hccs_pcc_rx_callback, + .wait_cmd_complete = hccs_wait_cmd_complete_by_irq, + .fill_pcc_shared_mem = hccs_fill_ext_pcc_shared_mem_region, + .shared_mem_size = sizeof(struct acpi_pcct_ext_pcc_shared_memory), + .has_txdone_irq = true, +}; + static const struct acpi_device_id hccs_acpi_match[] = { - { "HISI04B1"}, - { ""}, + { "HISI04B1", (unsigned long)&hisi04b1_verspec_data}, + { "HISI04B2", (unsigned long)&hisi04b2_verspec_data}, + { } }; MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); |