From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7A24A4D09EF for ; Mon, 12 Oct 2026 18:18:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791829125; cv=none; b=ocq+aJyE++hdWRpIq/pPaIHBmtv1kGFk43VK9kbwaiPVmv2WPMjWAKeV3nYPUiJpNBz+nuDRaODBKMA9u0PgcHdlHOl1Nri+6wfcBBR2+gujmQvNj21otHOzQab60xz01WFnvQcBtjMD7cp517O9bD9dDysS8iLtr7OGmihuPIo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791829125; c=relaxed/simple; bh=dBPq6l9rURFDunzSNUlT+sZaqzcP3Ytbz7tKxF9fipg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gmvylQFQZO18vT1jbjAAsK31atELc6EJiV61iZB0/Zg8WMfHEpBXheSkP3qa7H8q0FkhxnEayKnslYkhU0OrNA1Vkames+e+WAs7lYXPbFF2Rx7fKP815+RF0UGAB48EhXLXCRbGKw09XzASgeYCIdKqZNIwCo6u88EtjZRff0U= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=Mn28HAZ0; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=f7PjLIGq; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="Mn28HAZ0"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="f7PjLIGq" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 69CHv6m23466887 for ; Mon, 12 Oct 2026 18:18:42 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= HIVGEDll2jp2JXJq4ICnIXt8TxFWZic/DxVsb7WJmMg=; b=Mn28HAZ0FI6We+OW T0wfNcdjlhZwIM7wexMjhIngubXrsfodCZZ6EDUqDy2hWPpVnxpTYxltzhMqEXOA IAdRL3XoKXZvkQuZAXvloTtGKwzGkCoU7dHYnUnU3NJ/sW9xWDdGv7e0u8AWXayP SV5R4zxAcxt/8KirYmMZ9B1D0HkplopdvPacLXtz81aB8IkxmiBPpffTK5gswptv k9i7HatlY1rJB6c2IGZVZM1hyllYR+nXvV7UTvyHK0WXUvGD+nndlDc56BQmZEw+ hm1ILghy1gazCNdnZja90PA64XmH4388z47GwD9zx5TZxU3c1BSfLMQDGE8TTIPR suWjTA== Received: from mail-dy1-f197.google.com (mail-dy1-f197.google.com [74.125.82.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4h8sd1udjf-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Mon, 12 Oct 2026 18:18:42 +0000 (GMT) Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-33c35f5ca6cso5315702eec.1 for ; Mon, 12 Oct 2026 11:18:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1791829121; x=1792433921; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=HIVGEDll2jp2JXJq4ICnIXt8TxFWZic/DxVsb7WJmMg=; b=f7PjLIGqWUGjmPj/YesWgSQSxrpkKE1xlyM4HbYkv/rSf9cM6N2Yp2HHp4onXNmcFn NydY3fFqD+HOPMrLT1EhVbOHE3n8JfY5CpK1apmkRNLVWmyN2nv3M1hqIeXvUdAdof7f 8KX78y3ZhBGZZbNFpwJA9FzQCxTdmWXlFUcChTYOH/SfIOFJn6jbHUhSzHk70EkDGvRr O2T6KZaSfoFuQYihsiUyeJF+ZPyHYRs7FatnjCUbEP8QPdfdrj/b2FAL/2B9OH02nVzR pbxO4bhwoy7Nbbjg5b0f4BF0/58SYzcmCW7HIWJEt4s3itCA7NoafV5H/UmJlx0K/IUc n2hg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791829121; x=1792433921; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=HIVGEDll2jp2JXJq4ICnIXt8TxFWZic/DxVsb7WJmMg=; b=qUXHRA6ZHp6s/HfyFs+dTPRii/2l1Qos4lHHBIwO3WTvxd3gw+c50NKLm2xk8n7jQL UciMYqKjl1x96w3RUjegg5ZFi4SUQJ7bQch7PZpUGrZG51ad/sVtqAh9Q2dGDOEtRn3F ar657DGe+QyPuFe+IOJYX7GDAy15HG1Pgfk6ZTs4UJt+WnGKyxJA9qr/LLwQdyRU+XSZ BeqXVZOjYBuw7xvPi9041mDZgRQOtBf0gfTuqETBUQyUe/c4jqfD49V/qjKB+iXlYBmI B4abU5wU6sASe0vtuQ0AdzLPjTT1MsenIuUbbbM7Meqo85LjcsuV0PU/viuULfllxJOX 9OyA== X-Forwarded-Encrypted: i=1; AKwUvBzXkE0ynM4thC43PLzUR4h4uAK2Fuch1/SMM/ZV0zLy9abkwzupzgKke1Z5+i9Of0FKSqFYzDs8UPZEyDo=@vger.kernel.org X-Gm-Message-State: AFq9FYLGRaz82f9QvhNQLaawjwLHpJc+nQBIak7rJTIkiQGbU5GjxpCZ wSvtq3oWvDiXszFuRrIirMhRXVmFycb5zterNDQK1e16m7xT5LyiQdUA8YRiusRMPJh43yqspD4 +EZ59FaKgDABIf9eIKvWwoUZOlJ05TSW9vm2JOj2bkloaIMofYG5IHNqrBIfqzUT6Lzs= X-Gm-Gg: AYBFou1ZC8QnUGYoMu+UDsFNjoPR8TNpAGdTQP73q1YNH88B3rfEUV/aVqbcsfrR+zn Rr3zdff6vVsdFZ6SBUM6HbCJbdLEn1TGwp1G3tblYRIwDL08Q+EEl3kXTa3uxuB/0cWyrofPr3K xtvMt95H8CvDxTKFwIjaQbtZTbKBOFEqCgkf3aFmRDUNPDDzK4kYu1dXxtP+fLA2V3fT1druvqY OZvgjwJDoDGxD6NfX96hJDiJld0WeqlAxJUq5mkugnNWk6OsIEi1kjsLiJBFgjeWnuc1MJhWg2w FqNmAqLRpHM8uJm7Imw17wa1C/YzlqDvuMYD2DFlcIl+b6Ab7qBXq6RRWKlol/gGi7Qi9EGM0T2 Gk1AWzNEeanwWTROh+JFN0y6fRhdc X-Received: by 2002:a05:7301:1:b0:35b:9bd:1435 with SMTP id 5a478bee46e88-35b09bd1510mr3697166eec.2.1791829121085; Mon, 12 Oct 2026 11:18:41 -0700 (PDT) X-Received: by 2002:a05:7301:1:b0:35b:9bd:1435 with SMTP id 5a478bee46e88-35b09bd1510mr3697113eec.2.1791829120281; Mon, 12 Oct 2026 11:18:40 -0700 (PDT) Received: from hu-batta-hyd.qualcomm.com ([202.46.23.25]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-358de54fe47sm22827311eec.31.2026.10.12.11.18.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Oct 2026 11:18:39 -0700 (PDT) From: Kishore Batta Date: Mon, 12 Oct 2026 23:48:04 +0530 Subject: [PATCH v8 6/7] bus: mhi: Capture DDR training data via command mode Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20261012-sahara_protocol_new_v2-v8-6-e12939d229a1@oss.qualcomm.com> References: <20261012-sahara_protocol_new_v2-v8-0-e12939d229a1@oss.qualcomm.com> In-Reply-To: <20261012-sahara_protocol_new_v2-v8-0-e12939d229a1@oss.qualcomm.com> To: Jonathan Corbet , Shuah Khan , Jeff Hugo , Carl Vanderlip , Oded Gabbay , Manivannan Sadhasivam , Randy Dunlap Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, mhi@lists.linux.dev, Kishore Batta X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1791829086; l=15044; i=kishore.batta@oss.qualcomm.com; s=20260206; h=from:subject:message-id; bh=dBPq6l9rURFDunzSNUlT+sZaqzcP3Ytbz7tKxF9fipg=; b=mR4VvIdnx4JMnR0dloxSQCy3bY/aYGnrE0+4wBzxUApizAdrZJh0Ix3Sn4OdK/3xY3s6ywuj1 LmFd5/f5GkfDbggtoibDpenniczUhUq8t/z3BY/IvwhvoJOJuLC42/k X-Developer-Key: i=kishore.batta@oss.qualcomm.com; a=ed25519; pk=vJo8RvTf+HZpRLK2oOIljmbn9l3zFkibCGh+blaqZCw= X-Proofpoint-ORIG-GUID: zr25IYuPqxJiktlFke8IyZaWKISxWmTw X-Proofpoint-Spam-Info: AW1haW4tMjYxMDEyMDA3MiBTYWx0ZWRfX6yU0n7Y3JC+R FCPu23gMfOa4ZiPvo+VC0DpPQp+7rJKDcOJUKlQU6kTQfeZNccqX8jnbIKlYUODzy5RGohrTctY M/RYSamXffnf2iwFkW1sXySM7VD9DYE= X-Authority-Analysis: v=2.4 cv=QtHLTlyd c=1 sm=1 tr=0 ts=6acd2482 cx=c_pps a=Uww141gWH0fZj/3QKPojxA==:117 a=ZePRamnt/+rB5gQjfz0u9A==:17 a=IkcTkHD0fZMA:10 a=660iZSQnnn4A:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=EUspDBNiAAAA:8 a=_u4x-iUupSARUiuVX_kA:9 a=QEXdDO2ut3YA:10 a=PxkB5W3o20Ba91AHUih5:22 X-Proofpoint-GUID: zr25IYuPqxJiktlFke8IyZaWKISxWmTw X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYxMDEyMDA3MiBTYWx0ZWRfX0p3OkB3Uy0Vp khJV1Zu7a2gCBpPkEuyHTV//+iayNcQ2xivhwNaPH2AubByWK+d7emDeMe7K5I581PGRd7FVkyH B3DvW3tRbXnVZjT9Meyf2alpmvWd98Dltn30iiDwTvLbKCjIZwbyyx50vdrSnKuce5FUTpLQa2H o3oP/8xJicFAFxz3enNWI9T+ar/BlmM456IlSTr08TckG3AEbNv2gvobQlp/x1sv0nvi8MHVvBg SFIVckAL8PbYgMAQuyAWWuOIplkoaNWU2Rq6KJ+olWCXkH6EaXciZyNp7aYJIaJC4FIeVwbqxwB KHM0J2JTG0EkuoLFiTn9+3gp9zPqWyVBwzicpTR/BnqICQtUuE7zagfNQIVWk0yS04oHY1SfCux zjZxKxZPenofZxPoonNGAdTHT75E160VQKi6HtjZKt1X01jQ0an+Zn5mFUYZaUyNMJxArA1DfCL hEp95HKDM53k3FLzpLA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-10-12_05,2026-10-09_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 bulkscore=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 impostorscore=0 phishscore=0 adultscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2610080000 definitions=main-2610120072 During early boot, devices may perform DDR training and produce training data that can be reused on subsequent boots to reduce initialization time. The Sahara protocol provides a command mode flow to transfer this training data to the host, but the driver currently does not handle command mode and drops the training payload. Add Sahara command mode support to retrieve DDR training data from the device. When the device enters command mode and sends CMD_READY, query the support command list(ID 8) and request DDR training data(ID 9) using EXECUTE and EXECUTE_DATA as defined by protocol. Allocate receive buffers based on the reported response size and copy the raw payload directly from the MHI DL completion callback. Store the captured training data in controller-scoped memory using devres, so it remains available after Sahara channel teardown. Also distinguish raw payload completion from control packets in the DL callback, avoiding misinterpretation of training data as protocol messages, and requeue the RX buffer after switching back to IMAGE_TX_PENDING to allow the boot flow to continue. Signed-off-by: Kishore Batta --- drivers/bus/mhi/host/clients/sahara/sahara.c | 326 ++++++++++++++++++++++++++- 1 file changed, 319 insertions(+), 7 deletions(-) diff --git a/drivers/bus/mhi/host/clients/sahara/sahara.c b/drivers/bus/mhi/host/clients/sahara/sahara.c index afb72910fd67b225cd77c44d7e835cae138c2ffb..e7a6289b11a72d5dda008d6107eff6b4f9b67519 100644 --- a/drivers/bus/mhi/host/clients/sahara/sahara.c +++ b/drivers/bus/mhi/host/clients/sahara/sahara.c @@ -5,11 +5,14 @@ */ #include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -59,7 +62,15 @@ #define SAHARA_RESET_LENGTH 0x8 #define SAHARA_MEM_DEBUG64_LENGTH 0x18 #define SAHARA_MEM_READ64_LENGTH 0x18 +#define SAHARA_COMMAND_READY_LENGTH 0x8 +#define SAHARA_COMMAND_EXEC_RESP_LENGTH 0x10 +#define SAHARA_COMMAND_EXECUTE_LENGTH 0xc +#define SAHARA_COMMAND_EXEC_DATA_LENGTH 0xc +#define SAHARA_SWITCH_MODE_LENGTH 0xc +#define SAHARA_EXEC_CMD_GET_COMMAND_ID_LIST 0x8 +#define SAHARA_EXEC_CMD_GET_TRAINING_DATA 0x9 #define SAHARA_DDR_TRAINING_IMG_ID 34 +#define SAHARA_NUM_CMD_BUF SAHARA_NUM_TX_BUF struct sahara_packet { __le32 cmd; @@ -95,6 +106,19 @@ struct sahara_packet { __le64 memory_address; __le64 memory_length; } memory_read64; + struct { + __le32 client_command; + } command_execute; + struct { + __le32 client_command; + __le32 response_length; + } command_execute_resp; + struct { + __le32 client_command; + } command_exec_data; + struct { + __le32 mode; + } mode_switch; }; }; @@ -161,6 +185,7 @@ struct sahara_context { struct work_struct fw_work; struct work_struct dump_work; struct work_struct read_data_work; + struct work_struct cmd_work; struct mhi_device *mhi_dev; const char * const *image_table; u32 table_size; @@ -181,6 +206,24 @@ struct sahara_context { bool is_mem_dump_mode; bool non_streaming; const char *fw_folder; + bool is_cmd_mode; + bool receiving_training_data; + size_t training_size; + size_t training_rcvd; + u32 training_nbuf; + char *cmd_buff[SAHARA_NUM_CMD_BUF]; +}; + +/* + * Controller-scoped training data store (per MHI controller device). + * Stored as devres resource on mhi_dev->mhi_cntrl->mhi_dev->dev. + */ +struct sahara_cntrl_training_data { + struct mutex lock; /* Protects data, size, copied and receiving */ + void *data; + size_t size; + size_t copied; + bool receiving; }; static bool is_streaming(struct sahara_context *context) @@ -188,6 +231,48 @@ static bool is_streaming(struct sahara_context *context) return !context->non_streaming; } +static void sahara_cntrl_training_release(struct device *dev, void *res) +{ + struct sahara_cntrl_training_data *ct = res; + + mutex_lock(&ct->lock); + kfree(ct->data); + ct->data = NULL; + ct->size = 0; + ct->copied = 0; + ct->receiving = false; + mutex_unlock(&ct->lock); +} + +static int sahara_cntrl_training_match(struct device *dev, void *res, void *match_data) +{ + /* Exactly one instance per controller */ + return 1; +} + +static struct sahara_cntrl_training_data *sahara_cntrl_training_get(struct device *dev) +{ + struct sahara_cntrl_training_data *ct; + + ct = devres_find(dev, sahara_cntrl_training_release, + sahara_cntrl_training_match, NULL); + if (ct) + return ct; + + ct = devres_alloc(sahara_cntrl_training_release, sizeof(*ct), GFP_KERNEL); + if (!ct) + return NULL; + + mutex_init(&ct->lock); + ct->data = NULL; + ct->size = 0; + ct->copied = 0; + ct->receiving = false; + + devres_add(dev, ct); + return ct; +} + static int sahara_find_image(struct sahara_context *context, u32 image_id) { char *fw_path; @@ -281,6 +366,11 @@ static void sahara_send_reset(struct sahara_context *context) context->is_mem_dump_mode = false; context->read_data_offset = 0; context->read_data_length = 0; + context->is_cmd_mode = false; + context->receiving_training_data = false; + context->training_size = 0; + context->training_rcvd = 0; + context->training_nbuf = 0; context->tx[0]->cmd = cpu_to_le32(SAHARA_RESET_CMD); context->tx[0]->length = cpu_to_le32(SAHARA_RESET_LENGTH); @@ -316,7 +406,8 @@ static void sahara_hello(struct sahara_context *context) if (le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_PENDING && le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_COMPLETE && - le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_MEMORY_DEBUG) { + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_MEMORY_DEBUG && + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_COMMAND) { dev_err(&context->mhi_dev->dev, "Unsupported hello packet - mode %d\n", le32_to_cpu(context->rx->hello.mode)); return; @@ -335,6 +426,153 @@ static void sahara_hello(struct sahara_context *context) dev_err(&context->mhi_dev->dev, "Unable to send hello response %d\n", ret); } +static void sahara_switch_mode_to_img_tx(struct sahara_context *context) +{ + int ret; + + context->tx[0]->cmd = cpu_to_le32(SAHARA_SWITCH_MODE_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_SWITCH_MODE_LENGTH); + context->tx[0]->mode_switch.mode = cpu_to_le32(SAHARA_MODE_IMAGE_TX_PENDING); + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_SWITCH_MODE_LENGTH, MHI_EOT); + + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to send mode switch %d\n", ret); +} + +static void sahara_command_execute(struct sahara_context *context, u32 client_command) +{ + int ret; + + context->tx[0]->cmd = cpu_to_le32(SAHARA_EXECUTE_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_COMMAND_EXECUTE_LENGTH); + context->tx[0]->command_execute.client_command = cpu_to_le32(client_command); + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_COMMAND_EXECUTE_LENGTH, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to send command execute %d\n", ret); +} + +static void sahara_command_execute_data(struct sahara_context *context, u32 client_command) +{ + int ret; + + context->tx[0]->cmd = cpu_to_le32(SAHARA_EXECUTE_DATA_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_COMMAND_EXEC_DATA_LENGTH); + context->tx[0]->command_exec_data.client_command = cpu_to_le32(client_command); + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_COMMAND_EXEC_DATA_LENGTH, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to send execute data %d\n", ret); +} + +static void sahara_command_ready(struct sahara_context *context) +{ + if (le32_to_cpu(context->rx->length) != SAHARA_COMMAND_READY_LENGTH) { + dev_err(&context->mhi_dev->dev, + "Malformed command ready packet - length %u\n", + le32_to_cpu(context->rx->length)); + return; + } + + context->is_cmd_mode = true; + context->receiving_training_data = false; + + sahara_command_execute(context, SAHARA_EXEC_CMD_GET_COMMAND_ID_LIST); +} + +static void sahara_command_execute_resp(struct sahara_context *context) +{ + struct device *dev = &context->mhi_dev->mhi_cntrl->mhi_dev->dev; + struct sahara_cntrl_training_data *ct; + u32 client_cmd, resp_len; + int ret; + u64 remaining; + u32 i; + + if (le32_to_cpu(context->rx->length) != SAHARA_COMMAND_EXEC_RESP_LENGTH || + le32_to_cpu(context->rx->command_execute_resp.response_length) < 0) { + dev_err(&context->mhi_dev->dev, + "Malformed command execute resp packet - length %d\n", + le32_to_cpu(context->rx->length)); + return; + } + + client_cmd = le32_to_cpu(context->rx->command_execute_resp.client_command); + resp_len = le32_to_cpu(context->rx->command_execute_resp.response_length); + + sahara_command_execute_data(context, client_cmd); + + if (client_cmd == SAHARA_EXEC_CMD_GET_COMMAND_ID_LIST) { + sahara_command_execute(context, SAHARA_EXEC_CMD_GET_TRAINING_DATA); + return; + } + + if (client_cmd != SAHARA_EXEC_CMD_GET_TRAINING_DATA) + return; + + ct = sahara_cntrl_training_get(dev); + if (!ct) { + context->is_cmd_mode = false; + sahara_switch_mode_to_img_tx(context); + return; + } + + mutex_lock(&ct->lock); + kfree(ct->data); + ct->data = kzalloc(resp_len, GFP_KERNEL); + ct->size = resp_len; + ct->copied = 0; + ct->receiving = true; + mutex_unlock(&ct->lock); + + if (!ct->data) { + context->is_cmd_mode = false; + sahara_switch_mode_to_img_tx(context); + return; + } + + context->training_size = resp_len; + context->training_rcvd = 0; + context->receiving_training_data = true; + + remaining = resp_len; + for (i = 0; i < SAHARA_NUM_CMD_BUF && remaining; i++) { + size_t pkt = min_t(size_t, remaining, SAHARA_PACKET_MAX_SIZE); + + ret = mhi_queue_buf(context->mhi_dev, DMA_FROM_DEVICE, + context->cmd_buff[i], pkt, + (remaining <= pkt) ? MHI_EOT : MHI_CHAIN); + if (ret) + break; + + remaining -= pkt; + } + + context->training_nbuf = i; +} + +static void sahara_command_processing(struct work_struct *work) +{ + struct sahara_context *context = container_of(work, struct sahara_context, cmd_work); + int ret; + + if (le32_to_cpu(context->rx->cmd) == SAHARA_EXECUTE_RESP_CMD) + sahara_command_execute_resp(context); + + if (!context->receiving_training_data) { + ret = mhi_queue_buf(context->mhi_dev, DMA_FROM_DEVICE, + context->rx, SAHARA_PACKET_MAX_SIZE, MHI_EOT); + + if (ret) + dev_err(&context->mhi_dev->dev, + "Unable to requeue rx buf %d\n", ret); + } +} + static int read_data_helper(struct sahara_context *context, int buf_index) { enum mhi_flags mhi_flag; @@ -561,6 +799,9 @@ static void sahara_processing(struct work_struct *work) case SAHARA_MEM_DEBUG64_CMD: sahara_memory_debug64(context); break; + case SAHARA_CMD_READY_CMD: + sahara_command_ready(context); + break; default: dev_err(&context->mhi_dev->dev, "Unknown command %d\n", le32_to_cpu(context->rx->cmd)); @@ -861,6 +1102,20 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_ INIT_WORK(&context->fw_work, sahara_processing); INIT_WORK(&context->dump_work, sahara_dump_processing); INIT_WORK(&context->read_data_work, sahara_read_data_processing); + INIT_WORK(&context->cmd_work, sahara_command_processing); + + for (i = 0; i < SAHARA_NUM_CMD_BUF; i++) { + context->cmd_buff[i] = devm_kzalloc(&mhi_dev->dev, + SAHARA_PACKET_MAX_SIZE, GFP_KERNEL); + if (!context->cmd_buff[i]) + return -ENOMEM; + } + + context->is_cmd_mode = false; + context->receiving_training_data = false; + context->training_size = 0; + context->training_rcvd = 0; + context->training_nbuf = 0; context->active_image_id = SAHARA_IMAGE_ID_NONE; dev_set_drvdata(&mhi_dev->dev, context); @@ -884,6 +1139,7 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev) cancel_work_sync(&context->fw_work); cancel_work_sync(&context->dump_work); + cancel_work_sync(&context->cmd_work); vfree(context->mem_dump); sahara_release_image(context); mhi_unprepare_from_transfer(mhi_dev); @@ -900,15 +1156,71 @@ static void sahara_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result static void sahara_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev); + struct sahara_cntrl_training_data *ct; + struct device *dev; + size_t copy; + int ret; + u32 i; + + if (mhi_result->transaction_status) + return; + + /* + * Raw training payload completions arrive for cmd_buff[] buffers. + * Do not schedule cmd_work for those. + */ + if (context->is_cmd_mode && context->receiving_training_data && + mhi_result->buf_addr != context->rx) { + dev = &context->mhi_dev->mhi_cntrl->mhi_dev->dev; + ct = sahara_cntrl_training_get(dev); + if (!ct) + return; - if (!mhi_result->transaction_status) { - context->rx_size = mhi_result->bytes_xferd; - if (context->is_mem_dump_mode) - schedule_work(&context->dump_work); - else - schedule_work(&context->fw_work); + for (i = 0; i < context->training_nbuf; i++) { + if (mhi_result->buf_addr == context->cmd_buff[i]) { + mutex_lock(&ct->lock); + copy = min_t(size_t, mhi_result->bytes_xferd, + ct->size - ct->copied); + memcpy((u8 *)ct->data + ct->copied, + mhi_result->buf_addr, copy); + ct->copied += copy; + mutex_unlock(&ct->lock); + + context->training_rcvd += copy; + + if (context->training_rcvd >= context->training_size) { + mutex_lock(&ct->lock); + ct->receiving = false; + mutex_unlock(&ct->lock); + + context->receiving_training_data = false; + context->is_cmd_mode = false; + + sahara_switch_mode_to_img_tx(context); + ret = mhi_queue_buf(context->mhi_dev, + DMA_FROM_DEVICE, + context->rx, + SAHARA_PACKET_MAX_SIZE, + MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, + "Unable to requeue rx buf %d\n", ret); + } + return; + } + } + return; } + /* Normal Rx completion */ + context->rx_size = mhi_result->bytes_xferd; + if (context->is_mem_dump_mode) + schedule_work(&context->dump_work); + else if (context->is_cmd_mode) + schedule_work(&context->cmd_work); + else + schedule_work(&context->fw_work); + } static const struct mhi_device_id sahara_mhi_match_table[] = { -- 2.34.1