Merge "mmc: sdhci-msm: Ping with known good phase"
This commit is contained in:
commit
8d75d72e2e
7 changed files with 150 additions and 11 deletions
|
@ -633,5 +633,12 @@ config MSM_RDBG
|
||||||
for a debugger running on a host PC to communicate with a remote
|
for a debugger running on a host PC to communicate with a remote
|
||||||
stub running on peripheral subsystems such as the ADSP, MODEM etc.
|
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
|
endmenu
|
||||||
|
|
||||||
|
|
|
@ -67,3 +67,4 @@ ifdef CONFIG_COMPAT
|
||||||
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o
|
obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o
|
||||||
endif
|
endif
|
||||||
obj-$(CONFIG_MSM_RDBG) += rdbg.o
|
obj-$(CONFIG_MSM_RDBG) += rdbg.o
|
||||||
|
obj-$(CONFIG_QCOM_SDIO_CLIENT) += qti_sdio_client.o
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
static bool to_console;
|
static bool to_console;
|
||||||
module_param(to_console, bool, S_IRUGO | S_IWUSR | S_IWGRP);
|
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);
|
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 mdata_count;
|
||||||
unsigned int tx_ready_count;
|
unsigned int tx_ready_count;
|
||||||
unsigned int data_avail_count;
|
unsigned int data_avail_count;
|
||||||
|
atomic_t is_client_closing;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data_avail_node {
|
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,
|
ret = sdio_al_queue_transfer(qsb->channel_handle,
|
||||||
SDIO_AL_RX, rx_dma_buf, padded_len, 0);
|
SDIO_AL_RX, rx_dma_buf, padded_len, 0);
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
pr_err("TRACK: operating in async mode now\n");
|
pr_debug("operating in async mode now\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -413,9 +413,10 @@ int qti_client_read(int id, char *buf, size_t count)
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
struct qti_sdio_bridge *qsb = NULL;
|
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);
|
pr_err("%s invalid client ID %d\n", __func__, id);
|
||||||
return ret;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsb = qsbdev[id];
|
qsb = qsbdev[id];
|
||||||
|
@ -428,7 +429,10 @@ int qti_client_read(int id, char *buf, size_t count)
|
||||||
goto out;
|
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;
|
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;
|
struct qti_sdio_bridge *qsb = NULL;
|
||||||
DECLARE_COMPLETION_ONSTACK(tx_complete);
|
DECLARE_COMPLETION_ONSTACK(tx_complete);
|
||||||
|
|
||||||
|
if (atomic_read(&qsbdev[id]->is_client_closing))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case QCN_SDIO_CLI_ID_TTY:
|
case QCN_SDIO_CLI_ID_TTY:
|
||||||
event = TTY_TX_BUF_SZ_EVENT;
|
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);
|
qlog(qsb, "MDATA: %x\n", mdata);
|
||||||
qsb->mdata_count++;
|
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) {
|
if (qsb->mode) {
|
||||||
reinit_completion(&tx_complete);
|
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;
|
qsb->priv_dev_info = diag_pdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_set(&qsb->is_client_closing, 0);
|
||||||
qlog(qsb, "probed client %s\n", qsb->name);
|
qlog(qsb, "probed client %s\n", qsb->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -905,8 +916,12 @@ static int qti_client_remove(struct sdio_al_client_handle *client_handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
qsb = qsbdev[client_handle->id];
|
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;
|
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);
|
minor_no = MINOR(tty_dev->qsb_device->devt);
|
||||||
major_no = MAJOR(tty_dev->qsb_device->devt);
|
major_no = MAJOR(tty_dev->qsb_device->devt);
|
||||||
device_destroy(tty_dev->qsb_class, MKDEV(major_no, minor_no));
|
device_destroy(tty_dev->qsb_class, MKDEV(major_no, minor_no));
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
|
* drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
|
||||||
* driver source file
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -1288,6 +1288,34 @@ retry:
|
||||||
} else {
|
} else {
|
||||||
pr_debug("%s: %s: found ## bad ## phase = %d\n",
|
pr_debug("%s: %s: found ## bad ## phase = %d\n",
|
||||||
mmc_hostname(mmc), __func__, phase);
|
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);
|
} while (++phase < 16);
|
||||||
|
|
||||||
|
|
|
@ -16,3 +16,4 @@ obj-$(CONFIG_SEEMP_CORE) += seemp_core/
|
||||||
obj-$(CONFIG_USB_BAM) += usb_bam.o
|
obj-$(CONFIG_USB_BAM) += usb_bam.o
|
||||||
obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
|
obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
|
||||||
obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
|
obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
|
||||||
|
obj-$(CONFIG_SDIO_QCN) += qcn/
|
||||||
|
|
|
@ -33,6 +33,8 @@ module_param(rx_dump, bool, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||||
static int dump_len = 32;
|
static int dump_len = 32;
|
||||||
module_param(dump_len, int, S_IRUGO | S_IWUSR | S_IWGRP);
|
module_param(dump_len, int, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||||
|
|
||||||
|
static struct mmc_host *current_host;
|
||||||
|
|
||||||
#define HEX_DUMP(mode, buf, len) \
|
#define HEX_DUMP(mode, buf, len) \
|
||||||
print_hex_dump(KERN_ERR, mode, 2, 32, 4, buf, \
|
print_hex_dump(KERN_ERR, mode, 2, 32, 4, buf, \
|
||||||
dump_len > len ? len : dump_len, 0)
|
dump_len > len ? len : dump_len, 0)
|
||||||
|
@ -65,6 +67,8 @@ static struct list_head cinfo_head;
|
||||||
static atomic_t status;
|
static atomic_t status;
|
||||||
static spinlock_t async_lock;
|
static spinlock_t async_lock;
|
||||||
|
|
||||||
|
static int qcn_create_sysfs(struct device *dev);
|
||||||
|
|
||||||
#if (QCN_SDIO_META_VER_0)
|
#if (QCN_SDIO_META_VER_0)
|
||||||
#define META_INFO(event, data) \
|
#define META_INFO(event, data) \
|
||||||
((u32)((u32)data << QCN_SDIO_HMETA_DATA_SHFT) | \
|
((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;
|
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)
|
static void qcn_sdio_rw_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
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);
|
qcn_enable_async_irq(true);
|
||||||
sdio_release_host(sdio_ctxt->func);
|
sdio_release_host(sdio_ctxt->func);
|
||||||
|
|
||||||
if (qcn_read_meta_info()) {
|
if (qcn_read_meta_info()) {
|
||||||
pr_err("%s: Error: SDIO Config\n", __func__);
|
pr_err("%s: Error: SDIO Config\n", __func__);
|
||||||
qcn_send_meta_info((u8)QCN_SDIO_SW_MODE_HEVENT, (u32)0);
|
qcn_send_meta_info((u8)QCN_SDIO_SW_MODE_HEVENT, (u32)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_host = func->card->host;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
kfree(sdio_ctxt);
|
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_client_info *cinfo = NULL;
|
||||||
struct qcn_sdio_ch_info *ch_info = NULL;
|
struct qcn_sdio_ch_info *ch_info = NULL;
|
||||||
|
|
||||||
|
sdio_claim_host(sdio_ctxt->func);
|
||||||
qcn_enable_async_irq(false);
|
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);
|
mutex_lock(&lock);
|
||||||
list_for_each_entry(cinfo, &cinfo_head, cli_list) {
|
list_for_each_entry(cinfo, &cinfo_head, cli_list) {
|
||||||
while (!list_empty(&cinfo->ch_head)) {
|
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);
|
sdio_al_deregister_channel(&ch_info->ch_handle);
|
||||||
}
|
}
|
||||||
mutex_unlock(&lock);
|
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_lock(&lock);
|
||||||
}
|
}
|
||||||
mutex_unlock(&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);
|
kfree(sdio_ctxt);
|
||||||
sdio_ctxt = NULL;
|
sdio_ctxt = NULL;
|
||||||
}
|
}
|
||||||
|
@ -752,6 +784,8 @@ static int qcn_sdio_plat_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
init_completion(&client_probe_complete);
|
init_completion(&client_probe_complete);
|
||||||
|
|
||||||
|
qcn_create_sysfs(&pdev->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1120,3 +1154,55 @@ int sdio_al_meta_transfer(struct sdio_al_channel_handle *handle,
|
||||||
return qcn_send_meta_info(event, data);
|
return qcn_send_meta_info(event, data);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sdio_al_meta_transfer);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -292,4 +292,5 @@ int sdio_al_meta_transfer(struct sdio_al_channel_handle *ch_handle,
|
||||||
unsigned int data, unsigned int trans);
|
unsigned int data, unsigned int trans);
|
||||||
|
|
||||||
extern void qcn_sdio_client_probe_complete(int id);
|
extern void qcn_sdio_client_probe_complete(int id);
|
||||||
|
int qcn_sdio_card_state(bool enable);
|
||||||
#endif /* _QCN_SDIO_AL_ */
|
#endif /* _QCN_SDIO_AL_ */
|
||||||
|
|
Loading…
Add table
Reference in a new issue