From 02768612caf6e756f21add16e2484a3a95581f00 Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Fri, 7 Jun 2019 16:05:07 +0530 Subject: [PATCH 1/5] msm: qcn: Enable QCN SDIO client driver for compilation Add QCN SDIO client driver config into Makefile and Kconfig to enable its compilation. Change-Id: I40ffa1844b2030aca53d0e36f1bee2900a3ea8d4 Signed-off-by: Amandeep Singh --- drivers/char/Kconfig | 7 +++++++ drivers/char/Makefile | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index c5c403866816..efdff5d16c5d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -633,5 +633,12 @@ config MSM_RDBG for a debugger running on a host PC to communicate with a remote stub running on peripheral subsystems such as the ADSP, MODEM etc. +config QCOM_SDIO_CLIENT + bool "QCOM_SDIO_CLIENT support" + depends on SDIO_QCN + default y + help + Interface used for SDIO and sahara user spce application + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 77697b8c42c0..dc00ba448d20 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -67,3 +67,4 @@ ifdef CONFIG_COMPAT obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o endif obj-$(CONFIG_MSM_RDBG) += rdbg.o +obj-$(CONFIG_QCOM_SDIO_CLIENT) += qti_sdio_client.o From d1c96aa388a1a5b59d5a45caf226b9980f38604e Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Fri, 7 Jun 2019 16:07:58 +0530 Subject: [PATCH 2/5] msm: qcn: Enable QCN SDIO core driver for compilation Add QCN SDIO core diver config into Makefile and Kconfig to enable its compilation. Change-Id: I19d184c628658175179d9b5c52a3a8bd07dd7999 Signed-off-by: Amandeep Singh --- drivers/platform/msm/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index f2a0d7e1ba1c..75145aad0557 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SEEMP_CORE) += seemp_core/ obj-$(CONFIG_USB_BAM) += usb_bam.o obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o +obj-$(CONFIG_SDIO_QCN) += qcn/ From 31c76861574b45120c478838f8d69efe21a2a26f Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Wed, 24 Jul 2019 11:30:29 +0530 Subject: [PATCH 3/5] msm: qcn: Add dynamic add and remove of SDIO card Add API to dynamically add and remove the SDIO card on demand. Change-Id: I946115880da75804a6636616d9cf7cfb4a682b92 Signed-off-by: Amandeep Singh --- drivers/platform/msm/qcn/qcn_sdio.c | 90 ++++++++++++++++++++++++++++- include/linux/qcn_sdio_al.h | 1 + 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/qcn/qcn_sdio.c b/drivers/platform/msm/qcn/qcn_sdio.c index 71787acd6940..18bca8b2e13c 100644 --- a/drivers/platform/msm/qcn/qcn_sdio.c +++ b/drivers/platform/msm/qcn/qcn_sdio.c @@ -33,6 +33,8 @@ module_param(rx_dump, bool, S_IRUGO | S_IWUSR | S_IWGRP); static int dump_len = 32; module_param(dump_len, int, S_IRUGO | S_IWUSR | S_IWGRP); +static struct mmc_host *current_host; + #define HEX_DUMP(mode, buf, len) \ print_hex_dump(KERN_ERR, mode, 2, 32, 4, buf, \ dump_len > len ? len : dump_len, 0) @@ -65,6 +67,8 @@ static struct list_head cinfo_head; static atomic_t status; static spinlock_t async_lock; +static int qcn_create_sysfs(struct device *dev); + #if (QCN_SDIO_META_VER_0) #define META_INFO(event, data) \ ((u32)((u32)data << QCN_SDIO_HMETA_DATA_SHFT) | \ @@ -587,6 +591,18 @@ static int qcn_sdio_recv_buff(u32 cid, void *buff, size_t len) return ret; } +static void qcn_sdio_purge_rw_buff(void) +{ + struct qcn_sdio_rw_info *rw_req = NULL; + + while (!list_empty(&sdio_ctxt->rw_wait_q)) { + rw_req = list_first_entry(&sdio_ctxt->rw_wait_q, + struct qcn_sdio_rw_info, list); + list_del(&rw_req->list); + qcn_sdio_free_rw_req(rw_req); + } +} + static void qcn_sdio_rw_work(struct work_struct *work) { int ret = 0; @@ -685,11 +701,14 @@ int qcn_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) qcn_enable_async_irq(true); sdio_release_host(sdio_ctxt->func); + if (qcn_read_meta_info()) { pr_err("%s: Error: SDIO Config\n", __func__); qcn_send_meta_info((u8)QCN_SDIO_SW_MODE_HEVENT, (u32)0); } + current_host = func->card->host; + return 0; err: kfree(sdio_ctxt); @@ -702,7 +721,13 @@ static void qcn_sdio_remove(struct sdio_func *func) struct qcn_sdio_client_info *cinfo = NULL; struct qcn_sdio_ch_info *ch_info = NULL; + sdio_claim_host(sdio_ctxt->func); qcn_enable_async_irq(false); + sdio_release_host(sdio_ctxt->func); + + qcn_sdio_purge_rw_buff(); + + destroy_workqueue(sdio_ctxt->qcn_sdio_wq); mutex_lock(&lock); list_for_each_entry(cinfo, &cinfo_head, cli_list) { while (!list_empty(&cinfo->ch_head)) { @@ -711,11 +736,18 @@ static void qcn_sdio_remove(struct sdio_func *func) sdio_al_deregister_channel(&ch_info->ch_handle); } mutex_unlock(&lock); - cinfo->cli_data.remove(&cinfo->cli_handle); + if (cinfo->is_probed) { + cinfo->cli_data.remove(&cinfo->cli_handle); + cinfo->is_probed = 0; + } mutex_lock(&lock); } mutex_unlock(&lock); - destroy_workqueue(sdio_ctxt->qcn_sdio_wq); + + sdio_claim_host(sdio_ctxt->func); + sdio_release_irq(sdio_ctxt->func); + sdio_release_host(sdio_ctxt->func); + kfree(sdio_ctxt); sdio_ctxt = NULL; } @@ -752,6 +784,8 @@ static int qcn_sdio_plat_probe(struct platform_device *pdev) init_completion(&client_probe_complete); + qcn_create_sysfs(&pdev->dev); + return ret; } @@ -1120,3 +1154,55 @@ int sdio_al_meta_transfer(struct sdio_al_channel_handle *handle, return qcn_send_meta_info(event, data); } EXPORT_SYMBOL(sdio_al_meta_transfer); + +int qcn_sdio_card_state(bool enable) +{ + int ret = 0; + + if (!current_host) + return -ENODEV; + + mmc_try_claim_host(current_host, 2000); + if (enable) { + ret = mmc_add_host(current_host); + if (ret) + pr_err("%s ret = %d\n", __func__, ret); + } else { + mmc_remove_host(current_host); + } + mmc_release_host(current_host); + + return ret; +} +EXPORT_SYMBOL(qcn_sdio_card_state); + +static ssize_t qcn_card_state(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int state = 0; + + if (sscanf(buf, "%du", &state) != 1) + return -EINVAL; + + qcn_sdio_card_state(state); + + return count; +} +static DEVICE_ATTR(card_state, 0220, NULL, qcn_card_state); + +static int qcn_create_sysfs(struct device *dev) +{ + int ret = 0; + + ret = device_create_file(dev, &dev_attr_card_state); + if (ret) { + pr_err("Failed to create device file, err = %d\n", ret); + goto out; + } + + return 0; +out: + return ret; +} diff --git a/include/linux/qcn_sdio_al.h b/include/linux/qcn_sdio_al.h index 97d8aa189735..bee020b0ccb4 100644 --- a/include/linux/qcn_sdio_al.h +++ b/include/linux/qcn_sdio_al.h @@ -292,4 +292,5 @@ int sdio_al_meta_transfer(struct sdio_al_channel_handle *ch_handle, unsigned int data, unsigned int trans); extern void qcn_sdio_client_probe_complete(int id); +int qcn_sdio_card_state(bool enable); #endif /* _QCN_SDIO_AL_ */ From ae6070aa42bfab695c8e94c23944e6c28b6deb6f Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Wed, 24 Jul 2019 11:36:25 +0530 Subject: [PATCH 4/5] qti_sdio_client: Drop read write request during removal Update read write API to drop further messages during transport or interface removal. Change-Id: Ied43de8aa7cef1c36c9c520976357ba1e63017db Signed-off-by: Amandeep Singh --- drivers/char/qti_sdio_client.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/char/qti_sdio_client.c b/drivers/char/qti_sdio_client.c index 4904c1be83d0..0f34621c12eb 100644 --- a/drivers/char/qti_sdio_client.c +++ b/drivers/char/qti_sdio_client.c @@ -80,7 +80,7 @@ static bool to_console; module_param(to_console, bool, S_IRUGO | S_IWUSR | S_IWGRP); -static bool ipc_log = 1; +static bool ipc_log; module_param(ipc_log, bool, S_IRUGO | S_IWUSR | S_IWGRP); @@ -143,7 +143,7 @@ struct qti_sdio_bridge { unsigned int mdata_count; unsigned int tx_ready_count; unsigned int data_avail_count; - + atomic_t is_client_closing; }; struct data_avail_node { @@ -282,7 +282,7 @@ void qti_client_data_avail_cb(struct sdio_al_channel_handle *ch_handle, ret = sdio_al_queue_transfer(qsb->channel_handle, SDIO_AL_RX, rx_dma_buf, padded_len, 0); if (ret == 1) { - pr_err("TRACK: operating in async mode now\n"); + pr_debug("operating in async mode now\n"); goto out; } if (ret) { @@ -413,9 +413,10 @@ int qti_client_read(int id, char *buf, size_t count) int bytes = 0; struct qti_sdio_bridge *qsb = NULL; - if ((id < QCN_SDIO_CLI_ID_TTY) || (id > QCN_SDIO_CLI_ID_DIAG)) { + if ((id < QCN_SDIO_CLI_ID_TTY) || (id > QCN_SDIO_CLI_ID_DIAG) || + atomic_read(&qsbdev[id]->is_client_closing)) { pr_err("%s invalid client ID %d\n", __func__, id); - return ret; + return -ENODEV; } qsb = qsbdev[id]; @@ -428,7 +429,10 @@ int qti_client_read(int id, char *buf, size_t count) goto out; } - wait_event(qsb->wait_q, qsb->data_avail); + wait_event(qsb->wait_q, qsb->data_avail || + atomic_read(&qsb->is_client_closing)); + if (atomic_read(&qsb->is_client_closing)) + return count; bytes = qsb->data_avail; @@ -496,6 +500,9 @@ int qti_client_write(int id, char *buf, size_t count) struct qti_sdio_bridge *qsb = NULL; DECLARE_COMPLETION_ONSTACK(tx_complete); + if (atomic_read(&qsbdev[id]->is_client_closing)) + return -ENODEV; + switch (id) { case QCN_SDIO_CLI_ID_TTY: event = TTY_TX_BUF_SZ_EVENT; @@ -572,7 +579,10 @@ int qti_client_write(int id, char *buf, size_t count) qlog(qsb, "MDATA: %x\n", mdata); qsb->mdata_count++; - wait_event(qsb->wait_q, qsb->tx_ready); + wait_event(qsb->wait_q, qsb->tx_ready || + atomic_read(&qsb->is_client_closing)); + if (atomic_read(&qsb->is_client_closing)) + return count; if (qsb->mode) { reinit_completion(&tx_complete); @@ -865,6 +875,7 @@ static int qti_client_probe(struct sdio_al_client_handle *client_handle) qsb->priv_dev_info = diag_pdev; } + atomic_set(&qsb->is_client_closing, 0); qlog(qsb, "probed client %s\n", qsb->name); return 0; @@ -905,8 +916,12 @@ static int qti_client_remove(struct sdio_al_client_handle *client_handle) } qsb = qsbdev[client_handle->id]; + + atomic_set(&qsb->is_client_closing, 1); + wake_up(&qsb->wait_q); + tty_dev = (struct tty_device *)qsb->priv_dev_info; - if (tty_dev->qsb_device && client_handle->id == QCN_SDIO_CLI_ID_TTY) { + if (client_handle->id == QCN_SDIO_CLI_ID_TTY && tty_dev->qsb_device) { minor_no = MINOR(tty_dev->qsb_device->devt); major_no = MAJOR(tty_dev->qsb_device->devt); device_destroy(tty_dev->qsb_class, MKDEV(major_no, minor_no)); From 2ca7eb28dcac93fcf0818232e10fe51f43acfac1 Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Wed, 24 Jul 2019 11:46:12 +0530 Subject: [PATCH 5/5] mmc: sdhci-msm: Ping with known good phase Ping with known good phase if last phase of tuning fails. Change-Id: I3d8d8ce3d8a4dc00146668b815b69619d3a4cea8 Signed-off-by: Amandeep Singh --- drivers/mmc/host/sdhci-msm.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a7bd93f4eedb..a7afa467d32f 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2,7 +2,7 @@ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform * driver source file * - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1288,6 +1288,34 @@ retry: } else { pr_debug("%s: %s: found ## bad ## phase = %d\n", mmc_hostname(mmc), __func__, phase); + + if (phase == 15 && tuned_phase_cnt) { + pr_err("%s: %s: Ping with known good phase\n", + mmc_hostname(mmc), __func__); + /* set the phase in delay line hw block */ + rc = msm_config_cm_dll_phase(host, + tuned_phases[tuned_phase_cnt - 1]); + if (rc) + goto kfree; + + cmd.opcode = opcode; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.timeout_ns = 1000 * 1000 * 1000; + + data.sg = &sg; + data.sg_len = 1; + sg_init_one(&sg, data_buf, size); + memset(data_buf, 0, size); + mmc_wait_for_req(mmc, &mrq); + + if ((cmd.error || data.error)) + pr_err("%s: %s: Ping with known good phase failed\n", + mmc_hostname(mmc), __func__); + } } } while (++phase < 16);