diff options
| author | wzedlare <vedatak01@gmail.com> | 2017-06-18 16:38:26 +0000 |
|---|---|---|
| committer | wzedlare <vedatak01@gmail.com> | 2017-06-19 16:57:11 +0000 |
| commit | c7d4e3fd588e3ba3d3fa4d5cfa224aa54bc288bf (patch) | |
| tree | b8b64cb9deb6832c1e41f58f0f143514beafc709 /drivers/soc | |
| parent | 28c99c87b881bb664c44bb26e80a681f87d54e60 (diff) | |
Change-Id: Ia4c94f09e29843b1af34d466243378a357e97b70
Diffstat (limited to 'drivers/soc')
26 files changed, 1021 insertions, 186 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 1dbc2efa..ab5c7da2 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -707,14 +707,6 @@ config ICNSS control messages to FW over QMI channel. It is also responsible for handling WLAN PD restart notifications. -config MSM_CORE_CTL_HELPER - tristate "Core control helper functions for dynamically hotplug CPUs" - help - Provide helper functions for core control driver. Core control - driver dynamically hotplugs CPUs from kernel based on current - system load and state. It also supports limiting min and - max online CPUs from userspace. - config MSM_BAM_DMUX bool "BAM Data Mux Driver" depends on SPS @@ -782,7 +774,7 @@ config MSM_PACMAN peripheral (BLSP) ownership. config MSM_KERNEL_PROTECT - bool "Protect kernel text by removing write permissions in stage-2" + bool "Protect kernel text by removing write permissions" depends on !FUNCTION_TRACER help On hypervisor-enabled targets, this option will make a call into @@ -795,6 +787,18 @@ config MSM_KERNEL_PROTECT aarch64_insn_patch_text_nosync, etc. including the various CPU errata workarounds in arch/arm64/kernel/cpu_errata.c). + For MPU based protection-enabled targets please refer to + MSM_KERNEL_PROTECT_MPU + +config MSM_KERNEL_PROTECT_MPU + bool "Protect kernel text from other masters by MPU" + depends on MSM_KERNEL_PROTECT + help + On MPU based protection enabled targets, this option will make a call + into TrustZone to request that the kernel text be ptotected for any + write access from external bus masters. This protects against + malicious devices rewriting kernel code. + config MSM_KERNEL_PROTECT_TEST bool "Bootup test of kernel protection (INTENTIONAL CRASH)" depends on MSM_KERNEL_PROTECT @@ -812,6 +816,18 @@ config MSM_REMOTEQDSS enable/disable these events. Interface located in /sys/class/remoteqdss. +config MMI_UNIT_INFO + default n + bool "Motorola Mobility Unit Info" + help + Provide mechanism to expose unit information to other cpu via smem. + +config MMI_RAM_INFO + default n + bool "Motorola Mobility RAM Info" + help + Provide mechanism to access RAM size and MR registers values via sysfs. + config QCOM_SMCINVOKE bool "Secure QSEE Support" help @@ -819,5 +835,6 @@ config QCOM_SMCINVOKE communication between QSEE and HLOS. source "drivers/soc/qcom/memshare/Kconfig" +source "drivers/soc/qcom/unlock_bl/Kconfig" endif # ARCH_MSM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index a0f69ac8..d7c9b1a7 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -59,7 +59,11 @@ obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/ obj-$(CONFIG_CP_ACCESS64) += cpaccess64.o obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o rpm_rail_stats.o system_stats.o +ifdef CONFIG_ARCH_MSM8996 obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_kryo.o perf_event_l2.o +else +obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_l2.o +endif obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o obj-$(CONFIG_MSM_JTAG) += jtag-fuse.o jtag.o obj-$(CONFIG_MSM_JTAG_MM) += jtag-fuse.o jtag-mm.o @@ -71,7 +75,6 @@ obj-$(CONFIG_MSM_TZ_SMMU) += msm_tz_smmu.o obj-$(CONFIG_MSM_PIL) += peripheral-loader.o obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o -obj-$(CONFIG_MSM_CORE_CTL_HELPER) += core_ctl_helper.o obj-$(CONFIG_MSM_SCM_ERRATA) += scm-errata.o obj-$(CONFIG_MSM_PFE_WA) += pfe-wa.o obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o @@ -98,3 +101,6 @@ obj-$(CONFIG_MSM_KERNEL_PROTECT) += kernel_protect.o obj-$(CONFIG_MSM_RTB) += msm_rtb-hotplug.o obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o +obj-$(CONFIG_MMI_UNIT_INFO) += mmi-unit-info.o +obj-$(CONFIG_MMI_RAM_INFO) += mmi-ram-info.o +obj-$(CONFIG_LENOVO_UNLOCK_BL) += unlock_bl/ diff --git a/drivers/soc/qcom/core_ctl_helper.c b/drivers/soc/qcom/core_ctl_helper.c deleted file mode 100644 index c21ba2f7..00000000 --- a/drivers/soc/qcom/core_ctl_helper.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014-2016, 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/cpu.h> -#include <linux/cpufreq.h> -#include <linux/ktime.h> -#include <linux/hrtimer.h> -#include <linux/module.h> -#include <linux/init.h> -#include <soc/qcom/core_ctl.h> - -void core_ctl_block_hotplug(void) -{ - get_online_cpus(); -} -EXPORT_SYMBOL(core_ctl_block_hotplug); - -void core_ctl_unblock_hotplug(void) -{ - put_online_cpus(); -} -EXPORT_SYMBOL(core_ctl_unblock_hotplug); - -s64 core_ctl_get_time(void) -{ - return ktime_to_ms(ktime_get()); -} -EXPORT_SYMBOL(core_ctl_get_time); - -struct cpufreq_policy *core_ctl_get_policy(int cpu) -{ - return cpufreq_cpu_get(cpu); -} -EXPORT_SYMBOL(core_ctl_get_policy); - -void core_ctl_put_policy(struct cpufreq_policy *policy) -{ - cpufreq_cpu_put(policy); -} -EXPORT_SYMBOL(core_ctl_put_policy); - -struct device *core_ctl_find_cpu_device(unsigned cpu) -{ - return get_cpu_device(cpu); -} -EXPORT_SYMBOL(core_ctl_find_cpu_device); - -int __ref core_ctl_online_core(unsigned int cpu) -{ - int ret; - struct device *dev; - - lock_device_hotplug(); - dev = get_cpu_device(cpu); - if (!dev) { - pr_err("%s: failed to get cpu%d device\n", __func__, cpu); - ret = -ENODEV; - } else { - ret = device_online(dev); - } - unlock_device_hotplug(); - return ret; -} -EXPORT_SYMBOL(core_ctl_online_core); - -int __ref core_ctl_offline_core(unsigned int cpu) -{ - int ret; - struct device *dev; - - lock_device_hotplug(); - dev = get_cpu_device(cpu); - if (!dev) { - pr_err("%s: failed to get cpu%d device\n", __func__, cpu); - ret = -ENODEV; - } else { - ret = device_offline(dev); - } - unlock_device_hotplug(); - return ret; -} -EXPORT_SYMBOL(core_ctl_offline_core); diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index 277ab978..f41dca07 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -1146,6 +1146,7 @@ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, { struct glink_core_rx_intent *intent; struct glink_core_rx_intent *intent_tmp; + struct glink_core_rx_intent *best_intent = NULL; unsigned long flags; if (GLINK_MAX_PKT_SIZE < size) { @@ -1168,20 +1169,28 @@ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, list_for_each_entry_safe(intent, intent_tmp, &ctx->rmt_rx_intent_list, list) { if (intent->intent_size >= size) { - list_del(&intent->list); - GLINK_DBG_CH(ctx, - "%s: R[%u]:%zu Removed remote intent\n", - __func__, - intent->id, - intent->intent_size); - *riid_ptr = intent->id; - *intent_size = intent->intent_size; - kfree(intent); - spin_unlock_irqrestore( - &ctx->rmt_rx_intent_lst_lock_lhc2, flags); - return 0; + if (!best_intent) + best_intent = intent; + else if (best_intent->intent_size > intent->intent_size) + best_intent = intent; + if (best_intent->intent_size == size) + break; } } + if (best_intent) { + list_del(&best_intent->list); + GLINK_DBG_CH(ctx, + "%s: R[%u]:%zu Removed remote intent\n", + __func__, + best_intent->id, + best_intent->intent_size); + *riid_ptr = best_intent->id; + *intent_size = best_intent->intent_size; + kfree(best_intent); + spin_unlock_irqrestore( + &ctx->rmt_rx_intent_lst_lock_lhc2, flags); + return 0; + } spin_unlock_irqrestore(&ctx->rmt_rx_intent_lst_lock_lhc2, flags); return -EAGAIN; } @@ -2663,7 +2672,7 @@ int glink_close(void *handle) { struct glink_core_xprt_ctx *xprt_ctx = NULL; struct channel_ctx *ctx = (struct channel_ctx *)handle; - int ret; + int ret = 0; unsigned long flags; bool is_empty = false; @@ -2824,7 +2833,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, tracer_pkt_log_event(data, GLINK_CORE_TX); } - /* find matching rx intent (first-fit algorithm for now) */ + /* find matching rx intent (best-fit algorithm for now) */ if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size)) { if (!(tx_flags & GLINK_TX_REQ_INTENT)) { /* no rx intent available */ @@ -5228,7 +5237,7 @@ static int glink_scheduler_tx(struct channel_ctx *ctx, size_t txd_len = 0; size_t tx_len = 0; uint32_t num_pkts = 0; - int ret; + int ret = 0; spin_lock_irqsave(&ctx->tx_lists_lock_lhc3, flags); while (txd_len < xprt_ctx->mtu && diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c index 4952e12f..a14d912b 100644 --- a/drivers/soc/qcom/glink_ssr.c +++ b/drivers/soc/qcom/glink_ssr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -769,7 +769,7 @@ static int glink_ssr_probe(struct platform_device *pdev) struct device_node *phandle_node; struct restart_notifier_block *nb; struct subsys_info *ss_info; - struct subsys_info_leaf *ss_info_leaf; + struct subsys_info_leaf *ss_info_leaf = NULL; struct glink_link_info *link_info; char *key; const char *edge; diff --git a/drivers/soc/qcom/jtag-fuse.c b/drivers/soc/qcom/jtag-fuse.c index 46de4e5f..d7389f39 100644 --- a/drivers/soc/qcom/jtag-fuse.c +++ b/drivers/soc/qcom/jtag-fuse.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 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 @@ -152,8 +152,6 @@ static int jtag_fuse_probe(struct platform_device *pdev) drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; - /* Store the driver data pointer for use in exported functions */ - fusedrvdata = drvdata; drvdata->dev = &pdev->dev; platform_set_drvdata(pdev, drvdata); @@ -174,6 +172,8 @@ static int jtag_fuse_probe(struct platform_device *pdev) if (!drvdata->base) return -ENOMEM; + /* Store the driver data pointer for use in exported functions */ + fusedrvdata = drvdata; dev_info(dev, "JTag Fuse initialized\n"); return 0; } diff --git a/drivers/soc/qcom/kernel_protect.c b/drivers/soc/qcom/kernel_protect.c index 73192971..b48cd0bf 100644 --- a/drivers/soc/qcom/kernel_protect.c +++ b/drivers/soc/qcom/kernel_protect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015,2016 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 @@ -14,10 +14,12 @@ #include <linux/printk.h> #include <linux/init.h> #include <linux/gfp.h> +#include <soc/qcom/scm.h> #include <soc/qcom/secure_buffer.h> #include <asm/sections.h> #include <asm/cacheflush.h> +#define KERNEL_PROTECT_MPU 0x24 #ifdef CONFIG_MSM_KERNEL_PROTECT_TEST @@ -38,6 +40,10 @@ static void msm_protect_kernel_test(void) */ char *addr = (char *)__alloc_pages_nodemask; + if (IS_ENABLED(CONFIG_MSM_KERNEL_PROTECT_MPU)) { + pr_err("MPU protected kernel code is HLOS writable\n"); + return; + } pr_err("Checking whether the kernel text is writable...\n"); pr_err("A BUG means it is writable (this is bad)\n"); pr_err("A stage-2 fault means it's not writable (this is good, but we'll still crash)\n"); @@ -84,9 +90,33 @@ static int __init msm_protect_kernel(void) pr_debug("assigning from phys: %pa to %pa\n", &kernel_x_start_rounded, &kernel_x_end); pr_debug("virtual: %p to %p\n", virt_start, virt_end); - ret = hyp_assign_phys(kernel_x_start_rounded, - kernel_x_end - kernel_x_start_rounded, - &vmid_hlos, 1, &vmid_hlos, &dest_perms, 1); + + if (IS_ENABLED(CONFIG_MSM_KERNEL_PROTECT_MPU)) { + struct scm_desc desc = {0}; + + if (!scm_is_call_available(SCM_SVC_MP, KERNEL_PROTECT_MPU)) + return 0; + + desc.args[0] = kernel_x_start_rounded; + desc.args[1] = kernel_x_end - kernel_x_start_rounded; + desc.arginfo = SCM_ARGS(2); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + KERNEL_PROTECT_MPU), &desc); + if (ret) { + /* + * must not proceed if failed to MPU protect kernel + * text region + */ + panic("Failed to protect kernel region %pa -- %pa\n", + &kernel_x_start_rounded, + &kernel_x_end); + } + } else { + ret = hyp_assign_phys(kernel_x_start_rounded, + kernel_x_end - kernel_x_start_rounded, + &vmid_hlos, 1, &vmid_hlos, &dest_perms, 1); + } if (ret) /* * We want to fail relatively silently since not all diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index e1e91f56..6f1f3755 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -26,6 +26,7 @@ #include "heap_mem_ext_v01.h" #include <soc/qcom/secure_buffer.h> +#include <soc/qcom/ramdump.h> /* Macros */ #define MEMSHARE_DEV_NAME "memshare" @@ -37,6 +38,7 @@ static void mem_share_svc_recv_msg(struct work_struct *work); static DECLARE_DELAYED_WORK(work_recv_msg, mem_share_svc_recv_msg); static struct workqueue_struct *mem_share_svc_workqueue; static uint64_t bootup_request; +static void *memshare_ramdump_dev[MAX_CLIENTS]; /* Memshare Driver Structure */ struct memshare_driver { @@ -114,9 +116,37 @@ static struct msg_desc mem_share_svc_size_query_resp_desc = { .ei_array = mem_query_size_resp_msg_data_v01_ei, }; +/* + * This API creates ramdump dev handlers + * for each of the memshare clients. + * These dev handlers will be used for + * extracting the ramdump for loaned memory + * segments. + */ + +static int mem_share_configure_ramdump(void) +{ + char client_name[18] = "memshare_"; + char *clnt; + + clnt = ((!num_clients) ? "GPS" : ((num_clients == 1) ? "FTM" : "DIAG")); + snprintf(client_name, 18, "memshare_%s", clnt); + + memshare_ramdump_dev[num_clients] = create_ramdump_device(client_name, + NULL); + if (IS_ERR_OR_NULL(memshare_ramdump_dev[num_clients])) { + pr_err("memshare: %s: Unable to create memshare ramdump device.\n", + __func__); + memshare_ramdump_dev[num_clients] = NULL; + return -ENOMEM; + } + + return 0; +} + static int check_client(int client_id, int proc, int request) { - int i = 0; + int i = 0, rc; int found = DHMS_MEM_CLIENT_INVALID; for (i = 0; i < MAX_CLIENTS; i++) { @@ -127,7 +157,7 @@ static int check_client(int client_id, int proc, int request) } } if ((found == DHMS_MEM_CLIENT_INVALID) && !request) { - pr_debug("No registered client, adding a new client\n"); + pr_debug("memshare: No registered client, adding a new client\n"); /* Add a new client */ for (i = 0; i < MAX_CLIENTS; i++) { if (memblock[i].client_id == DHMS_MEM_CLIENT_INVALID) { @@ -136,6 +166,16 @@ static int check_client(int client_id, int proc, int request) memblock[i].guarantee = 0; memblock[i].peripheral = proc; found = i; + + if (!memblock[i].file_created) { + rc = mem_share_configure_ramdump(); + if (rc) + pr_err("In %s, Cannot create ramdump for client: %d\n", + __func__, client_id); + else + memblock[i].file_created = 1; + } + break; } } @@ -190,10 +230,63 @@ void initialize_client(void) memblock[i].memory_type = MEMORY_CMA; memblock[i].free_memory = 0; memblock[i].hyp_mapping = 0; + memblock[i].file_created = 0; } dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); } +/* + * This API initializes the ramdump segments + * with the physical address and size of + * the memshared clients. Extraction of ramdump + * is skipped if memshare client is not alloted + * This calls the ramdump api in extracting the + * ramdump in elf format. + */ + +static int mem_share_do_ramdump(void) +{ + int i = 0, ret; + char *client_name; + + for (i = 0; i < num_clients; i++) { + + struct ramdump_segment *ramdump_segments_tmp = NULL; + + client_name = (i == 0) ? "GPS" : + ((i == 1) ? "FTM" : ((i == 2) ? "DIAG" : "NULL")); + + if (!memblock[i].alloted) { + pr_err("memshare:%s memblock is not alloted\n", + client_name); + continue; + } + + ramdump_segments_tmp = kcalloc(1, + sizeof(struct ramdump_segment), + GFP_KERNEL); + if (!ramdump_segments_tmp) + return -ENOMEM; + + ramdump_segments_tmp[0].size = memblock[i].size; + ramdump_segments_tmp[0].address = memblock[i].phy_addr; + + pr_debug("memshare: %s:%s client:phy_address = %llx, size = %d\n", + __func__, client_name, + (unsigned long long) memblock[i].phy_addr, memblock[i].size); + + ret = do_elf_ramdump(memshare_ramdump_dev[i], + ramdump_segments_tmp, 1); + if (ret < 0) { + pr_err("memshare: Unable to dump: %d\n", ret); + kfree(ramdump_segments_tmp); + return ret; + } + kfree(ramdump_segments_tmp); + } + return 0; +} + static int modem_notifier_cb(struct notifier_block *this, unsigned long code, void *_cmd) { @@ -202,8 +295,10 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA}; int dest_vmids[1] = {VMID_HLOS}; int dest_perms[1] = {PERM_READ|PERM_WRITE}; + struct notif_data *notifdata = NULL; mutex_lock(&memsh_drv->mem_share); + switch (code) { case SUBSYS_BEFORE_SHUTDOWN: @@ -260,6 +355,23 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code, bootup_request++; break; + case SUBSYS_RAMDUMP_NOTIFICATION: + + if (_cmd) + notifdata = (struct notif_data *) _cmd; + else + break; + + if (!(notifdata->enable_ramdump)) { + pr_err("In %s, Ramdump collection is disabled\n", + __func__); + } else { + ret = mem_share_do_ramdump(); + if (ret) + pr_err("Ramdump collection failed\n"); + } + break; + default: pr_debug("Memshare: code: %lu\n", code); break; @@ -800,6 +912,9 @@ static int memshare_child_probe(struct platform_device *pdev) memblock[num_clients].size = size; memblock[num_clients].client_id = client_id; + /* + * Memshare allocation for guaranteed clients + */ if (memblock[num_clients].guarantee) { rc = memshare_alloc(memsh_child->dev, memblock[num_clients].size, @@ -812,6 +927,21 @@ static int memshare_child_probe(struct platform_device *pdev) memblock[num_clients].alloted = 1; } + /* + * call for creating ramdump dev handlers for + * memshare clients + */ + + if (!memblock[num_clients].file_created) { + rc = mem_share_configure_ramdump(); + if (rc) + pr_err("In %s, cannot collect dumps for client id: %d\n", + __func__, + memblock[num_clients].client_id); + else + memblock[num_clients].file_created = 1; + } + num_clients++; return 0; diff --git a/drivers/soc/qcom/memshare/msm_memshare.h b/drivers/soc/qcom/memshare/msm_memshare.h index 68a14390..39890753 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.h +++ b/drivers/soc/qcom/memshare/msm_memshare.h @@ -51,6 +51,9 @@ struct mem_blocks { uint8_t free_memory; /* Need Hypervisor mapping*/ uint8_t hyp_mapping; + /* Status flag which checks if ramdump file is created*/ + int file_created; + }; int memshare_alloc(struct device *dev, diff --git a/drivers/soc/qcom/mmi-ram-info.c b/drivers/soc/qcom/mmi-ram-info.c new file mode 100644 index 00000000..cc62a1a3 --- /dev/null +++ b/drivers/soc/qcom/mmi-ram-info.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/module.h> +#include <soc/qcom/smsm.h> +//#include <linux/pstore.h> + +static struct { + unsigned mr5; + unsigned mr6; + unsigned mr7; + unsigned mr8; + unsigned ramsize; +} *smem_ddr_info; + +static char sysfsram_type_name[20] = "unknown"; +static char sysfsram_vendor_name[20] = "unknown"; +static uint32_t sysfsram_ramsize; + +static ssize_t sysfsram_mr_register_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + uint32_t val = 0; + const char *name = attr->attr.name; + + if (smem_ddr_info != NULL && + strnlen(name, 4) == 3 && name[0] == 'm' && name[1] == 'r') + { + switch (name[2]) { + case '5': val = smem_ddr_info->mr5; break; + case '6': val = smem_ddr_info->mr6; break; + case '7': val = smem_ddr_info->mr7; break; + case '8': val = smem_ddr_info->mr8; break; + } + } + + return snprintf(buf, 6, "0x%02x\n", val); +} + +static ssize_t sysfsram_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, 12, "%u\n", sysfsram_ramsize); +} + +static ssize_t sysfsram_info_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, 60, "%s:%s:%uMB\n", + sysfsram_vendor_name, + sysfsram_type_name, + sysfsram_ramsize); +} + +static ssize_t sysfsram_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%s\n", sysfsram_type_name); +} + +static struct kobj_attribute ddr_mr5_register_attr = + __ATTR(mr5, 0444, sysfsram_mr_register_show, NULL); + +static struct kobj_attribute ddr_mr6_register_attr = + __ATTR(mr6, 0444, sysfsram_mr_register_show, NULL); + +static struct kobj_attribute ddr_mr7_register_attr = + __ATTR(mr7, 0444, sysfsram_mr_register_show, NULL); + +static struct kobj_attribute ddr_mr8_register_attr = + __ATTR(mr8, 0444, sysfsram_mr_register_show, NULL); + +static struct kobj_attribute ddr_size_attr = + __ATTR(size, 0444, sysfsram_size_show, NULL); + +static struct kobj_attribute ddr_type_attr = + __ATTR(type, 0444, sysfsram_type_show, NULL); + +static struct kobj_attribute ddr_info_attr = + __ATTR(info, 0444, sysfsram_info_show, NULL); + +static struct attribute *ram_info_properties_attrs[] = { + &ddr_mr5_register_attr.attr, + &ddr_mr6_register_attr.attr, + &ddr_mr7_register_attr.attr, + &ddr_mr8_register_attr.attr, + &ddr_size_attr.attr, + &ddr_type_attr.attr, + &ddr_info_attr.attr, + NULL +}; + +static struct attribute_group ram_info_properties_attr_group = { + .attrs = ram_info_properties_attrs, +}; + +static int __init init_mmi_ram_info(void) +{ + int status = 0; + static struct kobject *ram_info_properties_kobj; + uint32_t vid, tid; + const char *tname = "unknown"; + const char *vname = "unknown"; + static const char *vendors[] = { + "unknown", + "Samsung", + "Qimonda", + "Elpida", + "Etron", + "Nanya", + "Hynix", + "Mosel", + "Winbond", + "ESMT", + "unknown", + "Spansion", + "SST", + "ZMOS", + "Intel" + }; + static const char *types[] = { + "S4 SDRAM", + "S2 SDRAM", + "N NVM", + "Reserved" + }; + + smem_ddr_info = smem_alloc(SMEM_SDRAM_INFO, sizeof(*smem_ddr_info), 0, + SMEM_ANY_HOST_FLAG); + + if (smem_ddr_info != NULL) { + char apanic_annotation[128]; + + /* identify vendor */ + vid = smem_ddr_info->mr5 & 0xFF; + if (vid < (sizeof(vendors)/sizeof(vendors[0]))) + vname = vendors[vid]; + else if (vid == 0xFE) + vname = "Numonyx"; + else if (vid == 0xFF) + vname = "Micron"; + + snprintf(sysfsram_vendor_name, sizeof(sysfsram_vendor_name), + "%s", vname); + + /* identify type */ + tid = smem_ddr_info->mr8 & 0x03; + if (tid < (sizeof(types)/sizeof(types[0]))) + tname = types[tid]; + + snprintf(sysfsram_type_name, sizeof(sysfsram_type_name), + "%s", tname); + + /* extract size */ + sysfsram_ramsize = smem_ddr_info->ramsize; + + snprintf(apanic_annotation, sizeof(apanic_annotation), + "RAM: %s, %s, %u MB, MR5:0x%02X, MR6:0x%02X, " + "MR7:0x%02X, MR8:0x%02X\n", + vname, tname, smem_ddr_info->ramsize, + smem_ddr_info->mr5, smem_ddr_info->mr6, + smem_ddr_info->mr7, smem_ddr_info->mr8); + //pstore_annotate(apanic_annotation); + } + else { + /* complain, but do not fail if SMEM was not allocated */ + /* defaults will be reported */ + pr_err("%s: failed to access RAM info in SMEM\n", __func__); + } + + /* create sysfs object */ + ram_info_properties_kobj = kobject_create_and_add("ram", NULL); + + if (ram_info_properties_kobj) + status = sysfs_create_group(ram_info_properties_kobj, + &ram_info_properties_attr_group); + + if (!ram_info_properties_kobj || status) { + pr_err("%s: failed to create /sys/ram\n", __func__); + return 1; + } + else + return 0; +} + +module_init(init_mmi_ram_info); +MODULE_DESCRIPTION("Motorola Mobility Inc. RAM Info"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/mmi-unit-info.c b/drivers/soc/qcom/mmi-unit-info.c new file mode 100644 index 00000000..6cb9d1fb --- /dev/null +++ b/drivers/soc/qcom/mmi-unit-info.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2013 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/module.h> +#include <linux/seq_file.h> +#include <asm/setup.h> +#include <soc/qcom/bootinfo.h> + +#include <soc/qcom/smem.h> +#include "mmi-unit-info.h" + +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/slab.h> + +#ifndef CONFIG_ARM64 +#include <asm/mach/arch.h> +#endif +/* these are defined in kernel/setup.c for "arm" targets + but not used, so set 0 +*/ +unsigned int system_rev_local = 0; +unsigned int system_serial_low_local = 0; +unsigned int system_serial_high_local = 0; +static u32 prod_id; + +#define SERIALNO_MAX_LEN 64 +static char serialno[SERIALNO_MAX_LEN]; +int __init board_serialno_init(char *s) +{ + strlcpy(serialno, s, SERIALNO_MAX_LEN); + return 1; +} +__setup("androidboot.serialno=", board_serialno_init); + +static char carrier[CARRIER_MAX_LEN]; +int __init board_carrier_init(char *s) +{ + strlcpy(carrier, s, SERIALNO_MAX_LEN); + return 1; +} +__setup("androidboot.carrier=", board_carrier_init); + +static char baseband[BASEBAND_MAX_LEN]; +int __init board_baseband_init(char *s) +{ + strlcpy(baseband, s, SERIALNO_MAX_LEN); + return 1; +} +__setup("androidboot.baseband=", board_baseband_init); + +#define ANDROIDBOOT_DEVICE_MAX_LEN 32 +static char androidboot_device[ANDROIDBOOT_DEVICE_MAX_LEN]; +int __init setup_androidboot_device_init(char *s) +{ + strlcpy(androidboot_device, s, ANDROIDBOOT_DEVICE_MAX_LEN); + return 1; +} +__setup("androidboot.device=", setup_androidboot_device_init); + +static unsigned int androidboot_radio; +static char androidboot_radio_str[RADIO_MAX_LEN]; +int __init setup_androidboot_radio_init(char *s) +{ + int retval = kstrtouint(s, 16, &androidboot_radio); + + if (retval < 0) { + androidboot_radio = 0; + } + + strlcpy(androidboot_radio_str, s, RADIO_MAX_LEN); + + return 1; +} +__setup("androidboot.radio=", setup_androidboot_radio_init); + +static struct mmi_unit_info *mui; +void mmi_set_pureason(uint32_t val) +{ + if (mui) { + mui->powerup_reason = val; + pr_debug("%s: Set modem PU reason value in SMEM to %d\n", + __func__, mui->powerup_reason); + } +} + +static char msm_hw[MSMHW_MAX_LEN+1]; + +void mach_cpuinfo_show(struct seq_file *m, void *v) +{ + seq_printf(m, "Device\t\t: %s\n", androidboot_device); + /* Zero is not a valid "Radio" value. */ + /* Lack of "Radio" entry in cpuinfo means: */ + /* look for radio in "Revision" */ + if (strnlen(androidboot_radio_str, RADIO_MAX_LEN)) + seq_printf(m, "Radio\t\t: %s\n", androidboot_radio_str); + + seq_printf(m, "MSM Hardware\t: %s\n", msm_hw); +} + +static char extended_baseband[BASEBAND_MAX_LEN+1] = "\0"; + +struct mmi_of_lookup { + const char *compatible; + unsigned int *data; +}; + +static struct mmi_of_lookup mmi_of_setup[] __initdata = { + { .compatible = "linux,seriallow", .data = &system_serial_low_local }, + { .compatible = "linux,serialhigh", .data = &system_serial_high_local }, + { .compatible = "linux,hwrev", .data = &system_rev_local }, + { .compatible = "mmi,prod_id", .data = &prod_id }, + { } +}; + +static void __init mmi_of_populate_setup(void) +{ + struct device_node *n = of_find_node_by_path("/chosen"); + struct mmi_of_lookup *tbl = mmi_of_setup; + const char *baseband; + const char *temp; + + while (tbl->data) { + of_property_read_u32(n, tbl->compatible, tbl->data); + tbl++; + } + + if (0 == of_property_read_string(n, "mmi,baseband", &baseband)) + strlcpy(extended_baseband, baseband, sizeof(extended_baseband)); + + if (0 == of_property_read_string(n, "mmi,msm_hw", &temp)) + strlcpy(msm_hw, temp, sizeof(msm_hw)); + + of_node_put(n); +} + +static int __init mmi_unit_info_init(void) +{ + int ret = 0; + struct mmi_unit_info *mui_copy; + + mmi_of_populate_setup(); + + #define SMEM_KERNEL_RESERVE_SIZE 1024 + mui_copy = kzalloc(SMEM_KERNEL_RESERVE_SIZE, GFP_KERNEL); + if (!mui_copy) { + pr_err("%s: failed to allocate space for mmi_unit_info\n", + __func__); + ret = 1; + goto err; + } + + mui_copy->version = MMI_UNIT_INFO_VER; + mui_copy->system_rev = system_rev_local; + mui_copy->system_serial_low = system_serial_low_local; + mui_copy->system_serial_high = system_serial_high_local; +#ifndef CONFIG_ARM64 + strlcpy(mui_copy->machine, machine_desc->name, MACHINE_MAX_LEN); +#else + strlcpy(mui_copy->machine, "", MACHINE_MAX_LEN); +#endif + strlcpy(mui_copy->barcode, serialno, BARCODE_MAX_LEN); + strlcpy(mui_copy->baseband, extended_baseband, BASEBAND_MAX_LEN); + strlcpy(mui_copy->carrier, carrier, CARRIER_MAX_LEN); + strlcpy(mui_copy->device, androidboot_device, DEVICE_MAX_LEN); + mui_copy->radio = androidboot_radio; + strlcpy(mui_copy->radio_str, androidboot_radio_str, RADIO_MAX_LEN); + mui_copy->powerup_reason = bi_powerup_reason(); + + pr_info("mmi_unit_info (SMEM) for modem: version = 0x%02x," + " device = '%s', radio = 0x%x, radio_str = '%s'," + " system_rev = 0x%04x, system_serial = 0x%08x%08x," + " machine = '%s', barcode = '%s', baseband = '%s'," + " carrier = '%s', pu_reason = 0x%08x\n", + mui_copy->version, + mui_copy->device, + mui_copy->radio, + mui_copy->radio_str, + mui_copy->system_rev, + mui_copy->system_serial_high, mui_copy->system_serial_low, + mui_copy->machine, mui_copy->barcode, + mui_copy->baseband, mui_copy->carrier, + mui_copy->powerup_reason); + + mui = (struct mmi_unit_info *) smem_alloc(SMEM_KERNEL_RESERVE, + SMEM_KERNEL_RESERVE_SIZE, 0, SMEM_ANY_HOST_FLAG); + + if (!mui) { + pr_err("%s: failed to allocate mmi_unit_info in SMEM\n", + __func__); + ret = 1; + goto err_free; + } else if (PTR_ERR(mui_copy) == -EPROBE_DEFER) { + pr_err("%s: SMEM not yet initialized\n", __func__); + ret = 1; + goto err_free; + } + + memcpy(mui, mui_copy, SMEM_KERNEL_RESERVE_SIZE); + +err_free: + kfree(mui_copy); +err: + return ret; +} + +module_init(mmi_unit_info_init); +MODULE_DESCRIPTION("Motorola Mobility LLC. Unit Info"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/mmi-unit-info.h b/drivers/soc/qcom/mmi-unit-info.h new file mode 100644 index 00000000..d41b8ec1 --- /dev/null +++ b/drivers/soc/qcom/mmi-unit-info.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +#ifndef __ARCH_ARM_MACH_MSM_MMI_UNIT_INFO_H +#define __ARCH_ARM_MACH_MSM_MMI_UNIT_INFO_H + +/* set of data provided to the modem over SMEM */ +#define MMI_UNIT_INFO_VER 3 +#define BARCODE_MAX_LEN 65 +#define MACHINE_MAX_LEN 33 +#define CARRIER_MAX_LEN 65 +#define BASEBAND_MAX_LEN 97 +#define MSMHW_MAX_LEN 32 +#define DEVICE_MAX_LEN 33 +#define RADIO_MAX_LEN 33 +struct mmi_unit_info { + uint32_t version; + uint32_t system_rev; + uint32_t system_serial_low; + uint32_t system_serial_high; + char machine[MACHINE_MAX_LEN]; + char barcode[BARCODE_MAX_LEN]; + char carrier[CARRIER_MAX_LEN]; + char baseband[BASEBAND_MAX_LEN]; + char device[DEVICE_MAX_LEN]; + uint32_t radio; + uint32_t powerup_reason; + char radio_str[RADIO_MAX_LEN]; +}; + +/* Function that sets the modem reset value in the SMEM location + * where mmi_unit_info is stored. + */ +void mmi_set_pureason(uint32_t val); + +#endif diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 67c58d1e..50dd9256 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -223,8 +223,8 @@ static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request, } else if (!strcmp(apr_request->svc_name, VOICE_SVC_MVM_STR)) { apr_handle = prtd->apr_q6_mvm; } else { - pr_err("%s: Invalid service %s\n", __func__, - apr_request->svc_name); + pr_err("%s: Invalid service %.*s\n", __func__, + MAX_APR_SERVICE_NAME_LEN, apr_request->svc_name); ret = -EINVAL; goto done; @@ -338,8 +338,8 @@ static int process_reg_cmd(struct voice_svc_register *apr_reg_svc, svc = VOICE_SVC_CVS_STR; handle = &prtd->apr_q6_cvs; } else { - pr_err("%s: Invalid Service: %s\n", __func__, - apr_reg_svc->svc_name); + pr_err("%s: Invalid Service: %.*s\n", __func__, + MAX_APR_SERVICE_NAME_LEN, apr_reg_svc->svc_name); ret = -EINVAL; goto done; } @@ -365,7 +365,17 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, pr_debug("%s\n", __func__); - data = kmalloc(count, GFP_KERNEL); + /* + * Check if enough memory is allocated to parse the message type. + * Will check there is enough to hold the payload later. + */ + if (count >= sizeof(struct voice_svc_write_msg)) { + data = kmalloc(count, GFP_KERNEL); + } else { + pr_debug("%s: invalid data size\n", __func__); + ret = -EINVAL; + goto done; + } if (data == NULL) { pr_err("%s: data kmalloc failed.\n", __func__); @@ -383,7 +393,7 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, } cmd = data->msg_type; - prtd = (struct voice_svc_prvt *)file->private_data; + prtd = (struct voice_svc_prvt *) file->private_data; if (prtd == NULL) { pr_err("%s: prtd is NULL\n", __func__); @@ -393,9 +403,13 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, switch (cmd) { case MSG_REGISTER: - if (count >= - (sizeof(struct voice_svc_register) + - sizeof(*data))) { + /* + * Check that count reflects the expected size to ensure + * sufficient memory was allocated. Since voice_svc_register + * has a static size, this should be exact. + */ + if (count == (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_register))) { ret = process_reg_cmd( (struct voice_svc_register *)data->payload, prtd); if (!ret) @@ -407,8 +421,13 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, } break; case MSG_REQUEST: - if (count >= (sizeof(struct voice_svc_cmd_request) + - sizeof(*data))) { + /* + * Check that count reflects the expected size to ensure + * sufficient memory was allocated. Since voice_svc_cmd_request + * has a variable size, check the minimum value count must be. + */ + if (count >= (sizeof(struct voice_svc_write_msg) + + sizeof(struct voice_svc_cmd_request))) { ret = voice_svc_send_req( (struct voice_svc_cmd_request *)data->payload, prtd); if (!ret) diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 209e5c64..bb0be81d 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -523,7 +523,6 @@ static int msm_rpm_read_sleep_ack(void) { int ret; char buf[MAX_ERR_BUFFER_SIZE] = {0}; - uint32_t msg_id; if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); @@ -554,38 +553,18 @@ static int msm_rpm_read_sleep_ack(void) return -EAGAIN; ret = msm_rpm_read_smd_data(buf); - if (!ret) { - /* Mimic Glink behavior to ensure that the - * data is read and the msg is removed from - * the wait list. We should have gotten here - * only when there are no drivers waiting on - * ACKs. msm_rpm_get_entry_from_msg_id() - * return non-NULL only then. - */ - msg_id = msm_rpm_get_msg_id_from_ack(buf); - msm_rpm_process_ack(msg_id, 0); + if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); - } } return ret; } -static void msm_rpm_flush_noack_messages(void) -{ - while (!list_empty(&msm_rpm_wait_list)) { - if (!msm_rpm_read_sleep_ack()) - break; - } -} - static int msm_rpm_flush_requests(bool print) { struct rb_node *t; int ret; int count = 0; - msm_rpm_flush_noack_messages(); - for (t = rb_first(&tr_root); t; t = rb_next(t)) { struct slp_buf *s = rb_entry(t, struct slp_buf, node); @@ -844,18 +823,14 @@ static void msm_rpm_notify(void *data, unsigned event) bool msm_rpm_waiting_for_ack(void) { - bool ret = false; + bool ret; unsigned long flags; - struct msm_rpm_wait_data *elem = NULL; spin_lock_irqsave(&msm_rpm_list_lock, flags); - elem = list_first_entry_or_null(&msm_rpm_wait_list, - struct msm_rpm_wait_data, list); - if (elem) - ret = !elem->delete_on_ack; + ret = list_empty(&msm_rpm_wait_list); spin_unlock_irqrestore(&msm_rpm_list_lock, flags); - return ret; + return !ret; } static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id) diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c index ec5f2303..10a1d5b6 100644 --- a/drivers/soc/qcom/rpm_stats.c +++ b/drivers/soc/qcom/rpm_stats.c @@ -56,7 +56,13 @@ struct msm_rpmstats_private_data { u32 num_records; u32 read_idx; u32 len; +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG + char buf[480]; +#else char buf[320]; +#endif +/* lenovo.sw end chenyb1 add for adding master vote info in rpm_state */ struct msm_rpmstats_platform_data *platform_data; }; @@ -107,6 +113,20 @@ static inline int msm_rpmstats_append_data_to_buf(char *buf, time_since_last_mode = get_time_in_sec(time_since_last_mode); actual_last_sleep = get_time_in_msec(data->accumulated); +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG + return snprintf(buf , buflength, + "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n" + "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n" + "client votes: %#010x\n" + "master[0,1]: 0x%08x\n" + "master[2,3]: 0x%08x\n" + "master[4,5]: 0x%08x\n\n", + stat_type, data->count, time_in_last_mode, + time_since_last_mode, actual_last_sleep, + data->client_votes, + data->reserved[0], data->reserved[1], data->reserved[2]); +#else return snprintf(buf , buflength, "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n" "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n" @@ -114,6 +134,8 @@ static inline int msm_rpmstats_append_data_to_buf(char *buf, stat_type, data->count, time_in_last_mode, time_since_last_mode, actual_last_sleep, data->client_votes); +#endif +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ } static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase, @@ -162,6 +184,19 @@ static inline int msm_rpmstats_copy_stats_v2( data.client_votes = msm_rpmstats_read_long_register_v2(reg, i, offsetof(struct msm_rpm_stats_data_v2, client_votes)); +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG + data.reserved[0] = msm_rpmstats_read_long_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved)); + data.reserved[1] = msm_rpmstats_read_long_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved) + 4); + data.reserved[2] = msm_rpmstats_read_long_register_v2(reg, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved) + 8); +#endif +/* lenovo.sw end chenyb1 add for adding master vote info in rpm_state */ length += msm_rpmstats_append_data_to_buf(prvdata->buf + length, &data, sizeof(prvdata->buf) - length); prvdata->read_idx++; @@ -311,6 +346,46 @@ static int msm_rpmstats_file_close(struct inode *inode, struct file *file) return 0; } +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG +struct msm_rpmstats_platform_data *rpmstats = NULL; + +void msm_rpmstats_get_reverved(u32 reserved[][4]) +{ + void __iomem *reg_base; + int i; + + if(rpmstats == NULL) { + pr_err("%s: rpm stats has not been initialized\n", __func__); + return; + } + + reg_base = ioremap_nocache(rpmstats->phys_addr_base, + rpmstats->phys_size); + if (reg_base == NULL) { + pr_err("%s: ERROR could not ioremap start=%p, len=%u\n", + __func__, (void *)rpmstats->phys_addr_base, + rpmstats->phys_size); + return; + } + + for(i = 0; i < 2; i++) { + reserved[i][0] = msm_rpmstats_read_long_register_v2(reg_base, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved)); + reserved[i][1] = msm_rpmstats_read_long_register_v2(reg_base, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved) + 4); + reserved[i][2] = msm_rpmstats_read_long_register_v2(reg_base, + i, offsetof(struct msm_rpm_stats_data_v2, + reserved) + 8); + } + + iounmap(reg_base); +} +#endif +/* lenovo.sw end chenyb1 add for adding master vote info in rpm_state */ + static const struct file_operations msm_rpmstats_fops = { .owner = THIS_MODULE, .open = msm_rpmstats_file_open, @@ -528,6 +603,11 @@ static int msm_rpmstats_probe(struct platform_device *pdev) msm_rpmstats_create_sysfs(pdata); platform_set_drvdata(pdev, dent); +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG + rpmstats = pdata; +#endif +/* lenovo.sw end chenyb1 add for adding master vote info in rpm_state */ return 0; } @@ -539,6 +619,11 @@ static int msm_rpmstats_remove(struct platform_device *pdev) debugfs_remove(dent); debugfs_remove(heap_dent); platform_set_drvdata(pdev, NULL); +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG + rpmstats = NULL; +#endif +/* lenovo.sw end chenyb1 add for adding master vote info in rpm_state */ return 0; } diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 16115619..f958d98e 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -662,10 +662,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) desc->ret[0] = desc->ret[1] = desc->ret[2] = 0; - pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5); - trace_scm_call_start(x0, desc); if (scm_version == SCM_ARMV8_64) @@ -695,10 +691,8 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); if (ret < 0) - pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", - x0, desc->arginfo, desc->args[0], desc->args[1], - desc->args[2], desc->x5, ret, desc->ret[0], - desc->ret[1], desc->ret[2]); + pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", + x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]); if (arglen > N_REGISTER_ARGS) kfree(desc->extra_arg_buf); diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index d4efd42c..a8a284ff 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -548,6 +548,8 @@ struct smd_shared_word_access { /** * Maps edge type to local and remote processor ID's. */ +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ +#ifdef CONFIG_LENOVO_PM_LOG static struct edge_to_pid edge_to_pids[] = { [SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"}, [SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "adsp"}, @@ -564,13 +566,39 @@ static struct edge_to_pid edge_to_pids[] = { [SMD_QDSP_Q6FW] = {SMD_Q6, SMD_MODEM_Q6_FW}, [SMD_DSPS_Q6FW] = {SMD_DSPS, SMD_MODEM_Q6_FW}, [SMD_WCNSS_Q6FW] = {SMD_WCNSS, SMD_MODEM_Q6_FW}, - [SMD_APPS_RPM] = {SMD_APPS, SMD_RPM}, + [SMD_APPS_RPM] = {SMD_APPS, SMD_RPM, "rpm"}, [SMD_MODEM_RPM] = {SMD_MODEM, SMD_RPM}, [SMD_QDSP_RPM] = {SMD_Q6, SMD_RPM}, [SMD_WCNSS_RPM] = {SMD_WCNSS, SMD_RPM}, [SMD_TZ_RPM] = {SMD_TZ, SMD_RPM}, }; + +#else +static struct edge_to_pid edge_to_pids[] = { + [SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"}, + [SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "adsp"}, + [SMD_MODEM_QDSP] = {SMD_MODEM, SMD_Q6}, + [SMD_APPS_DSPS] = {SMD_APPS, SMD_DSPS, "dsps"}, + [SMD_MODEM_DSPS] = {SMD_MODEM, SMD_DSPS}, + [SMD_QDSP_DSPS] = {SMD_Q6, SMD_DSPS}, + [SMD_APPS_WCNSS] = {SMD_APPS, SMD_WCNSS, "wcnss"}, + [SMD_MODEM_WCNSS] = {SMD_MODEM, SMD_WCNSS}, + [SMD_QDSP_WCNSS] = {SMD_Q6, SMD_WCNSS}, + [SMD_DSPS_WCNSS] = {SMD_DSPS, SMD_WCNSS}, + [SMD_APPS_Q6FW] = {SMD_APPS, SMD_MODEM_Q6_FW}, + [SMD_MODEM_Q6FW] = {SMD_MODEM, SMD_MODEM_Q6_FW}, + [SMD_QDSP_Q6FW] = {SMD_Q6, SMD_MODEM_Q6_FW}, + [SMD_DSPS_Q6FW] = {SMD_DSPS, SMD_MODEM_Q6_FW}, + [SMD_WCNSS_Q6FW] = {SMD_WCNSS, SMD_MODEM_Q6_FW}, + [SMD_APPS_RPM] = {SMD_APPS, SMD_RPM}, + [SMD_MODEM_RPM] = {SMD_MODEM, SMD_RPM}, + [SMD_QDSP_RPM] = {SMD_Q6, SMD_RPM}, + [SMD_WCNSS_RPM] = {SMD_WCNSS, SMD_RPM}, + [SMD_TZ_RPM] = {SMD_TZ, SMD_RPM}, +}; +#endif +/* lenovo.sw begin chenyb1 add for adding master vote info in rpm_state */ struct restart_notifier_block { unsigned processor; char *name; diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index fc5688b4..79b8ffbc 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p.c * - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -519,8 +519,8 @@ static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item, char entry_name[SMP2P_MAX_ENTRY_NAME]; if (!item || !name || !entry_ptr) { - SMP2P_ERR("%s: invalid arguments %p, %p, %p\n", - __func__, item, name, entry_ptr); + SMP2P_ERR("%s: invalid arguments %d %d %d\n", + __func__, !item, !name, !entry_ptr); return; } diff --git a/drivers/soc/qcom/smp2p_debug.c b/drivers/soc/qcom/smp2p_debug.c index 4deb05a0..8d98d07c 100644 --- a/drivers/soc/qcom/smp2p_debug.c +++ b/drivers/soc/qcom/smp2p_debug.c @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p_debug.c * - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014,2016 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 @@ -41,7 +41,7 @@ static void smp2p_int_stats(struct seq_file *s) pid != SMP2P_REMOTE_MOCK_PROC) continue; - seq_printf(s, "| %5s (%d) | %11u | %10u | %10u | %p | %08x |\n", + seq_printf(s, "| %5s (%d) | %11u | %10u | %10u | %pK | %08x |\n", int_cfg[pid].name, pid, int_cfg[pid].in_int_id, int_cfg[pid].in_interrupt_count, diff --git a/drivers/soc/qcom/smp2p_test_common.h b/drivers/soc/qcom/smp2p_test_common.h index 747a812d..3be519bc 100644 --- a/drivers/soc/qcom/smp2p_test_common.h +++ b/drivers/soc/qcom/smp2p_test_common.h @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p_test_common.h * - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014,2016 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 @@ -49,7 +49,8 @@ void *a_tmp = (a); \ void *b_tmp = (b); \ if (!((a_tmp)cmp(b_tmp))) { \ - seq_printf(s, "%s:%d Fail: " #a "(%p) " #cmp " " #b "(%p)\n", \ + seq_printf(s, "%s:%d Fail: " #a "(%pK) " #cmp \ + " " #b "(%pK)\n", \ __func__, __LINE__, \ a_tmp, b_tmp); \ failed = 1; \ diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index f98cfbc8..19a306d4 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -25,6 +25,7 @@ #include <linux/msm-bus-board.h> #include <linux/msm-bus.h> #include <linux/dma-mapping.h> +#include <linux/highmem.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/ramdump.h> @@ -613,6 +614,10 @@ static int pil_init_image_trusted(struct pil_desc *pil, return -ENOMEM; } + /* Make sure there are no mappings in PKMAP and fixmap */ + kmap_flush_unused(); + kmap_atomic_flush_unused(); + memcpy(mdata_buf, metadata, size); request.proc = d->pas_id; diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 5fc22ce2..e0d566cb 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -1640,6 +1640,13 @@ struct subsys_device *subsys_register(struct subsys_desc *desc) strlcpy(subsys->desc->fw_name, desc->name, sizeof(subsys->desc->fw_name)); +//lenovo sw, yexh1 add for set the modem resart level to RELATED at init + if (!strcmp(desc->name, "modem")){ + subsys->restart_level = RESET_SUBSYS_COUPLED; + pr_info("set the %s restart level to RELATED'\n", desc->name); + } +//lenovo sw, yexh1 end + subsys->notify = subsys_notif_add_subsys(desc->name); snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name); diff --git a/drivers/soc/qcom/tracer_pkt_private.h b/drivers/soc/qcom/tracer_pkt_private.h index fc760e6b..79e0bd3c 100644 --- a/drivers/soc/qcom/tracer_pkt_private.h +++ b/drivers/soc/qcom/tracer_pkt_private.h @@ -15,7 +15,7 @@ #undef TRACE_SYSTEM #define TRACE_SYSTEM tracer_pkt #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_PATH ../../drivers/soc/qcom #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE tracer_pkt_private diff --git a/drivers/soc/qcom/unlock_bl/Kconfig b/drivers/soc/qcom/unlock_bl/Kconfig new file mode 100644 index 00000000..14f57245 --- /dev/null +++ b/drivers/soc/qcom/unlock_bl/Kconfig @@ -0,0 +1,5 @@ +config LENOVO_UNLOCK_BL + bool "lenovo_unlock_bl" + help + This driver helps in mitigating unlock code from LK into proc system. + Say Y here could be enabled with DTS parsing and copy data into userspace. diff --git a/drivers/soc/qcom/unlock_bl/Makefile b/drivers/soc/qcom/unlock_bl/Makefile new file mode 100644 index 00000000..899eb8b3 --- /dev/null +++ b/drivers/soc/qcom/unlock_bl/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_LENOVO_UNLOCK_BL) += unlock_bl.o diff --git a/drivers/soc/qcom/unlock_bl/unlock_bl.c b/drivers/soc/qcom/unlock_bl/unlock_bl.c new file mode 100644 index 00000000..82ac0b8c --- /dev/null +++ b/drivers/soc/qcom/unlock_bl/unlock_bl.c @@ -0,0 +1,150 @@ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/device.h> +#include <linux/of_fdt.h> +#include <asm/setup.h> +#include <linux/seq_file.h> +#include <asm/setup.h> +#include <soc/qcom/bootinfo.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#ifndef CONFIG_ARM64 +#include <asm/mach/arch.h> +#endif + + +#define UNLOCK_CODE_LEN 256 +#define PUBK_SHA1_FP_SIZE 60 +//#define DUMP_UNLOCK_CODE + +static char unlock_code_string[2*UNLOCK_CODE_LEN + PUBK_SHA1_FP_SIZE + 1] = "\0"; +struct proc_dir_entry * sec_unlock_entry = NULL; + + +#ifdef DUMP_UNLOCK_CODE +static void dump_unlock_code(char *src, char *dst, int src_len, int dst_len) +{ + + int i = 0; + char temp[3] = {0}; + + if (dst_len <= src_len * 2) { + pr_err("[Unlock BL]:%s\tinput length exceeds the output one\n", __func__); + return; + } + + for (i = 0; i < src_len; i++) { + sprintf(temp, "%02x", (unsigned char)src[i]); + memcpy(&dst[ i*2 ], temp, 2); + } + + printk("[Unlock BL]:Dump Hex str %d length is:%s\n", (int)strlen(dst), dst); + return; +} +#endif + +ssize_t sec_unlock_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + + int len = strlen(unlock_code_string); +#ifdef DUMP_UNLOCK_CODE + char hex_buff[2*UNLOCK_CODE_LEN + 1] = {0}; +#endif + if (*f_pos > 0) { + printk("[Unlock BL]: Need to locate correct position\n"); + *f_pos = 0; + return -EINVAL; + } + +#ifdef DUMP_UNLOCK_CODE + /* Note the original data in the unlock buffer where passed from LK is binary formatter. + * Nevertheless it's without meaning since encrypted data may contain '\0' as terminator. + */ + printk("[Unlock BL]: data from LK corruption with real len:(%d)\n", len); + dump_unlock_code(unlock_code_string, hex_buff, UNLOCK_CODE_LEN, 2*UNLOCK_CODE_LEN +1); + +#endif + + if (copy_to_user((char*)buf, unlock_code_string, len)) { + pr_err("[Unlock_BL]: Copy data to userspace error\n"); + return -EFAULT; + } + + *f_pos += len; + return len; + +} + +ssize_t sec_unlock_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + /* Dont allow to write or modification this memory. */ + return 0; +} + +ssize_t sec_unlock_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +ssize_t sec_unlock_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); + +static struct file_operations unlock_file_fops = { + .read = sec_unlock_proc_read, + .write = sec_unlock_proc_write, +}; + + +static int __init unlock_bl_of_populate_setup(void) +{ + int ret = -1; + struct device_node *n = of_find_node_by_path("/chosen"); + const char *unlock_code = NULL; + + ret = of_property_read_string(n, "mmi,unlock_code", &unlock_code); + if (ret == 0) { + strlcpy(unlock_code_string, unlock_code, sizeof(unlock_code_string)); + } + + of_node_put(n); + + return ret; +} + + +static int __init proc_unlock_init(void) +{ + int ret = 0; + ret = unlock_bl_of_populate_setup(); + if (ret != 0) { + + pr_err("[Unlock BL]: Unable to acquire the mmi unlock_code\n\r"); + return -1; + } + + + sec_unlock_entry = proc_create("sec_unlock_code", 0664, NULL, &unlock_file_fops); + if (sec_unlock_entry == NULL) { + pr_err("[Unlock BL]: Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + + +static void __exit proc_unlock_exit(void) { + + if (NULL != sec_unlock_entry) { + proc_remove(sec_unlock_entry); + } +} + + +module_init(proc_unlock_init); +module_exit(proc_unlock_exit); +MODULE_DESCRIPTION("Lenovo Mobile Group. Unlock code"); +MODULE_LICENSE("GPL v2"); + |
