diff options
26 files changed, 348 insertions, 157 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 355e4ab2f9e5..8856f10a72bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20549,6 +20549,7 @@ PCI ENDPOINT SUBSYSTEM M: Manivannan Sadhasivam <mani@kernel.org> M: Krzysztof Wilczyński <kwilczynski@kernel.org> R: Kishon Vijay Abraham I <kishon@kernel.org> +R: Frank Li <Frank.Li@kernel.org> L: linux-pci@vger.kernel.org S: Supported Q: https://patchwork.kernel.org/project/linux-pci/list/ diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c index e1912108a0fe..2a7a0f774389 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -723,15 +723,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev) return -ENOMEM; priv->client.dev = dev; - priv->client.receive_cb = NULL; priv->client.priv = priv; - priv->status.current_image = 0; - priv->status.fail_image = 0; - priv->status.error_location = 0; - priv->status.error_details = 0; - priv->status.version = 0; - priv->status.state = 0; priv->retry_counter = INVALID_RETRY_COUNTER; + priv->max_retry = INVALID_RETRY_COUNTER; priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION; priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION; priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION; @@ -740,11 +734,11 @@ static int stratix10_rsu_probe(struct platform_device *pdev) priv->dcmf_status.dcmf1 = INVALID_DCMF_STATUS; priv->dcmf_status.dcmf2 = INVALID_DCMF_STATUS; priv->dcmf_status.dcmf3 = INVALID_DCMF_STATUS; - priv->max_retry = INVALID_RETRY_COUNTER; - priv->spt0_address = INVALID_SPT_ADDRESS; - priv->spt1_address = INVALID_SPT_ADDRESS; + /* spt0/1_address and status fields default to 0 from kzalloc */ mutex_init(&priv->lock); + init_completion(&priv->completion); + priv->chan = stratix10_svc_request_channel_byname(&priv->client, SVC_CLIENT_RSU); if (IS_ERR(priv->chan)) { @@ -756,11 +750,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev) ret = stratix10_svc_add_async_client(priv->chan, false); if (ret) { dev_err(dev, "failed to add async client\n"); - stratix10_svc_free_channel(priv->chan); - return ret; + goto free_channel; } - init_completion(&priv->completion); platform_set_drvdata(pdev, priv); /* get the initial state from firmware */ @@ -768,41 +760,44 @@ static int stratix10_rsu_probe(struct platform_device *pdev) rsu_async_status_callback); if (ret) { dev_err(dev, "Error, getting RSU status %i\n", ret); - stratix10_svc_remove_async_client(priv->chan); - stratix10_svc_free_channel(priv->chan); - return ret; + goto remove_async_client; } /* get DCMF version from firmware */ - ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION, - 0, rsu_dcmf_version_callback); + ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION, 0, + rsu_dcmf_version_callback); if (ret) { dev_err(dev, "Error, getting DCMF version %i\n", ret); - stratix10_svc_free_channel(priv->chan); + goto remove_async_client; } - ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS, - 0, rsu_dcmf_status_callback); + ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_STATUS, 0, + rsu_dcmf_status_callback); if (ret) { dev_err(dev, "Error, getting DCMF status %i\n", ret); - stratix10_svc_free_channel(priv->chan); + goto remove_async_client; } ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0, rsu_max_retry_callback); if (ret) { dev_err(dev, "Error, getting RSU max retry %i\n", ret); - stratix10_svc_free_channel(priv->chan); + goto remove_async_client; } - ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0, rsu_async_get_spt_table_callback); if (ret) { dev_err(dev, "Error, getting SPT table %i\n", ret); - stratix10_svc_free_channel(priv->chan); + goto remove_async_client; } + return 0; + +remove_async_client: + stratix10_svc_remove_async_client(priv->chan); +free_channel: + stratix10_svc_free_channel(priv->chan); return ret; } diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index e9e35d67ef96..39eb78f5905b 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -212,6 +212,7 @@ struct stratix10_async_chan { /** * struct stratix10_async_ctrl - Control structure for Stratix10 * asynchronous operations + * @supported: Flag indicating whether the system supports async operations * @initialized: Flag indicating whether the control structure has * been initialized * @invoke_fn: Function pointer for invoking Stratix10 service calls @@ -228,6 +229,7 @@ struct stratix10_async_chan { */ struct stratix10_async_ctrl { + bool supported; bool initialized; void (*invoke_fn)(struct stratix10_async_ctrl *actrl, const struct arm_smccc_1_2_regs *args, @@ -1103,6 +1105,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname); * Return: 0 on success, or a negative error code on failure: * -EINVAL if the channel is NULL or the async controller is * not initialized. + * -EOPNOTSUPP if async operations are not supported. * -EALREADY if the async channel is already allocated. * -ENOMEM if memory allocation fails. * Other negative values if ID allocation fails. @@ -1121,6 +1124,9 @@ int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan, ctrl = chan->ctrl; actrl = &ctrl->actrl; + if (!actrl->supported) + return -EOPNOTSUPP; + if (!actrl->initialized) { dev_err(ctrl->dev, "Async controller not initialized\n"); return -EINVAL; @@ -1562,6 +1568,7 @@ static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl, * initialized, -ENOMEM if memory allocation fails, * -EADDRINUSE if the client ID is already reserved, or other * negative error codes on failure. + * -EOPNOTSUPP if system doesn't support async operations. */ static int stratix10_svc_async_init(struct stratix10_svc_controller *controller) { @@ -1585,10 +1592,12 @@ static int stratix10_svc_async_init(struct stratix10_svc_controller *controller) !(res.a1 > ASYNC_ATF_MINIMUM_MAJOR_VERSION || (res.a1 == ASYNC_ATF_MINIMUM_MAJOR_VERSION && res.a2 >= ASYNC_ATF_MINIMUM_MINOR_VERSION))) { - dev_err(dev, - "Intel Service Layer Driver: ATF version is not compatible for async operation\n"); - return -EINVAL; + dev_info(dev, + "Intel Service Layer Driver: ATF version is not compatible for async operation\n"); + actrl->supported = false; + return -EOPNOTSUPP; } + actrl->supported = true; actrl->invoke_fn = stratix10_smc_1_2; @@ -1952,10 +1961,14 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) init_completion(&controller->complete_status); ret = stratix10_svc_async_init(controller); - if (ret) { + if (ret == -EOPNOTSUPP) { + dev_info(dev, "Intel Service Layer Driver Initialized (sync-only mode)\n"); + } else if (ret) { dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_init %d\n", ret); goto err_destroy_pool; + } else { + dev_info(dev, "Intel Service Layer Driver Initialized\n"); } fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO; diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 1080f9acf70a..f3a49384586d 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -310,6 +310,8 @@ struct fastrpc_user { spinlock_t lock; /* lock for allocations */ struct mutex mutex; + /* Reference count */ + struct kref refcount; }; /* Extract SMMU PA from consolidated IOVA */ @@ -386,7 +388,7 @@ static int fastrpc_map_get(struct fastrpc_map *map) static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, - struct fastrpc_map **ppmap) + struct fastrpc_map **ppmap, bool take_ref) { struct fastrpc_map *map = NULL; struct dma_buf *buf; @@ -401,6 +403,12 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, if (map->fd != fd || map->buf != buf) continue; + if (take_ref) { + ret = fastrpc_map_get(map); + if (ret) + break; + } + *ppmap = map; ret = 0; break; @@ -497,15 +505,57 @@ static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx) kref_put(&cctx->refcount, fastrpc_channel_ctx_free); } +static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx); + +static void fastrpc_user_free(struct kref *ref) +{ + struct fastrpc_user *fl = container_of(ref, struct fastrpc_user, refcount); + struct fastrpc_invoke_ctx *ctx, *n; + struct fastrpc_map *map, *m; + struct fastrpc_buf *buf, *b; + + if (fl->init_mem) + fastrpc_buf_free(fl->init_mem); + + list_for_each_entry_safe(ctx, n, &fl->pending, node) { + list_del(&ctx->node); + fastrpc_context_put(ctx); + } + + list_for_each_entry_safe(map, m, &fl->maps, node) + fastrpc_map_put(map); + + list_for_each_entry_safe(buf, b, &fl->mmaps, node) { + list_del(&buf->node); + fastrpc_buf_free(buf); + } + + fastrpc_channel_ctx_put(fl->cctx); + mutex_destroy(&fl->mutex); + kfree(fl); +} + +static void fastrpc_user_get(struct fastrpc_user *fl) +{ + kref_get(&fl->refcount); +} + +static void fastrpc_user_put(struct fastrpc_user *fl) +{ + kref_put(&fl->refcount, fastrpc_user_free); +} + static void fastrpc_context_free(struct kref *ref) { struct fastrpc_invoke_ctx *ctx; struct fastrpc_channel_ctx *cctx; + struct fastrpc_user *fl; unsigned long flags; int i; ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount); cctx = ctx->cctx; + fl = ctx->fl; for (i = 0; i < ctx->nbufs; i++) fastrpc_map_put(ctx->maps[i]); @@ -521,6 +571,8 @@ static void fastrpc_context_free(struct kref *ref) kfree(ctx->olaps); kfree(ctx); + /* Release the reference taken in fastrpc_context_alloc() */ + fastrpc_user_put(fl); fastrpc_channel_ctx_put(cctx); } @@ -628,6 +680,8 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc( /* Released in fastrpc_context_put() */ fastrpc_channel_ctx_get(cctx); + /* Take a reference to user, released in fastrpc_context_free() */ + fastrpc_user_get(user); ctx->sc = sc; ctx->retval = -1; @@ -658,6 +712,7 @@ err_idr: spin_lock(&user->lock); list_del(&ctx->node); spin_unlock(&user->lock); + fastrpc_user_put(user); fastrpc_channel_ctx_put(cctx); kfree(ctx->maps); kfree(ctx->olaps); @@ -871,19 +926,10 @@ get_err: static int fastrpc_map_create(struct fastrpc_user *fl, int fd, u64 len, u32 attr, struct fastrpc_map **ppmap) { - struct fastrpc_session_ctx *sess = fl->sctx; - int err = 0; - - if (!fastrpc_map_lookup(fl, fd, ppmap)) { - if (!fastrpc_map_get(*ppmap)) - return 0; - dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n", - __func__, fd); - } - - err = fastrpc_map_attach(fl, fd, len, attr, ppmap); + if (!fastrpc_map_lookup(fl, fd, ppmap, true)) + return 0; - return err; + return fastrpc_map_attach(fl, fd, len, attr, ppmap); } /* @@ -1041,7 +1087,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) pages[i].addr = ctx->maps[i]->dma_addr; mmap_read_lock(current->mm); - vma = find_vma(current->mm, ctx->args[i].ptr); + vma = vma_lookup(current->mm, ctx->args[i].ptr); if (vma) pages[i].addr += (ctx->args[i].ptr & PAGE_MASK) - vma->vm_start; @@ -1153,7 +1199,7 @@ cleanup_fdlist: for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { if (!fdlist[i]) break; - if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) + if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false)) fastrpc_map_put(mmap); } @@ -1579,9 +1625,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) { struct fastrpc_user *fl = (struct fastrpc_user *)file->private_data; struct fastrpc_channel_ctx *cctx = fl->cctx; - struct fastrpc_invoke_ctx *ctx, *n; - struct fastrpc_map *map, *m; - struct fastrpc_buf *buf, *b; unsigned long flags; fastrpc_release_current_dsp_process(fl); @@ -1590,28 +1633,10 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) list_del(&fl->user); spin_unlock_irqrestore(&cctx->lock, flags); - if (fl->init_mem) - fastrpc_buf_free(fl->init_mem); - - list_for_each_entry_safe(ctx, n, &fl->pending, node) { - list_del(&ctx->node); - fastrpc_context_put(ctx); - } - - list_for_each_entry_safe(map, m, &fl->maps, node) - fastrpc_map_put(map); - - list_for_each_entry_safe(buf, b, &fl->mmaps, node) { - list_del(&buf->node); - fastrpc_buf_free(buf); - } - fastrpc_session_free(cctx, fl->sctx); - fastrpc_channel_ctx_put(cctx); - - mutex_destroy(&fl->mutex); - kfree(fl); file->private_data = NULL; + /* Release the reference taken in fastrpc_device_open */ + fastrpc_user_put(fl); return 0; } @@ -1655,6 +1680,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) spin_lock_irqsave(&cctx->lock, flags); list_add_tail(&fl->user, &cctx->users); spin_unlock_irqrestore(&cctx->lock, flags); + kref_init(&fl->refcount); return 0; } @@ -2431,7 +2457,6 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) kref_init(&data->refcount); - dev_set_drvdata(&rpdev->dev, data); rdev->dma_mask = &data->dma_mask; dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32)); INIT_LIST_HEAD(&data->users); @@ -2440,6 +2465,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) idr_init(&data->ctx_idr); data->domain_id = domain_id; data->rpdev = rpdev; + dev_set_drvdata(&rpdev->dev, data); err = of_platform_populate(rdev->of_node, NULL, NULL, rdev); if (err) @@ -2513,6 +2539,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, if (len < sizeof(*rsp)) return -EINVAL; + if (!cctx) + return -ENODEV; + ctxid = ((rsp->ctx & FASTRPC_CTXID_MASK) >> 4); spin_lock_irqsave(&cctx->lock, flags); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 311cb2e5a5c0..e871181751f3 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1468,18 +1468,16 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); of_node_put(cell_np); if (!cell_entry) { - __nvmem_device_put(nvmem); nvmem_layout_module_put(nvmem); - if (nvmem->layout) - return ERR_PTR(-EPROBE_DEFER); - else - return ERR_PTR(-ENOENT); + ret = nvmem->layout ? -EPROBE_DEFER : -ENOENT; + __nvmem_device_put(nvmem); + return ERR_PTR(ret); } cell = nvmem_create_cell(cell_entry, id, cell_index); if (IS_ERR(cell)) { - __nvmem_device_put(nvmem); nvmem_layout_module_put(nvmem); + __nvmem_device_put(nvmem); } return cell; @@ -1593,8 +1591,8 @@ void nvmem_cell_put(struct nvmem_cell *cell) kfree_const(cell->id); kfree(cell); - __nvmem_device_put(nvmem); nvmem_layout_module_put(nvmem); + __nvmem_device_put(nvmem); } EXPORT_SYMBOL_GPL(nvmem_cell_put); diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c index 0967a32319a2..8b0f3c1b8a0e 100644 --- a/drivers/nvmem/layouts/onie-tlv.c +++ b/drivers/nvmem/layouts/onie-tlv.c @@ -119,7 +119,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem, cell.name = onie_tlv_cell_name(tlv.type); if (!cell.name) - continue; + goto next; cell.offset = hdr_len + offset + sizeof(tlv.type) + sizeof(tlv.len); cell.bytes = tlv.len; @@ -132,6 +132,7 @@ static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem, return ret; } +next: offset += sizeof(tlv) + tlv.len; } diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 1ed6be6e85d2..3071e46d03be 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1471,15 +1471,12 @@ static int qcom_slim_ngd_ssr_pdr_notify(struct qcom_slim_ngd_ctrl *ctrl, switch (action) { case QCOM_SSR_BEFORE_SHUTDOWN: case SERVREG_SERVICE_STATE_DOWN: - /* Make sure the last dma xfer is finished */ - mutex_lock(&ctrl->tx_lock); if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) { pm_runtime_get_noresume(ctrl->ctrl.dev); ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN; qcom_slim_ngd_down(ctrl); qcom_slim_ngd_exit_dma(ctrl); } - mutex_unlock(&ctrl->tx_lock); break; case QCOM_SSR_AFTER_POWERUP: case SERVREG_SERVICE_STATE_UP: @@ -1542,7 +1539,7 @@ static int of_qcom_slim_ngd_register(struct device *parent, kfree(ngd); return ret; } - ngd->pdev->dev.of_node = node; + ngd->pdev->dev.of_node = of_node_get(node); ctrl->ngd = ngd; ret = platform_device_add(ngd->pdev); @@ -1560,6 +1557,13 @@ static int of_qcom_slim_ngd_register(struct device *parent, return -ENODEV; } +static void qcom_slim_ngd_unregister(struct qcom_slim_ngd_ctrl *ctrl) +{ + struct qcom_slim_ngd *ngd = ctrl->ngd; + + platform_device_del(ngd->pdev); +} + static int qcom_slim_ngd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1577,24 +1581,10 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) ret = qcom_slim_ngd_qmi_svc_event_init(ctrl); if (ret) { dev_err(&pdev->dev, "QMI service registration failed:%d", ret); - return ret; + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); } - INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); - INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker); - ctrl->mwq = create_singlethread_workqueue("ngd_master"); - if (!ctrl->mwq) { - dev_err(&pdev->dev, "Failed to start master worker\n"); - ret = -ENOMEM; - goto wq_err; - } - - return 0; -wq_err: - qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); - if (ctrl->mwq) - destroy_workqueue(ctrl->mwq); - return ret; } @@ -1602,6 +1592,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct qcom_slim_ngd_ctrl *ctrl; + int irq; int ret; struct pdr_service *pds; @@ -1615,20 +1606,16 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) if (IS_ERR(ctrl->base)) return PTR_ERR(ctrl->base); - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - ret = devm_request_irq(dev, ret, qcom_slim_ngd_interrupt, - IRQF_TRIGGER_HIGH, "slim-ngd", ctrl); + ret = devm_request_irq(dev, irq, qcom_slim_ngd_interrupt, + IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, + "slim-ngd", ctrl); if (ret) return dev_err_probe(&pdev->dev, ret, "request IRQ failed\n"); - ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify; - ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb); - if (IS_ERR(ctrl->notifier)) - return PTR_ERR(ctrl->notifier); - ctrl->dev = dev; ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3; ctrl->framer.superfreq = @@ -1649,48 +1636,71 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) init_completion(&ctrl->qmi.qmi_comp); init_completion(&ctrl->qmi_up); + INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); + INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker); + + ctrl->mwq = create_singlethread_workqueue("ngd_master"); + if (!ctrl->mwq) + return dev_err_probe(dev, -ENOMEM, "Failed to start master worker\n"); + ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl); if (IS_ERR(ctrl->pdr)) { - ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), - "Failed to init PDR handle\n"); - goto err_pdr_alloc; + ret = dev_err_probe(dev, PTR_ERR(ctrl->pdr), "Failed to init PDR handle\n"); + goto err_destroy_mwq; } + ret = of_qcom_slim_ngd_register(dev, ctrl); + if (ret) + goto err_pdr_release; + pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd"); if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { ret = dev_err_probe(dev, PTR_ERR(pds), "pdr add lookup failed\n"); - goto err_pdr_lookup; + goto err_unregister_ngd; + } + + ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify; + ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb); + if (IS_ERR(ctrl->notifier)) { + ret = PTR_ERR(ctrl->notifier); + goto err_unregister_ngd; } - platform_driver_register(&qcom_slim_ngd_driver); - return of_qcom_slim_ngd_register(dev, ctrl); + enable_irq(irq); -err_pdr_alloc: - qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); + return 0; -err_pdr_lookup: +err_unregister_ngd: + qcom_slim_ngd_unregister(ctrl); +err_pdr_release: pdr_handle_release(ctrl->pdr); +err_destroy_mwq: + destroy_workqueue(ctrl->mwq); return ret; } static void qcom_slim_ngd_ctrl_remove(struct platform_device *pdev) { - platform_driver_unregister(&qcom_slim_ngd_driver); + struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + + pdr_handle_release(ctrl->pdr); + qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); + + qcom_slim_ngd_unregister(ctrl); + + destroy_workqueue(ctrl->mwq); } static void qcom_slim_ngd_remove(struct platform_device *pdev) { struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - pdr_handle_release(ctrl->pdr); - qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); qcom_slim_ngd_enable(ctrl, false); qcom_slim_ngd_exit_dma(ctrl); qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); - if (ctrl->mwq) - destroy_workqueue(ctrl->mwq); kfree(ctrl->ngd); ctrl->ngd = NULL; @@ -1752,6 +1762,28 @@ static struct platform_driver qcom_slim_ngd_driver = { }, }; -module_platform_driver(qcom_slim_ngd_ctrl_driver); +static int qcom_slim_ngd_init(void) +{ + int ret; + + ret = platform_driver_register(&qcom_slim_ngd_driver); + if (ret) + return ret; + + ret = platform_driver_register(&qcom_slim_ngd_ctrl_driver); + if (ret) + platform_driver_unregister(&qcom_slim_ngd_driver); + + return ret; +} + +static void qcom_slim_ngd_exit(void) +{ + platform_driver_unregister(&qcom_slim_ngd_ctrl_driver); + platform_driver_unregister(&qcom_slim_ngd_driver); +} + +module_init(qcom_slim_ngd_init); +module_exit(qcom_slim_ngd_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Qualcomm SLIMBus NGD controller"); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index b47637888c5c..4672bc2a873a 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -472,7 +472,9 @@ static inline void dw_spi_abort(struct spi_controller *ctlr) if (dws->dma_mapped) dws->dma_ops->dma_stop(dws); + disable_irq(dws->irq); dw_spi_reset_chip(dws); + enable_irq(dws->irq); } static void dw_spi_handle_err(struct spi_controller *ctlr, diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index d5fb0edc8e0c..23c6d3a37341 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -440,10 +440,15 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas return ret; } - if (!xfer->cs_change) { - if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) - peripheral.fragmentation = FRAGMENTATION; - } + /* + * Set fragmentation to keep CS asserted after this transfer when: + * - non-last transfer with cs_change=0: keep CS asserted between chained transfers + * - last transfer with cs_change=1: keep CS asserted after the message + * (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to + * keep CS asserted across header, wait-state and data phases) + */ + peripheral.fragmentation = list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ? + xfer->cs_change : !xfer->cs_change; if (peripheral.cmd & SPI_RX) { dmaengine_slave_config(mas->rx, &config); @@ -849,10 +854,16 @@ static int setup_se_xfer(struct spi_transfer *xfer, mas->cur_xfer_mode = GENI_SE_DMA; geni_se_select_mode(se, mas->cur_xfer_mode); - if (!xfer->cs_change) { - if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) - m_params = FRAGMENTATION; - } + /* + * Set FRAGMENTATION to keep CS asserted after this transfer when: + * - non-last transfer with cs_change=0: keep CS asserted between chained transfers + * - last transfer with cs_change=1: keep CS asserted after the message + * (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to + * keep CS asserted across header, wait-state and data phases) + */ + if (list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ? + xfer->cs_change : !xfer->cs_change) + m_params = FRAGMENTATION; /* * Lock around right before we start the transfer since our diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c index 1655efda7d20..6ed3fad873b8 100644 --- a/drivers/spi/spi-rzv2h-rspi.c +++ b/drivers/spi/spi-rzv2h-rspi.c @@ -135,8 +135,9 @@ static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \ RZV2H_RSPI_TX(writel, u32) RZV2H_RSPI_TX(writew, u16) RZV2H_RSPI_TX(writeb, u8) +/* The read access size for RSPI_SPDR is fixed at 32 bits */ RZV2H_RSPI_RX(readl, u32) -RZV2H_RSPI_RX(readw, u16) +RZV2H_RSPI_RX(readl, u16) RZV2H_RSPI_RX(readl, u8) static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi, diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index ddfc56f0253d..9f21a2226dbd 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -464,8 +464,11 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex if (check_fwstate(pmlmepriv, _FW_LINKED) && (is_same_network(&pmlmepriv->cur_network.network, pnetwork, 0))) { update_network(&pmlmepriv->cur_network.network, pnetwork, adapter, true); + if (pmlmepriv->cur_network.network.ie_length < sizeof(struct ndis_802_11_fix_ie)) + return; + rtw_update_protection(adapter, (pmlmepriv->cur_network.network.ies) + sizeof(struct ndis_802_11_fix_ie), - pmlmepriv->cur_network.network.ie_length); + pmlmepriv->cur_network.network.ie_length - sizeof(struct ndis_802_11_fix_ie)); } } @@ -601,6 +604,8 @@ static bool rtw_is_desired_network(struct adapter *adapter, struct wlan_network privacy = pnetwork->network.privacy; if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + if (pnetwork->network.ie_length < _FIXED_IE_LENGTH_) + return false; if (rtw_get_wps_ie(pnetwork->network.ies + _FIXED_IE_LENGTH_, pnetwork->network.ie_length - _FIXED_IE_LENGTH_, NULL, &wps_ielen)) return true; else @@ -614,11 +619,15 @@ static bool rtw_is_desired_network(struct adapter *adapter, struct wlan_network bselected = false; if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { - p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_)); - if (p && ie_len > 0) - bselected = true; - else + if (pnetwork->network.ie_length < _BEACON_IE_OFFSET_) { bselected = false; + } else { + p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + bselected = true; + else + bselected = false; + } } } @@ -1072,8 +1081,11 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net break; } + if (cur_network->network.ie_length < sizeof(struct ndis_802_11_fix_ie)) + return; + rtw_update_protection(padapter, (cur_network->network.ies) + sizeof(struct ndis_802_11_fix_ie), - (cur_network->network.ie_length)); + (cur_network->network.ie_length - sizeof(struct ndis_802_11_fix_ie))); rtw_update_ht_cap(padapter, cur_network->network.ies, cur_network->network.ie_length, (u8) cur_network->network.configuration.ds_config); } diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c index da2c59a17db5..59beab43f90a 100644 --- a/drivers/thunderbolt/property.c +++ b/drivers/thunderbolt/property.c @@ -60,6 +60,8 @@ static bool tb_property_entry_valid(const struct tb_property_entry *entry, case TB_PROPERTY_TYPE_DIRECTORY: case TB_PROPERTY_TYPE_DATA: case TB_PROPERTY_TYPE_TEXT: + if (!entry->length) + return false; if (entry->length > block_len) return false; if (check_add_overflow(entry->value, entry->length, &end) || @@ -185,6 +187,10 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, if (is_root) { content_offset = dir_offset + 2; content_len = dir_len; + if (content_offset + content_len > block_len) { + tb_property_free_dir(dir); + return NULL; + } } else { if (dir_len < 4) { tb_property_free_dir(dir); diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 754808c43f00..1fd1cf4295a2 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -55,6 +55,7 @@ static const char * const state_names[] = { struct xdomain_request_work { struct work_struct work; struct tb_xdp_header *pkg; + size_t pkg_len; struct tb *tb; }; @@ -122,7 +123,9 @@ static bool tb_xdomain_match(const struct tb_cfg_request *req, static bool tb_xdomain_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg) { - memcpy(req->response, pkg->buffer, req->response_size); + size_t len = min_t(size_t, pkg->frame.size, req->response_size); + + memcpy(req->response, pkg->buffer, len); req->result.err = 0; return true; } @@ -393,6 +396,8 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route, } } + if (req.offset + len > data_len) + len = data_len - req.offset; memcpy(data + req.offset, res->data, len * 4); req.offset += len; } while (!data_len || req.offset < data_len); @@ -731,6 +736,7 @@ static void tb_xdp_handle_request(struct work_struct *work) struct xdomain_request_work *xw = container_of(work, typeof(*xw), work); const struct tb_xdp_header *pkg = xw->pkg; const struct tb_xdomain_header *xhdr = &pkg->xd_hdr; + size_t pkg_len = xw->pkg_len; struct tb *tb = xw->tb; struct tb_ctl *ctl = tb->ctl; struct tb_xdomain *xd; @@ -762,7 +768,7 @@ static void tb_xdp_handle_request(struct work_struct *work) switch (pkg->type) { case PROPERTIES_REQUEST: tb_dbg(tb, "%llx: received XDomain properties request\n", route); - if (xd) { + if (xd && pkg_len >= sizeof(struct tb_xdp_properties)) { ret = tb_xdp_properties_response(tb, ctl, xd, sequence, (const struct tb_xdp_properties *)pkg); } @@ -816,7 +822,8 @@ static void tb_xdp_handle_request(struct work_struct *work) tb_dbg(tb, "%llx: received XDomain link state change request\n", route); - if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) { + if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH && + pkg_len >= sizeof(struct tb_xdp_link_state_change)) { const struct tb_xdp_link_state_change *lsc = (const struct tb_xdp_link_state_change *)pkg; @@ -868,6 +875,7 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr, kfree(xw); return false; } + xw->pkg_len = size; xw->tb = tb_domain_get(tb); schedule_work(&xw->work); diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index cb55370e036f..d48819d785ef 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -773,6 +773,12 @@ static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer) } /* Read the descriptor data */ + if (le16_to_cpu(rom_desc->Size) != sizeof(struct edge_ti_manuf_descriptor)) { + dev_err(dev, "unexpected Edge descriptor length: %u\n", + le16_to_cpu(rom_desc->Size)); + status = -EINVAL; + goto exit; + } status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), le16_to_cpu(rom_desc->Size), buffer); if (status) @@ -838,6 +844,11 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) /* Pointer to fw_down memory image */ img_header = (struct ti_i2c_image_header *)&fw->data[4]; + if (le16_to_cpu(img_header->Length) > + buffer_size - sizeof(struct ti_i2c_firmware_rec)) { + kfree(buffer); + return -EINVAL; + } memcpy(buffer + sizeof(struct ti_i2c_firmware_rec), &fw->data[4 + sizeof(struct ti_i2c_image_header)], le16_to_cpu(img_header->Length)); diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index ed8531a64768..e72a0b45a707 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -330,8 +330,8 @@ static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, unsigned char *buf = dest; int count; - count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, - &port->lock); + count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, + size - KLSI_HDR_LEN, &port->lock); put_unaligned_le16(count, buf); return count + KLSI_HDR_LEN; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 48ae0188f2e9..a34e79cfd5b6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -202,6 +202,7 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5821E_ESIM 0x81e0 #define DELL_PRODUCT_5829E_ESIM 0x81e4 #define DELL_PRODUCT_5829E 0x81e6 +#define DELL_PRODUCT_5826E_ESIM 0x81ea #define DELL_PRODUCT_FM101R_ESIM 0x8213 #define DELL_PRODUCT_FM101R 0x8215 @@ -1123,6 +1124,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(0) | RSVD(6) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E_ESIM), .driver_info = RSVD(0) | RSVD(6) }, + { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_5826E_ESIM, 0xff), + .driver_info = RSVD(1) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(DELL_VENDOR_ID, DELL_PRODUCT_FM101R_ESIM, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index 63061aa1cab9..926254b6898f 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -305,7 +305,6 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg, arg->partial_map = 1; if (iov != arg->iovs) break; - WRITE_ONCE(buf->len, len); } } diff --git a/io_uring/wait.c b/io_uring/wait.c index ec01e78a216d..d005ea17b35f 100644 --- a/io_uring/wait.c +++ b/io_uring/wait.c @@ -103,7 +103,7 @@ static enum hrtimer_restart io_cqring_min_timer_wakeup(struct hrtimer *timer) } /* any generated CQE posted past this time should wake us up */ - iowq->cq_tail = iowq->cq_min_tail; + iowq->cq_tail = iowq->cq_min_tail + 1; hrtimer_update_function(&iowq->t, io_cqring_timer_wakeup); hrtimer_set_expires(timer, iowq->timeout); diff --git a/sound/core/timer.c b/sound/core/timer.c index 57583dec3974..3d72379e57a8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -430,6 +430,8 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, if (timer) { guard(spinlock_irq)(&timer->lock); + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) + return; /* already closed */ timeri->flags |= SNDRV_TIMER_IFLG_DEAD; } @@ -975,18 +977,18 @@ EXPORT_SYMBOL(snd_timer_new); static int snd_timer_free(struct snd_timer *timer) { + struct snd_timer_instance *ti, *n; + if (!timer) return 0; guard(mutex)(®ister_mutex); if (! list_empty(&timer->open_list_head)) { - struct list_head *p, *n; - struct snd_timer_instance *ti; - pr_warn("ALSA: timer %p is busy?\n", timer); - list_for_each_safe(p, n, &timer->open_list_head) { - list_del_init(p); - ti = list_entry(p, struct snd_timer_instance, open_list); - ti->timer = NULL; + list_for_each_entry_safe(ti, n, &timer->open_list_head, open_list) { + struct device *card_dev_to_put = NULL; + + snd_timer_close_locked(ti, &card_dev_to_put); + put_device(card_dev_to_put); } } list_del(&timer->device_list); @@ -1809,6 +1811,7 @@ static int snd_timer_user_params(struct file *file, struct snd_timer *t; int err; + guard(mutex)(®ister_mutex); tu = file->private_data; if (!tu->timeri) return -EBADFD; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index b426cda529a9..ce229f5d0d46 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -808,6 +808,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "MS-17LN"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "PM1403CDA"), + } + }, {} }; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a637e22c3929..ca630c9948e4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -679,6 +679,9 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) { struct wm_coeff_ctl *ctl = cs_ctl->priv; + if (!ctl) + return; + cancel_work_sync(&ctl->work); kfree(ctl->name); diff --git a/sound/soc/loongson/loongson_dma.c b/sound/soc/loongson/loongson_dma.c index a149b643175c..f3ed14a48bd5 100644 --- a/sound/soc/loongson/loongson_dma.c +++ b/sound/soc/loongson/loongson_dma.c @@ -199,6 +199,7 @@ loongson_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct device *dev = substream->pcm->card->dev; struct loongson_runtime_data *prtd = runtime->private_data; struct loongson_dma_desc *desc; snd_pcm_uframes_t x; @@ -207,9 +208,16 @@ loongson_pcm_pointer(struct snd_soc_component *component, desc = dma_desc_save(prtd); addr = ((u64)desc->saddr_hi << 32) | desc->saddr; - x = bytes_to_frames(runtime, addr - runtime->dma_addr); - if (x == runtime->buffer_size) + if (addr < runtime->dma_addr || + addr > runtime->dma_addr + runtime->dma_bytes) { + dev_warn(dev, "WARNING! dma_addr:0x%llx\n", addr); x = 0; + } else { + x = bytes_to_frames(runtime, addr - runtime->dma_addr); + if (x == runtime->buffer_size) + x = 0; + } + return x; } diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c index feacfbc6a518..b5ca98283a88 100644 --- a/sound/soc/sdca/sdca_function_device.c +++ b/sound/soc/sdca/sdca_function_device.c @@ -82,6 +82,9 @@ static struct sdca_dev *sdca_dev_register(struct device *parent, static void sdca_dev_unregister(struct sdca_dev *sdev) { + if (!sdev) + return; + auxiliary_device_delete(&sdev->auxdev); auxiliary_device_uninit(&sdev->auxdev); } @@ -90,14 +93,24 @@ int sdca_dev_register_functions(struct sdw_slave *slave) { struct sdca_device_data *sdca_data = &slave->sdca_data; int i; + int ret; for (i = 0; i < sdca_data->num_functions; i++) { struct sdca_dev *func_dev; func_dev = sdca_dev_register(&slave->dev, &sdca_data->function[i]); - if (IS_ERR(func_dev)) - return PTR_ERR(func_dev); + if (IS_ERR(func_dev)) { + ret = PTR_ERR(func_dev); + /* + * Unregister functions that were successfully + * registered before this failure. This also + * sets func_dev to NULL so the caller will not + * try to unregister them again. + */ + sdca_dev_unregister_functions(slave); + return ret; + } sdca_data->function[i].func_dev = func_dev; } @@ -111,7 +124,12 @@ void sdca_dev_unregister_functions(struct sdw_slave *slave) struct sdca_device_data *sdca_data = &slave->sdca_data; int i; - for (i = 0; i < sdca_data->num_functions; i++) + for (i = 0; i < sdca_data->num_functions; i++) { + if (!sdca_data->function[i].func_dev) + continue; + sdca_dev_unregister(sdca_data->function[i].func_dev); + sdca_data->function[i].func_dev = NULL; + } } EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA"); diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 3cd4674dd800..94025bc799ea 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -181,14 +181,14 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) } dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write); - if (dsp_msg) { + if (dsp_msg == ACP_DSP_MSG_SET) { snd_sof_ipc_msgs_rx(sdev); acp_dsp_ipc_host_done(sdev); ipc_irq = true; } dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write); - if (dsp_ack) { + if (dsp_ack == ACP_DSP_ACK_SET) { if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { guard(spinlock_irq)(&sdev->ipc_lock); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index f615b8d1c802..e6af8927baa0 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -377,6 +377,33 @@ void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, snd_sof_dsp_write(sdev, ACP_DSP_BAR, reg_offset + i, src[j]); } +static int acp_init_scratch_mem_ipc_flags(struct snd_sof_dev *sdev) +{ + u32 dsp_msg_write, dsp_ack_write, host_msg_write, host_ack_write; + + dsp_msg_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_dsp_msg_write); + dsp_ack_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_dsp_ack_write); + host_msg_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_host_msg_write); + host_ack_write = sdev->debug_box.offset + + offsetof(struct scratch_ipc_conf, sof_host_ack_write); + /* Initialize host message write flag */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg_write, 0); + + /* Initialize host ack write flag */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_ack_write, 0); + + /* Initialize DSP message write flag */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write, 0); + + /* Initialize DSP ack write flag */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write, 0); + + return 0; +} + static int acp_memory_init(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; @@ -384,6 +411,7 @@ static int acp_memory_init(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET, ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK); + acp_init_scratch_mem_ipc_flags(sdev); init_dma_descriptor(adata); return 0; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 2b7ea8c64106..7bcb76676a98 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -116,6 +116,8 @@ #define ACP_SRAM_PAGE_COUNT 128 #define ACP6X_SDW_MAX_MANAGER_COUNT 2 #define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT +#define ACP_DSP_MSG_SET 1 +#define ACP_DSP_ACK_SET 1 enum clock_source { ACP_CLOCK_96M = 0, |
