diff options
Diffstat (limited to 'drivers')
32 files changed, 496 insertions, 207 deletions
diff --git a/drivers/clk/msm/clock-debug.c b/drivers/clk/msm/clock-debug.c index 00a86ba55171..0fe93ede17cc 100644 --- a/drivers/clk/msm/clock-debug.c +++ b/drivers/clk/msm/clock-debug.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007-2014, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2007-2014, 2016-2017, The Linux Foundation. All rights + * reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -77,6 +78,7 @@ static int clock_debug_measure_get(void *data, u64 *val) else is_hw_gated = 0; + mutex_lock(&clock->prepare_lock); ret = clk_set_parent(measure, clock); if (!ret) { /* @@ -107,6 +109,7 @@ static int clock_debug_measure_get(void *data, u64 *val) */ meas_rate = clk_get_rate(clock); sw_rate = clk_get_rate(measure->parent); + mutex_unlock(&clock->prepare_lock); if (sw_rate && meas_rate >= (sw_rate * 2)) *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate); diff --git a/drivers/clk/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c index 2a112aad1fa3..eb543010c17b 100644 --- a/drivers/clk/msm/clock-mmss-8998.c +++ b/drivers/clk/msm/clock-mmss-8998.c @@ -527,6 +527,7 @@ static struct clk_freq_tbl ftbl_csiphy_clk_src[] = { static struct clk_freq_tbl ftbl_csiphy_clk_src_vq[] = { F_MM( 164570000, mmpll10_pll_out, 3.5, 0, 0), F_MM( 256000000, mmpll4_pll_out, 3, 0, 0), + F_MM( 274290000, mmpll7_pll_out, 3.5, 0, 0), F_MM( 300000000, mmsscc_gpll0, 2, 0, 0), F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), F_END diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index 076ff3565ef4..d8ae85b65a47 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -818,7 +818,7 @@ static struct clk_rcg2 hmss_rbcpr_clk_src = { .parent_names = gcc_parent_names_ao_1, .num_parents = 3, .ops = &clk_rcg2_ops, - VDD_DIG_FMAX_MAP2( + VDD_DIG_FMAX_MAP2_AO( LOWER, 19200000, NOMINAL, 50000000), }, diff --git a/drivers/clk/qcom/vdd-level-660.h b/drivers/clk/qcom/vdd-level-660.h index f98a96033ea9..53317fe6d294 100644 --- a/drivers/clk/qcom/vdd-level-660.h +++ b/drivers/clk/qcom/vdd-level-660.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 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 @@ -95,6 +95,14 @@ }, \ .num_rate_max = VDD_DIG_NUM +#define VDD_DIG_FMAX_MAP2_AO(l1, f1, l2, f2) \ + .vdd_class = &vdd_dig_ao, \ + .rate_max = (unsigned long[VDD_DIG_NUM]) { \ + [VDD_DIG_##l1] = (f1), \ + [VDD_DIG_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_DIG_NUM + #define VDD_DIG_FMAX_MAP3_AO(l1, f1, l2, f2, l3, f3) \ .vdd_class = &vdd_dig_ao, \ .rate_max = (unsigned long[VDD_DIG_NUM]) { \ diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c index 433e4783d1d1..9ab03209b680 100644 --- a/drivers/crypto/msm/qcedev.c +++ b/drivers/crypto/msm/qcedev.c @@ -1,6 +1,6 @@ /* Qualcomm CE device driver. * - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, 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 @@ -1381,7 +1381,7 @@ static int qcedev_check_cipher_key(struct qcedev_cipher_op_req *req, /* if not using HW key make sure key * length is valid */ - if ((req->mode == QCEDEV_AES_MODE_XTS)) { + if (req->mode == QCEDEV_AES_MODE_XTS) { if ((req->encklen != QCEDEV_AES_KEY_128*2) && (req->encklen != QCEDEV_AES_KEY_256*2)) { pr_err("%s: unsupported key size: %d\n", diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index cd9a82a9bf4a..fe6aa45901d0 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, 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 @@ -1994,6 +1994,42 @@ static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level) return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate); } +static inline void _close_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->pcl) + msm_bus_scale_unregister_client(pwr->pcl); + + pwr->pcl = 0; +} + +static inline void _close_ocmem_pcl(struct kgsl_pwrctrl *pwr) +{ + if (pwr->ocmem_pcl) + msm_bus_scale_unregister_client(pwr->ocmem_pcl); + + pwr->ocmem_pcl = 0; +} + +static inline void _close_regulators(struct kgsl_pwrctrl *pwr) +{ + int i; + + for (i = 0; i < KGSL_MAX_REGULATORS; i++) + pwr->regulators[i].reg = NULL; +} + +static inline void _close_clks(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int i; + + for (i = 0; i < KGSL_MAX_CLKS; i++) + pwr->grp_clks[i] = NULL; + + if (pwr->gpu_bimc_int_clk) + devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); +} + int kgsl_pwrctrl_init(struct kgsl_device *device) { int i, k, m, n = 0, result; @@ -2011,7 +2047,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = _get_clocks(device); if (result) - return result; + goto error_cleanup_clks; /* Make sure we have a source clk for freq setting */ if (pwr->grp_clks[0] == NULL) @@ -2029,7 +2065,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) if (pwr->num_pwrlevels == 0) { KGSL_PWR_ERR(device, "No power levels are defined\n"); - return -EINVAL; + result = -EINVAL; + goto error_cleanup_clks; } /* Initialize the user and thermal clock constraints */ @@ -2059,7 +2096,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) result = get_regulators(device); if (result) - return result; + goto error_cleanup_regulators; pwr->power_flags = 0; @@ -2079,8 +2116,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->ocmem_pcl = msm_bus_scale_register_client (ocmem_scale_table); - if (!pwr->ocmem_pcl) - return -EINVAL; + if (!pwr->ocmem_pcl) { + result = -EINVAL; + goto error_disable_pm; + } } /* Bus width in bytes, set it to zero if not found */ @@ -2110,14 +2149,18 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) * from the driver. */ pwr->pcl = msm_bus_scale_register_client(bus_scale_table); - if (pwr->pcl == 0) - return -EINVAL; + if (pwr->pcl == 0) { + result = -EINVAL; + goto error_cleanup_ocmem_pcl; + } } pwr->bus_ib = kzalloc(bus_scale_table->num_usecases * sizeof(*pwr->bus_ib), GFP_KERNEL); - if (pwr->bus_ib == NULL) - return -ENOMEM; + if (pwr->bus_ib == NULL) { + result = -ENOMEM; + goto error_cleanup_pcl; + } /* * Pull the BW vote out of the bus table. They will be used to @@ -2175,36 +2218,26 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) &pwr->tsens_name); return result; + +error_cleanup_pcl: + _close_pcl(pwr); +error_cleanup_ocmem_pcl: + _close_ocmem_pcl(pwr); +error_disable_pm: + pm_runtime_disable(&pdev->dev); +error_cleanup_regulators: + _close_regulators(pwr); +error_cleanup_clks: + _close_clks(device); + return result; } void kgsl_pwrctrl_close(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int i; KGSL_PWR_INFO(device, "close device %d\n", device->id); - pm_runtime_disable(&device->pdev->dev); - - if (pwr->pcl) - msm_bus_scale_unregister_client(pwr->pcl); - - pwr->pcl = 0; - - if (pwr->ocmem_pcl) - msm_bus_scale_unregister_client(pwr->ocmem_pcl); - - pwr->ocmem_pcl = 0; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->regulators[i].reg = NULL; - - for (i = 0; i < KGSL_MAX_REGULATORS; i++) - pwr->grp_clks[i] = NULL; - - if (pwr->gpu_bimc_int_clk) - devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk); - pwr->power_flags = 0; if (!IS_ERR_OR_NULL(pwr->sysfs_pwr_limit)) { @@ -2213,6 +2246,16 @@ void kgsl_pwrctrl_close(struct kgsl_device *device) pwr->sysfs_pwr_limit = NULL; } kfree(pwr->bus_ib); + + _close_pcl(pwr); + + _close_ocmem_pcl(pwr); + + pm_runtime_disable(&device->pdev->dev); + + _close_regulators(pwr); + + _close_clks(device); } /** diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 70766e208217..fbe2302c4037 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -3531,8 +3531,10 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) smmu->num_clocks = of_property_count_strings(dev->of_node, "clock-names"); - if (smmu->num_clocks < 1) + if (smmu->num_clocks < 1) { + smmu->num_clocks = 0; return 0; + } smmu->clocks = devm_kzalloc( dev, sizeof(*smmu->clocks) * smmu->num_clocks, diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index ea5ac972b096..590e4c1a3f52 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017 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 @@ -467,12 +467,29 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) return rc; } +#define MAX_I2C_RETRIES 3 +static int i2c_pmic_read(struct regmap *map, unsigned int reg, void *val, + size_t val_count) +{ + int rc, retries = 0; + + do { + rc = regmap_bulk_read(map, reg, val, val_count); + } while (rc == -ENOTCONN && retries++ < MAX_I2C_RETRIES); + + if (retries > 1) + pr_err("i2c_pmic_read failed for %d retries, rc = %d\n", + retries - 1, rc); + + return rc; +} + static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) { int rc, i; for (i = 0; i < chip->num_periphs; i++) { - rc = regmap_bulk_read(chip->regmap, + rc = i2c_pmic_read(chip->regmap, chip->periph[i].addr | INT_SET_TYPE_OFFSET, chip->periph[i].cached, IRQ_MAX_REGS); if (rc < 0) { diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 3d346d85d45a..1653f7e1ae99 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4432,6 +4432,7 @@ int qseecom_start_app(struct qseecom_handle **handle, strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; + kfree(entry); goto err; } entry->app_arch = app_arch; diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 57cc6b29b2d0..9e0ccdc44d6b 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,6 +2,17 @@ # MMC core configuration # +config MMC_RING_BUFFER + bool "MMC_RING_BUFFER" + depends on MMC + default n + help + This enables the ring buffer tracing of significant + events for mmc driver to provide command history for + debugging purpose. + + If unsure, say N. + config MMC_EMBEDDED_SDIO boolean "MMC embedded SDIO device support (EXPERIMENTAL)" help diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2c25138f28b7..60781dd192ab 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,3 +10,4 @@ mmc_core-y := core.o bus.o host.o \ quirks.o slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MMC_RING_BUFFER) += ring_buffer.o diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c894f64c2e38..a0d31ded04db 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -32,6 +32,26 @@ module_param(fail_request, charp, 0); #endif /* CONFIG_FAIL_MMC_REQUEST */ /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ +static int mmc_ring_buffer_show(struct seq_file *s, void *data) +{ + struct mmc_host *mmc = s->private; + + mmc_dump_trace_buffer(mmc, s); + return 0; +} + +static int mmc_ring_buffer_open(struct inode *inode, struct file *file) +{ + return single_open(file, mmc_ring_buffer_show, inode->i_private); +} + +static const struct file_operations mmc_ring_buffer_fops = { + .open = mmc_ring_buffer_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int mmc_ios_show(struct seq_file *s, void *data) { static const char *vdd_str[] = { @@ -368,6 +388,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->cmdq_thist_enabled)) goto err_node; +#ifdef CONFIG_MMC_RING_BUFFER + if (!debugfs_create_file("ring_buffer", S_IRUSR, + root, host, &mmc_ring_buffer_fops)) + goto err_node; +#endif #ifdef CONFIG_MMC_CLKGATE if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index f6a54a8e1076..333f691a73c7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -26,6 +26,8 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/ring_buffer.h> + #include <linux/mmc/slot-gpio.h> #include "core.h" @@ -869,6 +871,7 @@ int mmc_add_host(struct mmc_host *host) mmc_add_host_debugfs(host); #endif mmc_host_clk_sysfs_init(host); + mmc_trace_init(host); err = sysfs_create_group(&host->class_dev.kobj, &clk_scaling_attr_grp); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 449514bae4f3..414877874190 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2635,6 +2635,7 @@ static int mmc_suspend(struct mmc_host *host) int err; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_suspend(host, true); if (!err) { pm_runtime_disable(&host->card->dev); @@ -2643,6 +2644,7 @@ static int mmc_suspend(struct mmc_host *host) trace_mmc_suspend(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -2718,6 +2720,7 @@ static int mmc_resume(struct mmc_host *host) int err = 0; ktime_t start = ktime_get(); + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_resume(host); pm_runtime_set_active(&host->card->dev); @@ -2727,7 +2730,7 @@ static int mmc_resume(struct mmc_host *host) trace_mmc_resume(mmc_hostname(host), err, ktime_to_us(ktime_sub(ktime_get(), start))); - + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/ring_buffer.c b/drivers/mmc/core/ring_buffer.c new file mode 100644 index 000000000000..83945e1cae40 --- /dev/null +++ b/drivers/mmc/core/ring_buffer.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mmc/ring_buffer.h> +#include <linux/mmc/host.h> + +void mmc_stop_tracing(struct mmc_host *mmc) +{ + mmc->trace_buf.stop_tracing = true; +} + +void mmc_trace_write(struct mmc_host *mmc, + const char *fmt, ...) +{ + unsigned int idx; + va_list args; + char *event; + unsigned long flags; + char str[MMC_TRACE_EVENT_SZ]; + + if (unlikely(!mmc->trace_buf.data) || + unlikely(mmc->trace_buf.stop_tracing)) + return; + + /* + * Here an increment and modulus is used to keep + * index within array bounds. The cast to unsigned is + * necessary so increment and rolover wraps to 0 correctly + */ + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + mmc->trace_buf.wr_idx += 1; + idx = ((unsigned int)mmc->trace_buf.wr_idx) & + (MMC_TRACE_RBUF_NUM_EVENTS - 1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); + + /* Catch some unlikely machine specific wrap-around bug */ + if (unlikely(idx > (MMC_TRACE_RBUF_NUM_EVENTS - 1))) { + pr_err("%s: %s: Invalid idx:%d for mmc trace, tracing stopped !\n", + mmc_hostname(mmc), __func__, idx); + mmc_stop_tracing(mmc); + return; + } + + event = &mmc->trace_buf.data[idx * MMC_TRACE_EVENT_SZ]; + va_start(args, fmt); + snprintf(str, MMC_TRACE_EVENT_SZ, "<%d> %lld: %s: %s", + raw_smp_processor_id(), + ktime_to_ns(ktime_get()), + mmc_hostname(mmc), fmt); + memset(event, '\0', MMC_TRACE_EVENT_SZ); + vscnprintf(event, MMC_TRACE_EVENT_SZ, str, args); + va_end(args); +} + +void mmc_trace_init(struct mmc_host *mmc) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(MMC_TRACE_RBUF_NUM_EVENTS); + + mmc->trace_buf.data = (char *) + __get_free_pages(GFP_KERNEL|__GFP_ZERO, + MMC_TRACE_RBUF_SZ_ORDER); + + if (!mmc->trace_buf.data) { + pr_err("%s: %s: Unable to allocate trace for mmc\n", + __func__, mmc_hostname(mmc)); + return; + } + + spin_lock_init(&mmc->trace_buf.trace_lock); + mmc->trace_buf.wr_idx = -1; +} + +void mmc_trace_free(struct mmc_host *mmc) +{ + if (mmc->trace_buf.data) + free_pages((unsigned long)mmc->trace_buf.data, + MMC_TRACE_RBUF_SZ_ORDER); +} + +void mmc_dump_trace_buffer(struct mmc_host *mmc, struct seq_file *s) +{ + unsigned int idx, cur_idx; + unsigned int N = MMC_TRACE_RBUF_NUM_EVENTS - 1; + char *event; + unsigned long flags; + + if (!mmc->trace_buf.data) + return; + + spin_lock_irqsave(&mmc->trace_buf.trace_lock, flags); + idx = ((unsigned int)mmc->trace_buf.wr_idx) & N; + cur_idx = (idx + 1) & N; + + do { + event = &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "%s", (char *)event); + else + pr_err("%s", (char *)event); + cur_idx = (cur_idx + 1) & N; + if (cur_idx == idx) { + event = + &mmc->trace_buf.data[cur_idx * MMC_TRACE_EVENT_SZ]; + if (s) + seq_printf(s, "latest_event: %s", + (char *)event); + else + pr_err("latest_event: %s", (char *)event); + break; + } + } while (1); + spin_unlock_irqrestore(&mmc->trace_buf.trace_lock, flags); +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 7b84030ffe92..7e7d7eb4da2a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1222,11 +1222,13 @@ static int mmc_sd_suspend(struct mmc_host *host) { int err; + MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_suspend(host); if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); } + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } @@ -1292,12 +1294,14 @@ static int mmc_sd_resume(struct mmc_host *host) { int err = 0; + MMC_TRACE(host, "%s: Enter\n", __func__); if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { err = _mmc_sd_resume(host); pm_runtime_set_active(&host->card->dev); pm_runtime_mark_last_busy(&host->card->dev); } pm_runtime_enable(&host->card->dev); + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5fedab49cf34..13a2f2d14d12 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -998,6 +998,7 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host) */ static int mmc_sdio_suspend(struct mmc_host *host) { + MMC_TRACE(host, "%s: Enter\n", __func__); mmc_claim_host(host); if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) @@ -1013,7 +1014,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) } mmc_release_host(host); - + MMC_TRACE(host, "%s: Exit\n", __func__); return 0; } @@ -1024,6 +1025,7 @@ static int mmc_sdio_resume(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); + MMC_TRACE(host, "%s: Enter\n", __func__); /* Basic card reinitialization. */ mmc_claim_host(host); @@ -1079,6 +1081,7 @@ static int mmc_sdio_resume(struct mmc_host *host) host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 52427815722b..d712f29da9f1 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017 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 @@ -198,6 +198,14 @@ static void cmdq_dumpregs(struct cmdq_host *cq_host) { struct mmc_host *mmc = cq_host->mmc; + MMC_TRACE(mmc, + "%s: 0x0C=0x%08x 0x10=0x%08x 0x14=0x%08x 0x18=0x%08x 0x28=0x%08x 0x2C=0x%08x 0x30=0x%08x 0x34=0x%08x 0x54=0x%08x 0x58=0x%08x 0x5C=0x%08x 0x48=0x%08x\n", + __func__, cmdq_readl(cq_host, CQCTL), cmdq_readl(cq_host, CQIS), + cmdq_readl(cq_host, CQISTE), cmdq_readl(cq_host, CQISGE), + cmdq_readl(cq_host, CQTDBR), cmdq_readl(cq_host, CQTCN), + cmdq_readl(cq_host, CQDQS), cmdq_readl(cq_host, CQDPT), + cmdq_readl(cq_host, CQTERRI), cmdq_readl(cq_host, CQCRI), + cmdq_readl(cq_host, CQCRA), cmdq_readl(cq_host, CQCRDCT)); pr_err(DRV_NAME ": ========== REGISTER DUMP (%s)==========\n", mmc_hostname(mmc)); @@ -426,6 +434,7 @@ static int cmdq_enable(struct mmc_host *mmc) pm_ref_count: cmdq_runtime_pm_put(cq_host); out: + MMC_TRACE(mmc, "%s: CQ enabled err: %d\n", __func__, err); return err; } @@ -443,6 +452,7 @@ static void cmdq_disable_nosync(struct mmc_host *mmc, bool soft) cq_host->enabled = false; mmc_host_set_cq_disable(mmc); + MMC_TRACE(mmc, "%s: CQ disabled\n", __func__); } static void cmdq_disable(struct mmc_host *mmc, bool soft) @@ -525,6 +535,12 @@ static void cmdq_prep_task_desc(struct mmc_request *mrq, REL_WRITE(!!(req_flags & REL_WR)) | BLK_COUNT(mrq->cmdq_req->data.blocks) | BLK_ADDR((u64)mrq->cmdq_req->blk_addr); + + MMC_TRACE(mrq->host, + "%s: Task: 0x%08x | Args: 0x%08x | cnt: 0x%08x\n", __func__, + lower_32_bits(*data), + upper_32_bits(*data), + mrq->cmdq_req->data.blocks); } static int cmdq_dma_map(struct mmc_host *host, struct mmc_request *mrq) @@ -665,6 +681,11 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc, dataddr = (__le64 __force *)(desc + 4); dataddr[0] = cpu_to_le64((u64)mrq->cmd->arg); cmdq_log_task_desc_history(cq_host, *task_desc, true); + MMC_TRACE(mrq->host, + "%s: DCMD: Task: 0x%08x | Args: 0x%08x\n", + __func__, + lower_32_bits(*task_desc), + upper_32_bits(*task_desc)); } static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq) @@ -743,6 +764,7 @@ ring_doorbell: cmdq_dumpregs(cq_host); BUG_ON(1); } + MMC_TRACE(mmc, "%s: tag: %d\n", __func__, tag); cmdq_writel(cq_host, 1 << tag, CQTDBR); /* Commit the doorbell write immediately */ wmb(); @@ -785,6 +807,8 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (!status && !err) return IRQ_NONE; + MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n", + __func__, status, err); if (err || (status & CQIS_RED)) { err_info = cmdq_readl(cq_host, CQTERRI); @@ -920,7 +944,9 @@ skip_cqterri: /* complete the corresponding mrq */ pr_debug("%s: completing tag -> %lu\n", mmc_hostname(mmc), tag); - cmdq_finish_data(mmc, tag); + MMC_TRACE(mmc, "%s: completing tag -> %lu\n", + __func__, tag); + cmdq_finish_data(mmc, tag); } } @@ -997,6 +1023,8 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) retries--; continue; } else { + MMC_TRACE(mmc, "%s: halt done , retries: %d\n", + __func__, retries); /* halt done: re-enable legacy interrupts */ if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, @@ -1014,6 +1042,7 @@ static int cmdq_halt(struct mmc_host *mmc, bool halt) cq_host->ops->set_data_timeout(mmc, 0xf); if (cq_host->ops->clear_set_irqs) cq_host->ops->clear_set_irqs(mmc, true); + MMC_TRACE(mmc, "%s: unhalt done\n", __func__); cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT, CQCTL); } diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index abf2ae2020c9..2ef459582aae 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -102,7 +102,7 @@ int sdhci_msm_ice_init(struct sdhci_host *host) struct sdhci_msm_host *msm_host = pltfm_host->priv; int err = 0; - if (msm_host->ice.vops->config) { + if (msm_host->ice.vops->init) { err = msm_host->ice.vops->init(msm_host->ice.pdev, msm_host, sdhci_msm_ice_error_cb); @@ -148,9 +148,10 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, req = mrq->req; if (req) { lba = req->__sector; - if (msm_host->ice.vops->config) { - err = msm_host->ice.vops->config(msm_host->ice.pdev, - req, &ice_set); + if (msm_host->ice.vops->config_start) { + err = msm_host->ice.vops->config_start( + msm_host->ice.pdev, + req, &ice_set, false); if (err) { pr_err("%s: ice config failed %d\n", mmc_hostname(host->mmc), err); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 203daf3bd5eb..466e0a2c8483 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-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, 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 @@ -3293,6 +3293,11 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); + MMC_TRACE(host->mmc, "Data cnt: 0x%08x | Fifo cnt: 0x%08x\n", + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_DATA_CNT), + sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_MCI_FIFO_CNT)); pr_info("Data cnt: 0x%08x | Fifo cnt: 0x%08x | Int sts: 0x%08x\n", sdhci_msm_readl_relaxed(host, msm_host_offset->CORE_MCI_DATA_CNT), diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 08822464d82f..3fd564388720 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -111,6 +111,17 @@ static void sdhci_dump_state(struct sdhci_host *host) static void sdhci_dumpregs(struct sdhci_host *host) { + MMC_TRACE(host->mmc, + "%s: 0x04=0x%08x 0x06=0x%08x 0x0E=0x%08x 0x30=0x%08x 0x34=0x%08x 0x38=0x%08x\n", + __func__, + sdhci_readw(host, SDHCI_BLOCK_SIZE), + sdhci_readw(host, SDHCI_BLOCK_COUNT), + sdhci_readw(host, SDHCI_COMMAND), + sdhci_readl(host, SDHCI_INT_STATUS), + sdhci_readl(host, SDHCI_INT_ENABLE), + sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); + mmc_stop_tracing(host->mmc); + pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); @@ -1013,6 +1024,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* Set the DMA boundary value and block size */ sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG); sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + MMC_TRACE(host->mmc, + "%s: 0x28=0x%08x 0x3E=0x%08x 0x06=0x%08x\n", __func__, + sdhci_readb(host, SDHCI_HOST_CONTROL), + sdhci_readw(host, SDHCI_HOST_CONTROL2), + sdhci_readw(host, SDHCI_BLOCK_COUNT)); } static void sdhci_set_transfer_mode(struct sdhci_host *host, @@ -1071,6 +1087,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); + MMC_TRACE(host->mmc, "%s: 0x00=0x%08x 0x0C=0x%08x\n", __func__, + sdhci_readw(host, SDHCI_ARGUMENT2), + sdhci_readw(host, SDHCI_TRANSFER_MODE)); } static void sdhci_finish_data(struct sdhci_host *host) @@ -1082,6 +1101,8 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; + MMC_TRACE(host->mmc, "%s: 0x24=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_PRESENT_STATE)); if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); @@ -1210,6 +1231,11 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (cmd->data) host->data_start_time = ktime_get(); trace_mmc_cmd_rw_start(cmd->opcode, cmd->arg, cmd->flags); + MMC_TRACE(host->mmc, + "%s: updated 0x8=0x%08x 0xC=0x%08x 0xE=0x%08x\n", __func__, + sdhci_readl(host, SDHCI_ARGUMENT), + sdhci_readw(host, SDHCI_TRANSFER_MODE), + sdhci_readw(host, SDHCI_COMMAND)); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); @@ -1231,8 +1257,14 @@ static void sdhci_finish_command(struct sdhci_host *host) sdhci_readb(host, SDHCI_RESPONSE + (3-i)*4-1); } + MMC_TRACE(host->mmc, + "%s: resp 0: 0x%08x resp 1: 0x%08x resp 2: 0x%08x resp 3: 0x%08x\n", + __func__, host->cmd->resp[0], host->cmd->resp[1], + host->cmd->resp[2], host->cmd->resp[3]); } else { host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE); + MMC_TRACE(host->mmc, "%s: resp 0: 0x%08x\n", + __func__, host->cmd->resp[0]); } } @@ -3169,6 +3201,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } + MMC_TRACE(host->mmc, + "%s: intmask: 0x%x\n", __func__, intmask); + if (intmask & SDHCI_INT_AUTO_CMD_ERR) host->auto_cmd_err_sts = sdhci_readw(host, SDHCI_AUTO_CMD_ERR); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index a617c9e8e11f..f32d3d9646c1 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, 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 @@ -362,8 +362,13 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt, notify->chan_user_data = ch_ctx->props.chan_user_data; notify->evt_id = evt->code; notify->bytes_xfered = evt->len; - if (callback) + if (callback) { + if (atomic_read(&ch_ctx->poll_mode)) { + GSIERR("Calling client callback in polling mode\n"); + WARN_ON(1); + } ch_ctx->props.xfer_cb(notify); + } } static void gsi_process_evt_re(struct gsi_evt_ctx *ctx, @@ -459,12 +464,12 @@ check_again: ctx->ring.rp = rp; while (ctx->ring.rp_local != rp) { ++cntr; - gsi_process_evt_re(ctx, ¬ify, true); if (ctx->props.exclusive && atomic_read(&ctx->chan->poll_mode)) { cntr = 0; break; } + gsi_process_evt_re(ctx, ¬ify, true); } gsi_ring_evt_doorbell(ctx); if (cntr != 0) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index d3f7e43ea10e..62d8ae0c5f36 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1216,11 +1216,9 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (!chg->external_vconn) { rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat); - if (rc < 0) { + if (rc < 0) smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n", rc); - return rc; - } /* check if VCONN is enabled on either CC pin */ if (stat & VCONN_EN_CC_MASK) { @@ -1229,7 +1227,6 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev) if (rc < 0) smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc); - return rc; } } diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index 9c4d89ac704d..d3f44ab75f67 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -1222,12 +1222,18 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } - if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { - comm_partition.partition_num = num; - comm_partition.offset = entry->offset; - comm_partition.size_cacheline = entry->size_cacheline; - SMEM_INFO("Common Partition %d offset:%x\n", num, - entry->offset); + if (is_comm_partition) { + if (hdr->host0 == SMEM_COMM_HOST + && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + } else { + LOG_ERR("Smem Comm partition hosts don't match TOC\n"); + WARN_ON(1); + } return; } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index e7307c46a895..8a501d4d0615 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -215,7 +215,7 @@ static void send_ind_ack(struct work_struct *work) if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) pr_err("QMI request failed 0x%x\n", QMI_RESP_BIT_SHIFT(resp.resp.error)); - pr_debug("Indication ACKed for transid %d, service %s, instance %d!\n", + pr_info("Indication ACKed for transid %d, service %s, instance %d!\n", data->ind_msg.transaction_id, data->ind_msg.service_path, data->instance_id); } @@ -240,7 +240,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, return; } - pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n", + pr_info("Indication received from %s, state: 0x%x, trans-id: %d\n", ind_msg.service_name, ind_msg.curr_state, ind_msg.transaction_id); diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 7aa04a4fa156..b81348ceb469 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2017, 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 @@ -45,8 +45,6 @@ #include <linux/msm-bus-board.h> #include "spi_qsd.h" -#define SPI_MAX_BYTES_PER_WORD (4) - static int msm_spi_pm_resume_runtime(struct device *device); static int msm_spi_pm_suspend_runtime(struct device *device); static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd); @@ -440,12 +438,10 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) u32 data_in; int i; int shift; - int read_bytes = (dd->pack_words ? - SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO); if (dd->read_buf) { - for (i = 0; (i < read_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->rx_bytes_remaining; i++) { /* The data format depends on bytes_per_word: 4 bytes: 0x12345678 @@ -458,8 +454,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd) dd->rx_bytes_remaining--; } } else { - if (dd->rx_bytes_remaining >= read_bytes) - dd->rx_bytes_remaining -= read_bytes; + if (dd->rx_bytes_remaining >= dd->bytes_per_word) + dd->rx_bytes_remaining -= dd->bytes_per_word; else dd->rx_bytes_remaining = 0; } @@ -556,7 +552,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n) if (n != (*config & SPI_CFG_N)) *config = (*config & ~SPI_CFG_N) | n; - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { if (dd->read_buf == NULL) *config |= SPI_NO_INPUT; if (dd->write_buf == NULL) @@ -621,34 +617,25 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw) static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words) { /* - * For FIFO mode: - * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0 - * - Set the READ/WRITE_COUNT registers to 0 (infinite mode) - * or num bytes (finite mode) if less than fifo worth of data. - * For Block mode: - * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes. - * - Set the READ/WRITE_COUNT registers to 0. + * n_words cannot exceed fifo_size, and only one READ COUNT + * interrupt is generated per transaction, so for transactions + * larger than fifo size READ COUNT must be disabled. + * For those transactions we usually move to Data Mover mode. */ - if (dd->tx_mode != SPI_BAM_MODE) { - if (dd->tx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - msm_spi_set_write_count(dd, n_words); - else - msm_spi_set_write_count(dd, 0); - writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT); - - if (dd->rx_mode == SPI_FIFO_MODE) { - if (n_words <= dd->input_fifo_size) - writel_relaxed(n_words, - dd->base + SPI_MX_READ_COUNT); - else - writel_relaxed(0, - dd->base + SPI_MX_READ_COUNT); + if (dd->mode == SPI_FIFO_MODE) { + if (n_words <= dd->input_fifo_size) { + writel_relaxed(n_words, + dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, n_words); + } else { + writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); + msm_spi_set_write_count(dd, 0); + } + if (dd->qup_ver == SPI_QUP_VERSION_BFAM) { + /* must be zero for FIFO */ writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT); - } else - writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT); + writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT); + } } else { /* must be zero for BAM and DMOV */ writel_relaxed(0, dd->base + SPI_MX_READ_COUNT); @@ -895,7 +882,7 @@ xfr_err: static int msm_spi_bam_next_transfer(struct msm_spi *dd) { - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) return 0; if (dd->tx_bytes_remaining > 0) { @@ -914,7 +901,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd) static int msm_spi_dma_send_next(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_next_transfer(dd); return ret; } @@ -945,38 +932,32 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id) } op = readl_relaxed(dd->base + SPI_OPERATIONAL); - writel_relaxed(op, dd->base + SPI_OPERATIONAL); - /* - * Ensure service flag was cleared before further - * processing of interrupt. - */ - mb(); if (op & SPI_OP_INPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_input_irq(irq, dev_id); } if (op & SPI_OP_OUTPUT_SERVICE_FLAG) { + writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG, + dd->base + SPI_OPERATIONAL); + /* + * Ensure service flag was cleared before further + * processing of interrupt. + */ + mb(); ret |= msm_spi_output_irq(irq, dev_id); } - if (dd->tx_mode != SPI_BAM_MODE) { - if (!dd->rx_done) { - if (dd->rx_bytes_remaining == 0) - dd->rx_done = true; - } - if (!dd->tx_done) { - if (!dd->tx_bytes_remaining && - (op & SPI_OP_IP_FIFO_NOT_EMPTY)) { - dd->tx_done = true; - } - } - } - if (dd->tx_done && dd->rx_done) { - msm_spi_set_state(dd, SPI_OP_STATE_RESET); - dd->tx_done = false; - dd->rx_done = false; + if (dd->done) { complete(&dd->rx_transfer_complete); complete(&dd->tx_transfer_complete); + dd->done = 0; } return ret; } @@ -987,23 +968,17 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id) dd->stat_rx++; - if (dd->rx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; - if (dd->rx_mode == SPI_FIFO_MODE) { + if (dd->mode == SPI_FIFO_MODE) { while ((readl_relaxed(dd->base + SPI_OPERATIONAL) & SPI_OP_IP_FIFO_NOT_EMPTY) && (dd->rx_bytes_remaining > 0)) { msm_spi_read_word_from_fifo(dd); } - } else if (dd->rx_mode == SPI_BLOCK_MODE) { - int count = 0; - - while (dd->rx_bytes_remaining && - (count < dd->input_block_size)) { - msm_spi_read_word_from_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + if (dd->rx_bytes_remaining == 0) + msm_spi_complete(dd); } return IRQ_HANDLED; @@ -1014,20 +989,18 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd) u32 word; u8 byte; int i; - int write_bytes = - (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word); word = 0; if (dd->write_buf) { - for (i = 0; (i < write_bytes) && + for (i = 0; (i < dd->bytes_per_word) && dd->tx_bytes_remaining; i++) { dd->tx_bytes_remaining--; byte = *dd->write_buf++; word |= (byte << (BITS_PER_BYTE * i)); } } else - if (dd->tx_bytes_remaining > write_bytes) - dd->tx_bytes_remaining -= write_bytes; + if (dd->tx_bytes_remaining > dd->bytes_per_word) + dd->tx_bytes_remaining -= dd->bytes_per_word; else dd->tx_bytes_remaining = 0; dd->write_xfr_cnt++; @@ -1039,22 +1012,11 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd) { int count = 0; - if (dd->tx_mode == SPI_FIFO_MODE) { - while ((dd->tx_bytes_remaining > 0) && - (count < dd->input_fifo_size) && - !(readl_relaxed(dd->base + SPI_OPERATIONAL) - & SPI_OP_OUTPUT_FIFO_FULL)) { - msm_spi_write_word_to_fifo(dd); - count++; - } - } - - if (dd->tx_mode == SPI_BLOCK_MODE) { - while (dd->tx_bytes_remaining && - (count < dd->output_block_size)) { - msm_spi_write_word_to_fifo(dd); - count += SPI_MAX_BYTES_PER_WORD; - } + while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) && + !(readl_relaxed(dd->base + SPI_OPERATIONAL) & + SPI_OP_OUTPUT_FIFO_FULL)) { + msm_spi_write_word_to_fifo(dd); + count++; } } @@ -1064,11 +1026,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id) dd->stat_tx++; - if (dd->tx_mode == SPI_MODE_NONE) + if (dd->mode == SPI_MODE_NONE) return IRQ_HANDLED; /* Output FIFO is empty. Transmit any outstanding write data. */ - if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE)) + if (dd->mode == SPI_FIFO_MODE) msm_spi_write_rmn_to_fifo(dd); return IRQ_HANDLED; @@ -1144,7 +1106,7 @@ error: static int msm_spi_dma_map_buffers(struct msm_spi *dd) { int ret = 0; - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) ret = msm_spi_bam_map_buffers(dd); return ret; } @@ -1173,7 +1135,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd) static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd) { - if (dd->tx_mode == SPI_BAM_MODE) + if (dd->mode == SPI_BAM_MODE) msm_spi_bam_unmap_buffers(dd); } @@ -1235,11 +1197,9 @@ static void msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count) { if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) { - dd->tx_mode = SPI_BAM_MODE; - dd->rx_mode = SPI_BAM_MODE; + dd->mode = SPI_BAM_MODE; } else { - dd->rx_mode = SPI_FIFO_MODE; - dd->tx_mode = SPI_FIFO_MODE; + dd->mode = SPI_FIFO_MODE; dd->read_len = dd->cur_transfer->len; dd->write_len = dd->cur_transfer->len; } @@ -1255,19 +1215,14 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd) spi_iom = readl_relaxed(dd->base + SPI_IO_MODES); /* Set input and output transfer mode: FIFO, DMOV, or BAM */ spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE); - spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT)); - spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT)); - /* Always enable packing for all % 8 bits_per_word */ - if (dd->cur_transfer->bits_per_word && - ((dd->cur_transfer->bits_per_word == 8) || - (dd->cur_transfer->bits_per_word == 16) || - (dd->cur_transfer->bits_per_word == 32))) { + spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT)); + spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT)); + /* Turn on packing for data mover */ + if (dd->mode == SPI_BAM_MODE) spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN; - dd->pack_words = true; - } else { + else { spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN); spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN; - dd->pack_words = false; } /*if (dd->mode == SPI_BAM_MODE) { @@ -1325,7 +1280,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd) { /* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status * change in BAM mode */ - u32 mask = (dd->tx_mode == SPI_BAM_MODE) ? + u32 mask = (dd->mode == SPI_BAM_MODE) ? QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG : 0; writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK); @@ -1366,8 +1321,6 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->rx_bytes_remaining = dd->cur_msg_len; dd->read_buf = dd->cur_transfer->rx_buf; dd->write_buf = dd->cur_transfer->tx_buf; - dd->tx_done = false; - dd->rx_done = false; init_completion(&dd->tx_transfer_complete); init_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) @@ -1398,12 +1351,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_set_transfer_mode(dd, bpw, read_count); msm_spi_set_mx_counts(dd, read_count); - if (dd->tx_mode == SPI_BAM_MODE) { + if (dd->mode == SPI_BAM_MODE) { ret = msm_spi_dma_map_buffers(dd); if (ret < 0) { pr_err("Mapping DMA buffers\n"); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; return ret; } } @@ -1417,11 +1368,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) the first. Restricting this to one write avoids contention issues and race conditions between this thread and the int handler */ - if (dd->tx_mode != SPI_BAM_MODE) { + if (dd->mode == SPI_FIFO_MODE) { if (msm_spi_prepare_for_write(dd)) goto transfer_end; msm_spi_start_write(dd, read_count); - } else { + } else if (dd->mode == SPI_BAM_MODE) { if ((msm_spi_bam_begin_transfer(dd)) < 0) { dev_err(dd->dev, "%s: BAM transfer setup failed\n", __func__); @@ -1437,11 +1388,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd) * might fire before the first word is written resulting in a * possible race condition. */ - if (dd->tx_mode != SPI_BAM_MODE) + if (dd->mode != SPI_BAM_MODE) if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) { dev_warn(dd->dev, "%s: Failed to set QUP to run-state. Mode:%d", - __func__, dd->tx_mode); + __func__, dd->mode); goto transfer_end; } @@ -1471,11 +1422,10 @@ static int msm_spi_process_transfer(struct msm_spi *dd) msm_spi_udelay(dd->xfrs_delay_usec); transfer_end: - if ((dd->tx_mode == SPI_BAM_MODE) && status) + if ((dd->mode == SPI_BAM_MODE) && status) msm_spi_bam_flush(dd); msm_spi_dma_unmap_buffers(dd); - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; msm_spi_set_state(dd, SPI_OP_STATE_RESET); if (!dd->cur_transfer->cs_change) @@ -2403,8 +2353,7 @@ static int init_resources(struct platform_device *pdev) pclk_enabled = 0; dd->transfer_pending = 0; - dd->tx_mode = SPI_MODE_NONE; - dd->rx_mode = SPI_MODE_NONE; + dd->mode = SPI_MODE_NONE; rc = msm_spi_request_irq(dd, pdev, master); if (rc) diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h index e8e6cdce1a02..53ec1e600594 100644 --- a/drivers/spi/spi_qsd.h +++ b/drivers/spi/spi_qsd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 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 @@ -113,8 +113,6 @@ #define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12) /* SPI_OPERATIONAL fields */ -#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000 -#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000 #define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800 #define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400 #define SPI_OP_INPUT_SERVICE_FLAG 0x00000200 @@ -316,8 +314,7 @@ struct msm_spi { bool transfer_pending; wait_queue_head_t continue_suspend; /* DMA data */ - enum msm_spi_mode tx_mode; - enum msm_spi_mode rx_mode; + enum msm_spi_mode mode; bool use_dma; int tx_dma_chan; int tx_dma_crci; @@ -349,8 +346,7 @@ struct msm_spi { #endif struct msm_spi_platform_data *pdata; /* Platform data */ /* When set indicates multiple transfers in a single message */ - bool rx_done; - bool tx_done; + bool done; u32 cur_msg_len; /* Used in FIFO mode to keep track of the transfer being processed */ struct spi_transfer *cur_tx_transfer; @@ -368,7 +364,6 @@ struct msm_spi { struct pinctrl_state *pins_active; struct pinctrl_state *pins_sleep; bool is_init_complete; - bool pack_words; }; /* Forward declaration */ @@ -522,8 +517,7 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) static inline void msm_spi_complete(struct msm_spi *dd) { - dd->tx_done = true; - dd->rx_done = true; + dd->done = 1; } static inline void msm_spi_enable_error_flags(struct msm_spi *dd) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f3715d85aedc..7cafd0dd59f5 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -454,13 +454,23 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + return; + } + spin_lock(&common->lock); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; @@ -473,15 +483,24 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) struct fsg_common *common = ep->driver_data; struct fsg_buffhd *bh = req->context; - dump_msg(common, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + pr_debug("%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); + /* + * Disconnect and completion might race each other and driver data + * is set to NULL during ep disable. So, add a check if that is case. + */ + if (!common) { + bh->outreq_busy = 0; + return; + } + + dump_msg(common, "bulk-out", req->buf, req->actual); spin_lock(&common->lock); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c index 11c73f584594..061095b78c37 100644 --- a/drivers/usb/gadget/function/f_qc_rndis.c +++ b/drivers/usb/gadget/function/f_qc_rndis.c @@ -683,6 +683,7 @@ static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* we know alt == 0 */ + opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst); if (intf == rndis->ctrl_id) { if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c index 8ef223370827..013c54da0d0a 100644 --- a/drivers/usb/gadget/function/u_ctrl_qti.c +++ b/drivers/usb/gadget/function/u_ctrl_qti.c @@ -485,7 +485,7 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count, port->copied_from_modem++; spin_lock_irqsave(&port->lock, flags); - if (port && port->port_usb) { + if (port->port_usb) { if (port->port_type == QTI_PORT_RMNET) { g_rmnet = (struct grmnet *)port->port_usb; } else { diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index bf9e0fa9950b..6c18a04f6c1c 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -1107,18 +1107,18 @@ static void bam2bam_data_resume_work(struct work_struct *w) unsigned long flags; int ret; - if (!port->port_usb->cdev) { - pr_err("!port->port_usb->cdev is NULL"); + spin_lock_irqsave(&port->port_lock, flags); + if (!port->port_usb || !port->port_usb->cdev) { + pr_err("port->port_usb or cdev is NULL"); goto exit; } if (!port->port_usb->cdev->gadget) { - pr_err("!port->port_usb->cdev->gadget is NULL"); + pr_err("port->port_usb->cdev->gadget is NULL"); goto exit; } pr_debug("%s: resume started\n", __func__); - spin_lock_irqsave(&port->port_lock, flags); gadget = port->port_usb->cdev->gadget; if (!gadget) { spin_unlock_irqrestore(&port->port_lock, flags); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index f3e17b84efff..f1360f20ffe4 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2009-2011, 2017 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 |