From 9986d0f71006317014fa8d7a8e5ff677f217d9ad Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Tue, 21 Jun 2016 14:35:50 +0530 Subject: soc: qcom: smem: Renaming smem item SMEM_SMEM_STATIC_LOG_EVENTS SMEM_SMEM_STATIC_LOG_EVENTS is currently unused as its usecase has been deprecated for a long time. Reallocate the ID to SMEM_CHARGER_BATTERY_INFO. CRs-Fixed: 1032131 Change-Id: I35a8307001ac14e3ade733d5f41d6231fe63ebd0 Signed-off-by: Dhoat Harpal --- include/soc/qcom/smem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h index d8ee4d523880..9295532dec8a 100644 --- a/include/soc/qcom/smem.h +++ b/include/soc/qcom/smem.h @@ -78,6 +78,7 @@ enum { SMEM_SMEM_LOG_EVENTS, SMEM_XBL_LOADER_CORE_INFO, SMEM_SMEM_STATIC_LOG_EVENTS, + SMEM_CHARGER_BATTERY_INFO = SMEM_SMEM_STATIC_LOG_EVENTS, SMEM_SMEM_SLOW_CLOCK_SYNC, SMEM_SMEM_SLOW_CLOCK_VALUE, SMEM_BIO_LED_BUF, -- cgit v1.2.3 From 23a1f5a2a64c391c376a74c8b77c82a60317fe02 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Wed, 23 Mar 2016 17:03:05 +0530 Subject: regulator: cpr3: Add panic handler to dump register contents Add panic handler to dump a few critical CPR registers when device crashes due to kernel panic errors. CRs-Fixed: 1004533 Change-Id: Id01b4f959c134af48c509ade61c7ec46401b4e70 Signed-off-by: Tirupathi Reddy --- .../bindings/regulator/cpr3-regulator.txt | 13 ++++ .../bindings/regulator/cpr4-apss-regulator.txt | 7 +++ drivers/regulator/cpr3-regulator.c | 47 +++++++++++++++ drivers/regulator/cpr3-regulator.h | 34 +++++++++++ drivers/regulator/cpr3-util.c | 70 ++++++++++++++++++++++ 5 files changed, 171 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt index 0a5ad543a2be..7d88e9fbd9c6 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt @@ -183,6 +183,19 @@ Platform independent properties: This is the voltage that vdd-supply must be set to when performing an aging measurement. +- qcom,cpr-panic-reg-addr-list + Usage: optional + Value type: + Definition: Array of register addresses to be dumped when device resets. + +- qcom,cpr-panic-reg-name-list + Usage: optional, though only meaningful if + qcom,cpr-panic-reg-addr-list is specified + Value type: + Definition: Address names. Must be specified in the same order + as the corresponding addresses are specified in + the qcom,cpr-panic-reg-addr-list property. + ================================================= Second Level Nodes - CPR Threads for a Controller ================================================= diff --git a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt index ff60d6e3ef7f..891feb571157 100644 --- a/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr4-apss-regulator.txt @@ -407,6 +407,13 @@ apc_cpr: cpr4-ctrl@b018000 { qcom,cpr-step-quot-fixed = <16>; qcom,cpr-voltage-settling-time = <1600>; + qcom,cpr-panic-reg-addr-list = + <0xb1d2c18 0xb1d2900 0x0b1112b0 0xb018798>; + qcom,cpr-panic-reg-name-list = + "CCI_SAW4_PMIC_STS", "CCI_SAW4_VCTL", + "APCS_ALIAS0_APM_CTLER_STATUS", + "APCS0_CPR_CORE_ADJ_MODE_REG"; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <1>; diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index 9f5c67bc2d6f..c13e811a5d71 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -5880,6 +5880,42 @@ static int cpr3_regulator_validate_controller(struct cpr3_controller *ctrl) return 0; } +/** + * cpr3_panic_callback() - panic notification callback function. This function + * is invoked when a kernel panic occurs. + * @nfb: Notifier block pointer of CPR3 controller + * @event: Value passed unmodified to notifier function + * @data: Pointer passed unmodified to notifier function + * + * Return: NOTIFY_OK + */ +static int cpr3_panic_callback(struct notifier_block *nfb, + unsigned long event, void *data) +{ + struct cpr3_controller *ctrl = container_of(nfb, + struct cpr3_controller, panic_notifier); + struct cpr3_panic_regs_info *regs_info = ctrl->panic_regs_info; + struct cpr3_reg_info *reg; + void __iomem *virt_addr; + int i = 0; + + for (i = 0; i < regs_info->reg_count; i++) { + reg = &(regs_info->regs[i]); + virt_addr = ioremap(reg->addr, 0x4); + reg->value = readl_relaxed(virt_addr); + iounmap(virt_addr); + pr_err("%s[0x%08x] = 0x%08x\n", reg->name, reg->addr, + reg->value); + } + /* + * Barrier to ensure that the information has been updated in the + * structure. + */ + mb(); + + return NOTIFY_OK; +} + /** * cpr3_regulator_register() - register the regulators for a CPR3 controller and * perform CPR hardware initialization @@ -6031,6 +6067,13 @@ int cpr3_regulator_register(struct platform_device *pdev, list_add(&ctrl->list, &cpr3_controller_list); mutex_unlock(&cpr3_controller_list_mutex); + if (ctrl->panic_regs_info) { + /* Register panic notification call back */ + ctrl->panic_notifier.notifier_call = cpr3_panic_callback; + atomic_notifier_chain_register(&panic_notifier_list, + &ctrl->panic_notifier); + } + return 0; free_regulators: @@ -6082,5 +6125,9 @@ int cpr3_regulator_unregister(struct cpr3_controller *ctrl) for (j = 0; j < ctrl->thread[i].vreg_count; j++) regulator_unregister(ctrl->thread[i].vreg[j].rdev); + if (ctrl->panic_notifier.notifier_call) + atomic_notifier_chain_unregister(&panic_notifier_list, + &ctrl->panic_notifier); + return 0; } diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 0c4b6cb66805..d750b70519d1 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -493,6 +493,35 @@ struct cpr3_aging_sensor_info { u32 bypass_mask[CPR3_MAX_SENSOR_COUNT / 32]; }; +/** + * struct cpr3_reg_info - Register information data structure + * @name: Register name + * @addr: Register physical address + * @value: Register content + * + * This data structure is used to dump some critical register contents + * when the device crashes due to a kernel panic. + */ +struct cpr3_reg_info { + const char *name; + u32 addr; + u32 value; +}; + +/** + * struct cpr3_panic_regs_info - Data structure to dump critical register + * contents. + * @reg_count: Number of elements in the regs array + * @regs: Array of critical registers information + * + * This data structure is used to dump critical register contents when + * the device crashes due to a kernel panic. + */ +struct cpr3_panic_regs_info { + int reg_count; + struct cpr3_reg_info *regs; +}; + /** * struct cpr3_controller - CPR3 controller data structure * @dev: Device pointer for the CPR3 controller device @@ -662,6 +691,9 @@ struct cpr3_aging_sensor_info { * VDD supply voltage to settle after being increased or * decreased by step_volt microvolts which is used when * SDELTA voltage margin adjustments are applied. + * @panic_regs_info: Array of panic registers information which provides the + * list of registers to dump when the device crashes. + * @panic_notifier: Notifier block registered to global panic notifier list. * * This structure contains both configuration and runtime state data. The * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled, @@ -755,6 +787,8 @@ struct cpr3_controller { u32 temp_sensor_id_start; u32 temp_sensor_id_end; u32 voltage_settling_time; + struct cpr3_panic_regs_info *panic_regs_info; + struct notifier_block panic_notifier; }; /* Used for rounding voltages to the closest physically available set point. */ diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 164579344c81..57631b14b5f6 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -1020,6 +1020,74 @@ static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl) return 0; } +static int cpr3_panic_notifier_init(struct cpr3_controller *ctrl) +{ + struct device_node *node = ctrl->dev->of_node; + struct cpr3_panic_regs_info *panic_regs_info; + struct cpr3_reg_info *regs; + int i, reg_count, len, rc = 0; + + if (!of_find_property(node, "qcom,cpr-panic-reg-addr-list", &len)) { + /* panic register address list not specified */ + return rc; + } + + reg_count = len / sizeof(u32); + if (!reg_count) { + cpr3_err(ctrl, "qcom,cpr-panic-reg-addr-list has invalid len = %d\n", + len); + return -EINVAL; + } + + if (!of_find_property(node, "qcom,cpr-panic-reg-name-list", NULL)) { + cpr3_err(ctrl, "property qcom,cpr-panic-reg-name-list not specified\n"); + return -EINVAL; + } + + len = of_property_count_strings(node, "qcom,cpr-panic-reg-name-list"); + if (reg_count != len) { + cpr3_err(ctrl, "qcom,cpr-panic-reg-name-list should have %d strings\n", + reg_count); + return -EINVAL; + } + + panic_regs_info = devm_kzalloc(ctrl->dev, sizeof(*panic_regs_info), + GFP_KERNEL); + if (!panic_regs_info) + return -ENOMEM; + + regs = devm_kcalloc(ctrl->dev, reg_count, sizeof(*regs), GFP_KERNEL); + if (!regs) + return -ENOMEM; + + for (i = 0; i < reg_count; i++) { + rc = of_property_read_string_index(node, + "qcom,cpr-panic-reg-name-list", i, + &(regs[i].name)); + if (rc) { + cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-name-list, rc=%d\n", + rc); + return rc; + } + + rc = of_property_read_u32_index(node, + "qcom,cpr-panic-reg-addr-list", i, + &(regs[i].addr)); + if (rc) { + cpr3_err(ctrl, "error reading property qcom,cpr-panic-reg-addr-list, rc=%d\n", + rc); + return rc; + } + regs[i].value = 0xFFFFFFFF; + } + + panic_regs_info->reg_count = reg_count; + panic_regs_info->regs = regs; + ctrl->panic_regs_info = panic_regs_info; + + return rc; +} + /** * cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from * device tree @@ -1147,6 +1215,8 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) } } + rc = cpr3_panic_notifier_init(ctrl); + return rc; } -- cgit v1.2.3 From 506ddf3b445f5392f01d3ea2aeff782ae4ef0b37 Mon Sep 17 00:00:00 2001 From: Osvaldo Banuelos Date: Wed, 22 Jun 2016 14:51:47 -0700 Subject: regulator: cpr3-util: init panic notifier for CPRh controllers Call cpr3_panic_notifier_init() when cpr3_parse_common_ctrl_data() is called for CPRh controllers. This allows dumping registers during a kernel panic when CPRh controller devices specify panic register configuration. CRs-Fixed: 1033060 Change-Id: I437fe28725d5c1ed06fe8b9735b04bbd84e92db1 Signed-off-by: Osvaldo Banuelos --- drivers/regulator/cpr3-util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 57631b14b5f6..34b51ec8cab8 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -1174,6 +1174,10 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) } } + rc = cpr3_panic_notifier_init(ctrl); + if (rc) + return rc; + /* * Regulator device handles are not necessary for CPRh controllers * since communication with the regulators is completely managed @@ -1215,8 +1219,6 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) } } - rc = cpr3_panic_notifier_init(ctrl); - return rc; } -- cgit v1.2.3 From a26ae43d87f17437319b0a2f5e30b9f79ad18950 Mon Sep 17 00:00:00 2001 From: Osvaldo Banuelos Date: Wed, 22 Jun 2016 14:33:29 -0700 Subject: ARM: dts: msm: add CPR panic register configuration for msmcobalt Specify the panic register configuration in the VDD_APC0 and VDD_APC1 CPR device nodes. This enables the CPR panic handler to dump the values of the specified registers during a kernel panic. CRs-Fixed: 1033060 Change-Id: Ifdd03f27ed1135acd4470d891e1b5aca4a11dd65 Signed-off-by: Osvaldo Banuelos --- arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 7dc276bb5fdb..21dbb8143061 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -614,6 +614,11 @@ qcom,cpr-enable; qcom,cpr-hw-closed-loop; + qcom,cpr-panic-reg-addr-list = + <0x179cbaa4 0x17912c18>; + qcom,cpr-panic-reg-name-list = + "PWR_CPRH_STATUS", "APCLUS0_L2_SAW4_PMIC_STS"; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; @@ -770,6 +775,11 @@ qcom,cpr-enable; qcom,cpr-hw-closed-loop; + qcom,cpr-panic-reg-addr-list = + <0x179c7aa4 0x17812c18>; + qcom,cpr-panic-reg-name-list = + "PERF_CPRH_STATUS", "APCLUS1_L2_SAW4_PMIC_STS"; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; -- cgit v1.2.3 From 73fa24503bf34047745bfd0602ec59f3ee2c74db Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 10 Jun 2016 12:33:18 -0700 Subject: scsi: ufs-debugfs: add error state This change adds support to allow user space query if low level UFS driver has encountered any error or not, this state can be read/cleared via debugfs. Change-Id: I867a4621315108aff17be852cfaadcfa945566a7 Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufs-debugfs.c | 47 +++++++++++++++++++++++++++++++++++++++++- drivers/scsi/ufs/ufs-debugfs.h | 6 +++++- drivers/scsi/ufs/ufshcd.c | 16 ++++++++++++++ drivers/scsi/ufs/ufshcd.h | 2 ++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c index 0f2f9bd91e02..f3b4b6c08571 100644 --- a/drivers/scsi/ufs/ufs-debugfs.c +++ b/drivers/scsi/ufs/ufs-debugfs.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 @@ -1433,6 +1433,41 @@ static const struct file_operations ufsdbg_reset_controller = { .write = ufsdbg_reset_controller_write, }; +static int ufsdbg_clear_err_state(void *data, u64 val) +{ + struct ufs_hba *hba = data; + + if (!hba) + return -EINVAL; + + /* clear the error state on any write attempt */ + hba->debugfs_files.err_occurred = false; + + return 0; +} + +static int ufsdbg_read_err_state(void *data, u64 *val) +{ + struct ufs_hba *hba = data; + + if (!hba) + return -EINVAL; + + *val = hba->debugfs_files.err_occurred ? 1 : 0; + + return 0; +} + +void ufsdbg_set_err_state(struct ufs_hba *hba) +{ + hba->debugfs_files.err_occurred = true; +} + +DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_err_state, + ufsdbg_read_err_state, + ufsdbg_clear_err_state, + "%llu\n"); + void ufsdbg_add_debugfs(struct ufs_hba *hba) { char root_name[sizeof("ufshcd00")]; @@ -1594,6 +1629,16 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba) goto err; } + hba->debugfs_files.err_state = + debugfs_create_file("err_state", S_IRUSR | S_IWUSR, + hba->debugfs_files.debugfs_root, hba, + &ufsdbg_err_state); + if (!hba->debugfs_files.err_state) { + dev_err(hba->dev, + "%s: failed create err_state debugfs entry", __func__); + goto err; + } + ufsdbg_setup_fault_injection(hba); ufshcd_vops_add_debugfs(hba, hba->debugfs_files.debugfs_root); diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h index bf4d51ac8935..13848e8b72e0 100644 --- a/drivers/scsi/ufs/ufs-debugfs.h +++ b/drivers/scsi/ufs/ufs-debugfs.h @@ -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 @@ -37,6 +37,7 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba); void ufsdbg_remove_debugfs(struct ufs_hba *hba); void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs, char *str, void *priv); +void ufsdbg_set_err_state(struct ufs_hba *hba); #else static inline void ufsdbg_add_debugfs(struct ufs_hba *hba) { @@ -48,6 +49,9 @@ static inline void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs, char *str, void *priv) { } +void ufsdbg_set_err_state(struct ufs_hba *hba) +{ +} #endif #ifdef CONFIG_UFS_FAULT_INJECTION diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 40dcaa8f0eee..ad679e5d3f76 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -71,6 +71,7 @@ static int ufshcd_tag_req_type(struct request *rq) static void ufshcd_update_error_stats(struct ufs_hba *hba, int type) { + ufsdbg_set_err_state(hba); if (type < UFS_ERR_MAX) hba->ufs_stats.err_stats[type]++; } @@ -2143,6 +2144,9 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) else ret = -ETIMEDOUT; + if (ret) + ufsdbg_set_err_state(hba); + spin_lock_irqsave(hba->host->host_lock, flags); hba->active_uic_cmd = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2842,6 +2846,9 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, ufshcd_outstanding_req_clear(hba, lrbp->task_tag); } + if (err) + ufsdbg_set_err_state(hba); + return err; } @@ -3874,6 +3881,9 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) ret = (status != PWR_OK) ? status : -1; } out: + if (ret) + ufsdbg_set_err_state(hba); + ufshcd_save_tstamp_of_last_dme_cmd(hba); spin_lock_irqsave(hba->host->host_lock, flags); hba->active_uic_cmd = NULL; @@ -4947,6 +4957,11 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) ocs == OCS_MISMATCH_DATA_BUF_SIZE); ufshcd_print_trs(hba, 1 << lrbp->task_tag, print_prdt); } + + if ((host_byte(result) == DID_ERROR) || + (host_byte(result) == DID_ABORT)) + ufsdbg_set_err_state(hba); + return result; } @@ -5532,6 +5547,7 @@ static void ufshcd_err_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eh_work); + ufsdbg_set_err_state(hba); pm_runtime_get_sync(hba->dev); ufshcd_hold_all(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 1ccda45743d6..a4ee3726edb0 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -543,6 +543,8 @@ struct debugfs_files { u32 dme_local_attr_id; u32 dme_peer_attr_id; struct dentry *reset_controller; + struct dentry *err_state; + bool err_occurred; #ifdef CONFIG_UFS_FAULT_INJECTION struct dentry *err_inj_scenario; struct dentry *err_inj_stats; -- cgit v1.2.3 From 5812a73a1459918f892f96213f44eb083a66b538 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 16 Jun 2016 09:44:14 +1000 Subject: mm, sl[au]b: add __GFP_ATOMIC to the GFP reclaim mask Commit d0164adc89f6 ("mm, page_alloc: distinguish between being unable to sleep, unwilling to sleep and avoiding waking kswapd") modified __GFP_WAIT to explicitly identify the difference between atomic callers and those that were unwilling to sleep. Later the definition was removed entirely. The GFP_RECLAIM_MASK is the set of flags that affect watermark checking and reclaim behaviour but __GFP_ATOMIC was never added. Without it, atomic users of the slab allocator strip the __GFP_ATOMIC flag and cannot access the page allocator atomic reserves. This patch addresses the problem. The user-visible impact depends on the workload but potentially atomic allocations unnecessarily fail without this path. Change-Id: Ieac0932d146f7fd992db9fd834b0e9aa3822f891 Link: http://lkml.kernel.org/r/20160610093832.GK2527@techsingularity.net Signed-off-by: Mel Gorman Reported-by: Marcin Wojtas Acked-by: Vlastimil Babka Acked-by: Michal Hocko Cc: [4.4+] Signed-off-by: Andrew Morton Git-Commit: 843f65ccbb2273430b57ae135ccd26dddee05be7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Vinayak Menon --- mm/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/internal.h b/mm/internal.h index 899f7b332a0b..55d4fa99b486 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -22,7 +22,8 @@ */ #define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\ __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\ - __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC) + __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\ + __GFP_ATOMIC) /* The GFP flags allowed during early boot */ #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS)) -- cgit v1.2.3 From 54588859dbe2840d4cd4657bbca6fa142f4d23a4 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Mon, 20 Jun 2016 18:09:07 +0530 Subject: ASoC: msm: qdsp6v2: DAP: Add check to validate data length Validate input data length to ensure only relevant data is copied. CRs-Fixed: 1027585 Change-Id: I67eb4f162f944bbf4d9e55fb8fe93759e6b8ff91 Signed-off-by: Ashish Jain --- sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c index fea7bb4e7331..379062eee285 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c @@ -1522,6 +1522,14 @@ static int msm_ds2_dap_get_param(u32 cmd, void *arg) goto end; } + /* Return if invalid length */ + if (dolby_data->length > + (DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM - DOLBY_PARAM_PAYLOAD_SIZE)) { + pr_err("Invalid length %d", dolby_data->length); + rc = -EINVAL; + goto end; + } + for (i = 0; i < DS2_DEVICES_ALL; i++) { if ((dev_map[i].active) && (dev_map[i].device_id & dolby_data->device_id)) { -- cgit v1.2.3 From 99c05f926ee82537aa7405faec7605daedf56a68 Mon Sep 17 00:00:00 2001 From: Alan Kwong Date: Fri, 17 Jun 2016 10:11:29 -0400 Subject: msm: mdss: Add dereference check for xlog vbif dump Bypass vbif dump for ununsed vbif by checking for null pointer dereference of io base. Change-Id: Ic7204921fc82d5aea31c58fcbb668b296794b1c1 CRs-Fixed: 1030443 Signed-off-by: Alan Kwong --- drivers/video/fbdev/msm/mdss_debug_xlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c index c696832a96e8..a34bce1200d8 100644 --- a/drivers/video/fbdev/msm/mdss_debug_xlog.c +++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c @@ -349,7 +349,7 @@ static void mdss_dump_vbif_debug_bus(u32 bus_dump_flag, bus_size = mdata->nrt_vbif_dbg_bus_size; } - if (!dbg_bus || !bus_size) + if (!vbif_base || !dbg_bus || !bus_size) return; /* allocate memory for each test point */ -- cgit v1.2.3 From 1ca62857bd57317b8289b31753e4ee4ce14b0e87 Mon Sep 17 00:00:00 2001 From: Alan Kwong Date: Thu, 16 Jun 2016 21:08:57 -0400 Subject: ARM: dts: msm: Enable v4l2 rotator node on msm8996 Enable sde v4l2 rotator node on 8996. This replaces mdss rotator node. Reserve dma 0/1, writeback mixers, writeback 0/1, and control 5 for rotator driver. Disable WFD as it shares context bank with rotator. CRs-Fixed: 1030443 Change-Id: Ie3970f29c7f1800c4457dc71a3f36a54e1cbdb91 Signed-off-by: Alan Kwong --- arch/arm/boot/dts/qcom/msm8996-mdss.dtsi | 103 ++++++++++++++++--------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi index 5c01812d7d6e..3186f96b4275 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mdss.dtsi @@ -14,10 +14,11 @@ mdss_mdp: qcom,mdss_mdp@900000 { compatible = "qcom,mdss_mdp"; reg = <0x00900000 0x90000>, - <0x009b0000 0x1040>, - <0x009b8000 0x1040>; - reg-names = "mdp_phys", "vbif_phys", "vbif_nrt_phys"; + <0x009b0000 0x1040>; + reg-names = "mdp_phys", "vbif_phys"; interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; vdd-supply = <&gdsc_mdss>; #address-cells = <1>; @@ -65,12 +66,10 @@ 0x00009000 0x0000B000>; qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000 0x00019000 0x0001B000>; - qcom,mdss-pipe-dma-off = <0x00025000 0x00027000>; qcom,mdss-pipe-cursor-off = <0x00035000 0x00037000>; qcom,mdss-pipe-vig-xin-id = <0 4 8 12>; qcom,mdss-pipe-rgb-xin-id = <1 5 9 13>; - qcom,mdss-pipe-dma-xin-id = <2 10>; qcom,mdss-pipe-cursor-xin-id = <7 7>; /* These Offsets are relative to "mdp_phys + mdp-reg-offset" address */ @@ -82,19 +81,16 @@ <0x2B4 4 8>, <0x2BC 4 8>, <0x2C4 4 8>; - qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2AC 8 12>, - <0x2B4 8 12>; qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3A8 16 15>, <0x3B0 16 15>; qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400 - 0x00002600 0x00002800>; + 0x00002600>; qcom,mdss-mixer-intf-off = <0x00045000 0x00046000 0x00047000 0x0004A000>; - qcom,mdss-mixer-wb-off = <0x00048000 0x00049000>; qcom,mdss-dspp-off = <0x00055000 0x00057000>; - qcom,mdss-wb-off = <0x00065000 0x00065800 0x00066000>; + qcom,mdss-wb-off = <0x00066000>; qcom,mdss-intf-off = <0x0006B000 0x0006B800 0x0006C000 0x0006C800>; qcom,mdss-pingpong-off = <0x00071000 0x00071800 @@ -103,6 +99,7 @@ qcom,mdss-ppb-ctl-off = <0x00000330 0x00000338>; qcom,mdss-ppb-cfg-off = <0x00000334 0x0000033C>; qcom,mdss-has-pingpong-split; + qcom,mdss-has-separate-rotator; qcom,mdss-ad-off = <0x0079000 0x00079800 0x0007a000>; qcom,mdss-cdm-off = <0x0007a200>; @@ -111,7 +108,6 @@ qcom,mdss-has-source-split; qcom,mdss-highest-bank-bit = <0x2>; qcom,mdss-has-decimation; - qcom,mdss-has-rotator-downscale; qcom,mdss-idle-power-collapse-enabled; clocks = <&clock_mmss clk_mdss_ahb_clk>, <&clock_mmss clk_mdss_axi_clk>, @@ -248,19 +244,6 @@ "mdp_axi_clk"; }; - smmu_rot_unsec: qcom,smmu_rot_unsec_cb { - compatible = "qcom,smmu_rot_unsec"; - iommus = <&rot_smmu 0>; - reg = <0x00d09000 0xd00>; - reg-names = "mmu_cb"; - gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; - clocks = <&clock_mmss clk_smmu_rot_ahb_clk>, - <&clock_mmss clk_mmagic_mdss_axi_clk>, - <&clock_mmss clk_smmu_rot_axi_clk>; - clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk", - "rot_axi_clk"; - }; - smmu_mdp_sec: qcom,smmu_mdp_sec_cb { compatible = "qcom,smmu_mdp_sec"; iommus = <&mdp_smmu 1>; @@ -274,19 +257,6 @@ "mdp_axi_clk"; }; - smmu_rot_sec: qcom,smmu_rot_sec_cb { - compatible = "qcom,smmu_rot_sec"; - iommus = <&rot_smmu 1>; - reg = <0x00d0b000 0xd00>; - reg-names = "mmu_cb"; - gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; - clocks = <&clock_mmss clk_smmu_rot_ahb_clk>, - <&clock_mmss clk_mmagic_mdss_axi_clk>, - <&clock_mmss clk_smmu_rot_axi_clk>; - clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk", - "rot_axi_clk"; - }; - mdss_fb0: qcom,mdss_fb_primary { cell-index = <0>; compatible = "qcom,mdss-fb"; @@ -295,11 +265,6 @@ }; }; - mdss_fb1: qcom,mdss_fb_wfd { - cell-index = <1>; - compatible = "qcom,mdss-fb"; - }; - mdss_fb2: qcom,mdss_fb_hdmi { cell-index = <2>; compatible = "qcom,mdss-fb"; @@ -492,7 +457,6 @@ compatible = "qcom,mdss_wb"; qcom,mdss_pan_res = <640 480>; qcom,mdss_pan_bpp = <24>; - qcom,mdss-fb-map = <&mdss_fb1>; }; mdss_hdmi_tx: qcom,hdmi_tx@9a0000 { @@ -530,11 +494,15 @@ }; mdss_rotator: qcom,mdss_rotator { - compatible = "qcom,mdss_rotator"; - qcom,mdss-wb-count = <2>; - qcom,mdss-has-downscale; - qcom,mdss-has-ubwc; - qcom,mdss-has-reg-bus; + compatible = "qcom,sde_rotator"; + reg = <0x00900000 0x90000>, + <0x009b8000 0x1040>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + qcom,mdss-wb-count = <1>; + qcom,mdss-wb-id = <0>; + qcom,mdss-ctl-id = <4>; + qcom,mdss-highest-bank-bit = <0x2>; /* Bus Scale Settings */ qcom,msm-bus,name = "mdss_rotator"; qcom,msm-bus,num-cases = <3>; @@ -550,7 +518,42 @@ qcom,supply-names = "rot-mmagic-mdss-gdsc", "rot-vdd"; clocks = <&clock_mmss clk_mmss_misc_ahb_clk>, - <&clock_mmss clk_mdss_rotator_vote_clk>; - clock-names = "iface_clk", "rot_core_clk"; + <&clock_mmss clk_mdss_rotator_vote_clk>, + <&clock_mmss clk_mdss_ahb_clk>, + <&clock_mmss clk_mdss_axi_clk>, + <&clock_mmss clk_mdp_clk_src>; + clock-names = "iface_clk", "rot_core_clk", + "mdss_ahb_clk", "mdss_axi_clk", "mdp_clk_src"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <32 0>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <16>; + + smmu_rot_unsecure: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&rot_smmu 0>; + gdsc-mdss-supply = <&gdsc_mmagic_mdss>; + clocks = <&clock_mmss clk_smmu_rot_ahb_clk>, + <&clock_mmss clk_mmagic_mdss_axi_clk>, + <&clock_mmss clk_smmu_rot_axi_clk>; + clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk", + "rot_axi_clk"; + }; + + smmu_rot_secure: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&rot_smmu 1>; + gdsc-mdss-supply = <&gdsc_mmagic_mdss>; + clocks = <&clock_mmss clk_smmu_rot_ahb_clk>, + <&clock_mmss clk_mmagic_mdss_axi_clk>, + <&clock_mmss clk_smmu_rot_axi_clk>; + clock-names = "rot_ahb_clk", "mmagic_mdss_axi_clk", + "rot_axi_clk"; + }; }; }; -- cgit v1.2.3 From fc907d939b1f5b829995e33d90234d0ae195ecdd Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Mon, 20 Jun 2016 09:43:03 -0700 Subject: msm: mdss: fix multi-rect validation properties Fix issues with multi-rect to allow the multi-rects on the same z-order. In multi-rect use cases the rect 0 of the pipes have higher priority than rect 1. The change checks the priority of rect on the right mixer with the priority of rect on the pipe staged on left mixer. CRs-Fixed: 1023723 Change-Id: Ifd1df8ee04238db0338a7dd70eb5097af2d0eb62 Signed-off-by: Abhijit Kulkarni --- drivers/video/fbdev/msm/mdss_mdp_layer.c | 33 ++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 59283c815897..65b3b9739be6 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -662,6 +662,23 @@ exit_fail: return ret; } +static int __validate_pipe_priorities(struct mdss_mdp_pipe *left, + struct mdss_mdp_pipe *right) +{ + if (left->multirect.num > right->multirect.num) + return -EINVAL; + + if ((left->multirect.num == right->multirect.num) && + (left->priority >= right->priority)) + return -EINVAL; + + if ((left->multirect.num < right->multirect.num) && + (left->priority > right->priority)) + return -EINVAL; + + return 0; +} + static int __configure_pipe_params(struct msm_fb_data_type *mfd, struct mdss_mdp_validate_info_t *vinfo, struct mdss_mdp_pipe *pipe, struct mdss_mdp_pipe *left_blend_pipe, bool is_single_layer, @@ -773,10 +790,12 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, */ if (mdata->has_src_split) { if (left_blend_pipe) { - if (pipe->priority <= left_blend_pipe->priority) { - pr_err("priority limitation. left:%d right%d\n", - left_blend_pipe->priority, - pipe->priority); + if (__validate_pipe_priorities(left_blend_pipe, pipe)) { + pr_err("priority limitation. left:%d rect:%d, right:%d rect:%d\n", + left_blend_pipe->priority, + left_blend_pipe->multirect.num, + pipe->priority, + pipe->multirect.num); ret = -EPERM; goto end; } else { @@ -1521,12 +1540,6 @@ static bool __multirect_validate_properties(struct mdp_input_layer **layers, return false; } - if (layers[0]->z_order == layers[1]->z_order) { - pr_err("multirect layers cannot have same z_order=%d\n", - layers[0]->z_order); - return false; - } - return true; } -- cgit v1.2.3 From 80fbf5405fb059c33cbd3a7f677355cb92fec121 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Thu, 2 Jun 2016 17:38:53 -0700 Subject: regulator: Add snapshot of DT documentation for rpm-smd-regulator driver This DT bindings documentation snapshot is taken as of msm-3.18 'commit 00df358f2e6a8 ("regulator: rpm-smd-regulator: introduce BoB regulator type")'. CRs-Fixed: 1023326 Change-Id: Icc20967019996616a4eb2ebba6df47e7bc7188d7 Signed-off-by: Nicholas Troast --- .../bindings/regulator/rpm-smd-regulator.txt | 328 +++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt new file mode 100644 index 000000000000..ccefc98e51e5 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt @@ -0,0 +1,328 @@ +Qualcomm RPM Regulators + +rpm-regulator-smd is a regulator driver which supports regulators inside of +PMICs which are controlled by the RPM processor. Communication with the RPM +processor takes place over SMD. + +Required structure: +- RPM regulators must be described in two levels of devices nodes. The first + level describes the interface with the RPM. The second level describes + properties of one regulator framework interface (of potentially many) to + the regulator. + +[First Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator-resource" +- qcom,resource-name: Resource name string for this regulator to be used in RPM + transactions. Length is 4 characters max. +- qcom,resource-id: Resource instance ID for this regulator to be used in RPM + transactions. +- qcom,regulator-type: Type of this regulator. Supported values are: + 0 = LDO + 1 = SMPS + 2 = VS + 3 = NCP + 4 = Buck or Boost (BoB) + +Optional properties: +- qcom,allow-atomic: Flag specifying if atomic access is allowed for this + regulator. Supported values are: + 0 or not present = mutex locks used + 1 = spinlocks used +- qcom,enable-time: Time in us to delay after enabling the regulator +- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load + which requires the regulator to be in high power mode. +- qcom,apps-only: Flag which indicates that the regulator only has + consumers on the application processor. If this flag + is specified, then voltage and current updates are + only sent to the RPM if the regulator is enabled. +- qcom,always-wait-for-ack: Flag which indicates that the application + processor must wait for an ACK or a NACK from the RPM + for every request sent for this regulator including + those which are for a strictly lower power state. + +[Second Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator" +- regulator-name: A string used as a descriptive name for regulator outputs +- qcom,set: Specifies which sets that requests made with this + regulator interface should be sent to. Regulator + requests sent in the active set take effect immediately. + Requests sent in the sleep set take effect when the Apps + processor transitions into RPM assisted power collapse. + Supported values are: + 1 = Active set only + 2 = Sleep set only + 3 = Both active and sleep sets + + + +Optional properties: +- parent-supply: phandle to the parent supply/regulator node +- qcom,system-load: Load in uA present on regulator that is not + captured by any consumer request +- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage + calls should modify the corner parameter instead + of the voltage parameter. When used, voltages + specified inside of the regulator framework + represent corners that have been incremented by + 1. This value shift is necessary to work around + limitations in the regulator framework which + treat 0 uV as an error. +- qcom,use-voltage-floor-corner: Flag that signifies if regulator_set_voltage + calls should modify the floor corner parameter + instead of the voltage parameter. When used, + voltages specified inside of the regulator + framework represent corners that have been + incremented by 1. The properties + qcom,use-voltage-corner and + qcom,use-voltage-floor-corner are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-voltage-level: Flag that signifies if regulator_set_voltage + calls should modify the level parameter instead + of the voltage parameter. +- qcom,use-voltage-floor-level: Flag that signifies if regulator_set_voltage + calls should modify the floor level parameter + instead of the voltage parameter. + The properties qcom,use-voltage-level and + qcom,use-voltage-floor-level are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-pin-ctrl-voltage1: Flag which indicates that updates to voltage + should be sent to the pin control voltage 1 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage2: Flag which indicates that updates to voltage + should be sent to the pin control voltage 2 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage3: Flag which indicates that updates to voltage + should be sent to the pin control voltage 3 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,always-send-voltage: Flag which indicates that updates to the + voltage, voltage corner or voltage level set + point should always be sent immediately to the + RPM. If this flag is not specified, then + voltage set point updates are only sent if the + given regulator has also been enabled by a + Linux consumer. +- qcom,always-send-current: Flag which indicates that updates to the load + current should always be sent immediately to the + RPM. If this flag is not specified, then load + current updates are only sent if the given + regulator has also been enabled by a Linux + consumer. +- qcom,send-defaults: Boolean flag which indicates that the initial + parameter values should be sent to the RPM + before consumers make their own requests. If + this flag is not specified, then initial + parameters values will only be sent after some + consumer makes a request. +- qcom,enable-with-pin-ctrl: Double in which the first element corresponds to + the pin control enable parameter value to send + when all consumers have requested the regulator + to be disabled. The second element corresponds + to the pin control enable parameter value to + send when any consumer has requested the + regulator to be enabled. Each element supports + the same set of values as the + qcom,init-pin-ctrl-enable property listed below. + +The following properties specify initial values for parameters to be sent to the +RPM in regulator requests. +- qcom,init-enable: 0 = regulator disabled + 1 = regulator enabled +- qcom,init-voltage: Voltage in uV +- qcom,init-current: Current in mA +- qcom,init-ldo-mode: Operating mode to be used with LDO regulators + Supported values are: + 0 = mode determined by current requests + 1 = force HPM (NPM) +- qcom,init-smps-mode: Operating mode to be used with SMPS regulators + Supported values are: + 0 = auto; hardware determines mode + 1 = mode determined by current requests + 2 = force HPM (PWM) +- qcom,init-bob-mode: Operating mode to be used with BoB regulators + Supported values are: + 0 = pass; use priority order + 1 = force PFM + 2 = auto; hardware determines mode + 3 = force PWM +- qcom,init-pin-ctrl-enable: Bit mask specifying which hardware pins should be + used to enable the regulator, if any; supported + bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal +- qcom,init-pin-ctrl-mode: Bit mask specifying which hardware pins should be + used to force the regulator into high power + mode, if any. Supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state +- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin + control 1 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin + control 2 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin + control 3 is enabled. This property only + applies to BoB type regulators. +- qcom,init-frequency: Switching frequency divisor for SMPS regulators. + Supported values are n = 0 to 31 where + freq = 19.2 MHz / (n + 1). +- qcom,init-head-room: Voltage head room in mV required for the + regulator. This head room value should be used + in situations where the device connected to the + output of the regulator has low noise tolerance. + Note that the RPM independently enforces a + safety head room value for subregulated LDOs + which is sufficient to account for LDO drop-out + voltage. +- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS + regulator in order to have lower output noise. + Supported values are: + 0 = No quiet mode + 1 = Quiet mode + 2 = Super quiet mode +- qcom,init-freq-reason: Consumer requiring specified frequency for an + SMPS regulator. Supported values are: + 0 = None + 1 = Bluetooth + 2 = GPS + 4 = WLAN + 8 = WAN +- qcom,init-voltage-corner: Performance corner to use in order to determine + voltage set point. This value corresponds to + the actual value that will be sent and is not + incremented by 1 like the values used inside of + the regulator framework. The meaning of corner + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different corner values. These are + corner values supported on MSM8974 for PMIC + PM8841 SMPS 2 (VDD_Dig); nominal voltages for + these corners are also shown: + 0 = None (don't care) + 1 = Retention (0.5000 V) + 2 = SVS Krait (0.7250 V) + 3 = SVS SOC (0.8125 V) + 4 = Normal (0.9000 V) + 5 = Turbo (0.9875 V) + 6 = Super Turbo (1.0500 V) +- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a + given LDO regulator. When in bypass mode, an + LDO performs no regulation and acts as a simple + switch. The RPM can utilize this mode for an + LDO that is subregulated from an SMPS when it is + possible to reduce the SMPS voltage to the + desired LDO output level. Bypass mode may be + disallowed if lower LDO output noise is + required. Supported values are: + 0 = Allow RPM to utilize LDO bypass mode + if possible + 1 = Disallow LDO bypass mode +- qcom,init-voltage-floor-corner: Minimum performance corner to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-corner. +- qcom,init-voltage-level: Performance level to use in order to determine + voltage set point. The meaning of level + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different level values. These are + level values supported on MSM8952 for PMIC + PM8952 SMPS 2 (VDD_Dig); nominal voltages for + these level are also shown: + 16 = Retention (0.5000 V) + 128 = SVS (1.0500 V) + 192 = SVS+ (1.1550 V) + 256 = Normal (1.2250 V) + 320 = Normal+ (1.2875 V) + 384 = Turbo (1.3500 V) +- qcom,init-voltage-floor-level: Minimum performance level to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-level. + +All properties specified within the core regulator framework can also be used in +second level nodes. These bindings can be found in: +Documentation/devicetree/bindings/regulator/regulator.txt. + +Examples: + +rpm-regulator-smpb1 { + qcom,resource-name = "smpb"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + compatible = "qcom,rpm-smd-regulator-resource"; + status = "disabled"; + + pm8841_s1: regulator-s1 { + regulator-name = "8841_s1"; + qcom,set = <3>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + qcom,init-voltage = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_ao: regulator-s1-ao { + regulator-name = "8841_s1_ao"; + qcom,set = <1>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_corner: regulator-s1-corner { + regulator-name = "8841_s1_corner"; + qcom,set = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <6>; + qcom,init-voltage-corner = <3>; + qcom,use-voltage-corner; + compatible = "qcom,rpm-smd-regulator"; + }; +}; + +rpm-regulator-ldoa2 { + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + compatible = "qcom,rpm-smd-regulator-resource"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + }; + regulator-l2-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + qcom,enable-with-pin-ctrl = <0 1>; + }; +}; -- cgit v1.2.3 From 0db49c2550a09458db188fb7312c66783c5af104 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 2 May 2016 11:27:21 -0700 Subject: usb: gadget: mtp: Increase RX transfer length to 1M The test results indicate that larger transfers improve write speeds. The Rx request transfer length is now 16K bytes. Increase the Rx transfer length from 16K to 1MB to get good throughputs. Change-Id: I3c64e6b96d569b4dc61805a53a0835db9142d55e Signed-off-by: ChandanaKishori Chiluveru Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_mtp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 6b3ed12ede73..3b3b1b011407 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -42,6 +42,7 @@ #include "configfs.h" +#define MTP_RX_BUFFER_INIT_SIZE 1048576 #define MTP_BULK_BUFFER_SIZE 16384 #define INTR_BUFFER_SIZE 28 #define MAX_INST_NAME_LEN 40 @@ -77,7 +78,7 @@ #define MAX_ITERATION 100 -unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE; +unsigned int mtp_rx_req_len = MTP_RX_BUFFER_INIT_SIZE; module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR); unsigned int mtp_tx_req_len = MTP_BULK_BUFFER_SIZE; -- cgit v1.2.3 From b1e748622f9223bff4b53adc89b2eb127ae9dbc1 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 20 Apr 2016 08:34:16 -0700 Subject: diag: Add support for multi connection logging This change adds support to route On-Device logging and USB logging traffic per peripheral. A peripherals' traffic can go to either endpoint but not both. The mux layer has a peripheral state and the mode switching logic has multi mode support. CRs-Fixed: 1004236 Change-Id: I54fef744bdf08a346e4aef22c1280e928cdaf5d2 Signed-off-by: Chris Lew --- drivers/char/diag/diag_mux.c | 120 ++++++++++++--- drivers/char/diag/diag_mux.h | 15 +- drivers/char/diag/diagchar.h | 20 ++- drivers/char/diag/diagchar_core.c | 317 +++++++++++++++++++++----------------- drivers/char/diag/diagfwd.c | 24 +-- 5 files changed, 310 insertions(+), 186 deletions(-) diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index e016acf4e12e..6586f5e0cf86 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.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 @@ -23,11 +23,13 @@ #include #include #include "diagchar.h" +#include "diagfwd.h" #include "diag_mux.h" #include "diag_usb.h" #include "diag_memorydevice.h" -struct diag_logger_t *logger; + +struct diag_mux_state_t *diag_mux; static struct diag_logger_t usb_logger; static struct diag_logger_t md_logger; @@ -49,11 +51,11 @@ static struct diag_logger_ops md_log_ops = { int diag_mux_init() { - logger = kzalloc(NUM_MUX_PROC * sizeof(struct diag_logger_t), + diag_mux = kzalloc(sizeof(struct diag_mux_state_t), GFP_KERNEL); - if (!logger) + if (!diag_mux) return -ENOMEM; - kmemleak_not_leak(logger); + kmemleak_not_leak(diag_mux); usb_logger.mode = DIAG_USB_MODE; usb_logger.log_ops = &usb_log_ops; @@ -66,13 +68,17 @@ int diag_mux_init() * Set USB logging as the default logger. This is the mode * Diag should be in when it initializes. */ - logger = &usb_logger; + diag_mux->usb_ptr = &usb_logger; + diag_mux->md_ptr = &md_logger; + diag_mux->logger = &usb_logger; + diag_mux->mux_mask = 0; + diag_mux->mode = DIAG_USB_MODE; return 0; } void diag_mux_exit() { - kfree(logger); + kfree(diag_mux); } int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops) @@ -106,19 +112,43 @@ int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops) int diag_mux_queue_read(int proc) { + struct diag_logger_t *logger = NULL; + if (proc < 0 || proc >= NUM_MUX_PROC) return -EINVAL; - if (!logger) + if (!diag_mux) return -EIO; - if (logger->log_ops && logger->log_ops->queue_read) + + if (diag_mux->mode == DIAG_MULTI_MODE) + logger = diag_mux->usb_ptr; + else + logger = diag_mux->logger; + + if (logger && logger->log_ops && logger->log_ops->queue_read) return logger->log_ops->queue_read(proc); + return 0; } int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) { + struct diag_logger_t *logger = NULL; + int peripheral; + if (proc < 0 || proc >= NUM_MUX_PROC) return -EINVAL; + if (!diag_mux) + return -EIO; + + peripheral = GET_BUF_PERIPHERAL(ctx); + if (peripheral > NUM_PERIPHERALS) + return -EINVAL; + + if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask) + logger = diag_mux->md_ptr; + else + logger = diag_mux->usb_ptr; + if (logger && logger->log_ops && logger->log_ops->write) return logger->log_ops->write(proc, buf, len, ctx); return 0; @@ -126,38 +156,86 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx) int diag_mux_close_peripheral(int proc, uint8_t peripheral) { + struct diag_logger_t *logger = NULL; if (proc < 0 || proc >= NUM_MUX_PROC) return -EINVAL; /* Peripheral should account for Apps data as well */ if (peripheral > NUM_PERIPHERALS) return -EINVAL; + if (!diag_mux) + return -EIO; + + if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask) + logger = diag_mux->md_ptr; + else + logger = diag_mux->logger; + if (logger && logger->log_ops && logger->log_ops->close_peripheral) return logger->log_ops->close_peripheral(proc, peripheral); return 0; } -int diag_mux_switch_logging(int new_mode) +int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) { - struct diag_logger_t *new_logger = NULL; + unsigned int new_mask = 0; + + if (!req_mode) + return -EINVAL; - switch (new_mode) { + if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) { + pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__); + return -EINVAL; + } + + switch (*req_mode) { case DIAG_USB_MODE: - new_logger = &usb_logger; + new_mask = ~(*peripheral_mask) & diag_mux->mux_mask; + if (new_mask != DIAG_CON_NONE) + *req_mode = DIAG_MULTI_MODE; break; case DIAG_MEMORY_DEVICE_MODE: - new_logger = &md_logger; + new_mask = (*peripheral_mask) | diag_mux->mux_mask; + if (new_mask != DIAG_CON_ALL) + *req_mode = DIAG_MULTI_MODE; break; default: - pr_err("diag: Invalid mode %d in %s\n", new_mode, __func__); + pr_err("diag: Invalid mode %d in %s\n", *req_mode, __func__); return -EINVAL; } - if (logger) { - logger->log_ops->close(); - logger = new_logger; - logger->log_ops->open(); + switch (diag_mux->mode) { + case DIAG_USB_MODE: + if (*req_mode == DIAG_MEMORY_DEVICE_MODE) { + diag_mux->usb_ptr->log_ops->close(); + diag_mux->logger = diag_mux->md_ptr; + diag_mux->md_ptr->log_ops->open(); + } else if (*req_mode == DIAG_MULTI_MODE) { + diag_mux->md_ptr->log_ops->open(); + diag_mux->logger = NULL; + } + break; + case DIAG_MEMORY_DEVICE_MODE: + if (*req_mode == DIAG_USB_MODE) { + diag_mux->md_ptr->log_ops->close(); + diag_mux->logger = diag_mux->usb_ptr; + diag_mux->usb_ptr->log_ops->open(); + } else if (*req_mode == DIAG_MULTI_MODE) { + diag_mux->usb_ptr->log_ops->open(); + diag_mux->logger = NULL; + } + break; + case DIAG_MULTI_MODE: + if (*req_mode == DIAG_USB_MODE) { + diag_mux->md_ptr->log_ops->close(); + diag_mux->logger = diag_mux->usb_ptr; + } else if (*req_mode == DIAG_MEMORY_DEVICE_MODE) { + diag_mux->usb_ptr->log_ops->close(); + diag_mux->logger = diag_mux->md_ptr; + } + break; } - + diag_mux->mode = *req_mode; + diag_mux->mux_mask = new_mask; + *peripheral_mask = new_mask; return 0; } - diff --git a/drivers/char/diag/diag_mux.h b/drivers/char/diag/diag_mux.h index 97632d198494..e1fcebbe6fd1 100644 --- a/drivers/char/diag/diag_mux.h +++ b/drivers/char/diag/diag_mux.h @@ -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 @@ -13,6 +13,14 @@ #define DIAG_MUX_H #include "diagchar.h" +struct diag_mux_state_t { + struct diag_logger_t *logger; + struct diag_logger_t *usb_ptr; + struct diag_logger_t *md_ptr; + unsigned int mux_mask; + unsigned int mode; +}; + struct diag_mux_ops { int (*open)(int id, int mode); int (*close)(int id, int mode); @@ -24,6 +32,7 @@ struct diag_mux_ops { #define DIAG_USB_MODE 0 #define DIAG_MEMORY_DEVICE_MODE 1 #define DIAG_NO_LOGGING_MODE 2 +#define DIAG_MULTI_MODE 3 #define DIAG_MUX_LOCAL 0 #define DIAG_MUX_LOCAL_LAST 1 @@ -53,7 +62,7 @@ struct diag_logger_t { struct diag_logger_ops *log_ops; }; -extern struct diag_logger_t *logger; +extern struct diag_mux_state_t *diag_mux; int diag_mux_init(void); void diag_mux_exit(void); @@ -63,5 +72,5 @@ int diag_mux_write(int proc, unsigned char *buf, int len, int ctx); int diag_mux_close_peripheral(int proc, uint8_t peripheral); int diag_mux_open_all(struct diag_logger_t *logger); int diag_mux_close_all(void); -int diag_mux_switch_logging(int new_mode); +int diag_mux_switch_logging(int *new_mode, int *peripheral_mask); #endif diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index b021b99c6e9c..5d7b1e7fe757 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -59,11 +59,15 @@ #define DIAG_CTRL_MSG_F3_MASK 11 #define CONTROL_CHAR 0x7E -#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */ -#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */ -#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */ -#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */ -#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */ +#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */ +#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */ +#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */ +#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */ +#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */ +#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/ +#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \ + | DIAG_CON_LPASS | DIAG_CON_WCNSS \ + | DIAG_CON_SENSORS) #define DIAG_STM_MODEM 0x01 #define DIAG_STM_LPASS 0x02 @@ -158,8 +162,7 @@ #define FEATURE_MASK_LEN 2 #define DIAG_MD_NONE 0 -#define DIAG_MD_NORMAL 1 -#define DIAG_MD_PERIPHERAL 2 +#define DIAG_MD_PERIPHERAL 1 /* * The status bit masks when received in a signal handler are to be @@ -561,6 +564,7 @@ struct diagchar_dev { uint32_t dci_pkt_length; int in_busy_dcipktdata; int logging_mode; + int logging_mask; int mask_check; uint32_t md_session_mask; uint8_t md_session_mode; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index edc104acb777..ecdbf9f9480e 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -369,6 +369,24 @@ fail: return -ENOMEM; } +static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask) +{ + uint32_t ret = 0; + + if (peripheral_mask & MD_PERIPHERAL_MASK(APPS_DATA)) + ret |= DIAG_CON_APSS; + if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_MODEM)) + ret |= DIAG_CON_MPSS; + if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_LPASS)) + ret |= DIAG_CON_LPASS; + if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_WCNSS)) + ret |= DIAG_CON_WCNSS; + if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_SENSORS)) + ret |= DIAG_CON_SENSORS; + + return ret; +} + static void diag_close_logging_process(const int pid) { int i; @@ -388,7 +406,8 @@ static void diag_close_logging_process(const int pid) params.req_mode = USB_MODE; params.mode_param = 0; - params.peripheral_mask = 0; + params.peripheral_mask = + diag_translate_kernel_to_user_mask(session_peripheral_mask); mutex_lock(&driver->diagchar_mutex); diag_switch_logging(¶ms); mutex_unlock(&driver->diagchar_mutex); @@ -417,10 +436,11 @@ static int diag_remove_client_entry(struct file *file) diagpriv_data = file->private_data; - /* clean up any DCI registrations, if this is a DCI client - * This will specially help in case of ungraceful exit of any DCI client - * This call will remove any pending registrations of such client - */ + /* + * clean up any DCI registrations, if this is a DCI client + * This will specially help in case of ungraceful exit of any DCI client + * This call will remove any pending registrations of such client + */ mutex_lock(&driver->dci_mutex); dci_entry = dci_lookup_client_entry_pid(current->tgid); if (dci_entry) @@ -1148,19 +1168,10 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) struct diag_md_session_t *new_session = NULL; /* - * If there is any session running in Normal mode - * we cannot start a new session . If there is a - * session running in Peripheral mode we cannot - * start a new session in NORMAL mode. If a session is - * running with a peripheral mask and a new session - * request comes in with same peripheral mask value - * then return invalid param + * If a session is running with a peripheral mask and a new session + * request comes in with same peripheral mask value then return + * invalid param */ - if (driver->md_session_mode == DIAG_MD_NORMAL) - return -EINVAL; - if (driver->md_session_mode == DIAG_MD_PERIPHERAL - && mode == DIAG_MD_NORMAL) - return -EINVAL; if (driver->md_session_mode == DIAG_MD_PERIPHERAL && (driver->md_session_mask & peripheral_mask) != 0) return -EINVAL; @@ -1176,32 +1187,6 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) new_session->pid = current->tgid; new_session->task = current; - if (mode == DIAG_MD_NORMAL) { - new_session->log_mask = &log_mask; - new_session->event_mask = &event_mask; - new_session->msg_mask = &msg_mask; - for (i = 0; i < NUM_MD_SESSIONS; i++) { - if (driver->md_session_map[i] != NULL) { - DIAG_LOG(DIAG_DEBUG_USERSPACE, - "another instance present for %d\n", - i); - err = -EEXIST; - goto fail_normal; - } - new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i); - driver->md_session_mask |= MD_PERIPHERAL_MASK(i); - driver->md_session_map[i] = new_session; - } - driver->md_session_mode = DIAG_MD_NORMAL; - setup_timer(&new_session->hdlc_reset_timer, - diag_md_hdlc_reset_timer_func, - new_session->pid); - DIAG_LOG(DIAG_DEBUG_USERSPACE, - "created session in normal mode\n"); - mutex_unlock(&driver->md_session_lock); - return 0; - } - new_session->log_mask = kzalloc(sizeof(struct diag_mask_info), GFP_KERNEL); if (!new_session->log_mask) { @@ -1251,10 +1236,11 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) new_session->peripheral_mask |= MD_PERIPHERAL_MASK(i); driver->md_session_map[i] = new_session; driver->md_session_mask |= MD_PERIPHERAL_MASK(i); - setup_timer(&new_session->hdlc_reset_timer, - diag_md_hdlc_reset_timer_func, - new_session->pid); } + setup_timer(&new_session->hdlc_reset_timer, + diag_md_hdlc_reset_timer_func, + new_session->pid); + driver->md_session_mode = DIAG_MD_PERIPHERAL; mutex_unlock(&driver->md_session_lock); DIAG_LOG(DIAG_DEBUG_USERSPACE, @@ -1271,7 +1257,6 @@ fail_peripheral: diag_msg_mask_free(new_session->msg_mask); kfree(new_session->msg_mask); new_session->msg_mask = NULL; -fail_normal: kfree(new_session); new_session = NULL; mutex_unlock(&driver->md_session_lock); @@ -1292,19 +1277,17 @@ static void diag_md_session_close(struct diag_md_session_t *session_info) continue; driver->md_session_map[i] = NULL; driver->md_session_mask &= ~session_info->peripheral_mask; - if (driver->md_session_mode == DIAG_MD_NORMAL) - continue; - diag_log_mask_free(session_info->log_mask); - kfree(session_info->log_mask); - session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); - kfree(session_info->msg_mask); - session_info->msg_mask = NULL; - diag_event_mask_free(session_info->event_mask); - kfree(session_info->event_mask); - session_info->event_mask = NULL; - del_timer(&session_info->hdlc_reset_timer); } + diag_log_mask_free(session_info->log_mask); + kfree(session_info->log_mask); + session_info->log_mask = NULL; + diag_msg_mask_free(session_info->msg_mask); + kfree(session_info->msg_mask); + session_info->msg_mask = NULL; + diag_event_mask_free(session_info->event_mask); + kfree(session_info->event_mask); + session_info->event_mask = NULL; + del_timer(&session_info->hdlc_reset_timer); for (i = 0; i < NUM_MD_SESSIONS && !found; i++) { if (driver->md_session_map[i] != NULL) @@ -1337,113 +1320,157 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral) return driver->md_session_map[peripheral]; } +static int diag_md_peripheral_switch(struct diag_md_session_t *session_info, + int peripheral_mask, int req_mode) { + int i, bit = 0; + + if (!session_info) + return -EINVAL; + if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE) + return -EINVAL; + + /* + * check that md_session_map for i == session_info, + * if not then race condition occurred and bail + */ + mutex_lock(&driver->md_session_lock); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + bit = MD_PERIPHERAL_MASK(i) & peripheral_mask; + if (!bit) + continue; + if (req_mode == DIAG_USB_MODE) { + if (driver->md_session_map[i] != session_info) { + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + driver->md_session_map[i] = NULL; + driver->md_session_mask &= ~bit; + session_info->peripheral_mask &= ~bit; + + } else { + if (driver->md_session_map[i] != NULL) { + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + driver->md_session_map[i] = session_info; + driver->md_session_mask |= bit; + session_info->peripheral_mask |= bit; + + } + } + + driver->md_session_mode = DIAG_MD_PERIPHERAL; + mutex_unlock(&driver->md_session_lock); + DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n", + peripheral_mask, req_mode); +} + static int diag_md_session_check(int curr_mode, int req_mode, const struct diag_logging_mode_param_t *param, uint8_t *change_mode) { - int err = 0; + int i, bit = 0, err = 0; + int change_mask = 0; struct diag_md_session_t *session_info = NULL; if (!param || !change_mode) return -EIO; - *change_mode = 1; + *change_mode = 0; switch (curr_mode) { case DIAG_USB_MODE: case DIAG_MEMORY_DEVICE_MODE: + case DIAG_MULTI_MODE: break; default: return -EINVAL; } - switch (req_mode) { - case DIAG_USB_MODE: - case DIAG_MEMORY_DEVICE_MODE: - break; - default: + if (req_mode != DIAG_USB_MODE && req_mode != DIAG_MEMORY_DEVICE_MODE) return -EINVAL; - } - if (curr_mode == DIAG_USB_MODE) { - if (req_mode == DIAG_USB_MODE) { - /* - * This case tries to change from USB mode to USB mode. - * There is no change required. Return success. - */ - *change_mode = 0; + if (req_mode == DIAG_USB_MODE) { + if (curr_mode == DIAG_USB_MODE) + return 0; + if (driver->md_session_mode == DIAG_MD_NONE + && driver->md_session_mask == 0 && driver->logging_mask) { + *change_mode = 1; return 0; } /* - * If there is no other mdlog process, return success. - * Check if the peripheral interested in is active. + * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE + * Check if requested peripherals are already in usb mode */ - if (param->mode_param == DIAG_MD_NORMAL) { - err = diag_md_session_create(DIAG_MD_NORMAL, 0, - DIAG_LOCAL_PROC); - return err; - } else if (param->mode_param == DIAG_MD_PERIPHERAL && - (!(driver->md_session_mask & - param->peripheral_mask))) { - err = diag_md_session_create(DIAG_MD_PERIPHERAL, - param->peripheral_mask, - DIAG_LOCAL_PROC); - return err; + for (i = 0; i < NUM_MD_SESSIONS; i++) { + bit = MD_PERIPHERAL_MASK(i) & param->peripheral_mask; + if (!bit) + continue; + if (bit & driver->logging_mask) + change_mask |= bit; } - DIAG_LOG(DIAG_DEBUG_USERSPACE, - "an instance of mdlog is active\n"); - *change_mode = 0; - return -EINVAL; - } else if (curr_mode == DIAG_MEMORY_DEVICE_MODE) { - if (req_mode == DIAG_USB_MODE) { - if (driver->md_session_mask != 0 && - driver->md_session_mode == DIAG_MD_PERIPHERAL) { - /* - * An instance of mdlog is still running, Return - * error. - */ - DIAG_LOG(DIAG_DEBUG_USERSPACE, - "another instance running\n"); - *change_mode = 0; - return -EINVAL; - } - session_info = diag_md_session_get_pid(current->tgid); - diag_md_session_close(session_info); + if (!change_mask) return 0; - } - if (param->mode_param == DIAG_MD_NORMAL) { - /* - * The new client is asking for MD_NORMAL. We're - * already in memory device mode - this must be - * set by another active process. Return error - * for this new client. - */ + /* + * Change is needed. Check if this md_session has set all the + * requested peripherals. If another md session set a requested + * peripheral then we cannot switch that peripheral to USB. + * If this session owns all the requested peripherals, then + * call function to switch the modes/masks for the md_session + */ + session_info = diag_md_session_get_pid(current->tgid); + if (!session_info) { + *change_mode = 1; + return 0; + } + if ((change_mask & session_info->peripheral_mask) + != change_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, - "unable to switch logging mode\n"); - *change_mode = 0; + "Another MD Session owns a requested peripheral\n"); return -EINVAL; - } else if (param->mode_param == DIAG_MD_PERIPHERAL) { - if (driver->md_session_mask & param->peripheral_mask) { - /* - * The new client is asking for a - * specific peripheral. This case checks - * if a client is exercising this - * peripheral already. Return error - * if the peripheral is already in use. - */ + } + *change_mode = 1; + + /* If all peripherals are being set to USB Mode, call close */ + if (~change_mask & session_info->peripheral_mask) { + err = diag_md_peripheral_switch(session_info, + change_mask, DIAG_USB_MODE); + } else + diag_md_session_close(session_info); + + return err; + + } else if (req_mode == DIAG_MEMORY_DEVICE_MODE) { + /* + * Get bit mask that represents what peripherals already have + * been set. Check that requested peripherals already set are + * owned by this md session + */ + change_mask = driver->md_session_mask & param->peripheral_mask; + session_info = diag_md_session_get_pid(current->tgid); + + if (session_info) { + if ((session_info->peripheral_mask & change_mask) + != change_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "Another MD Session owns a requested peripheral\n"); + return -EINVAL; + } + err = diag_md_peripheral_switch(session_info, + change_mask, DIAG_USB_MODE); + } else { + if (change_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, - "another instance running\n"); - *change_mode = 0; + "Another MD Session owns a requested peripheral\n"); return -EINVAL; } err = diag_md_session_create(DIAG_MD_PERIPHERAL, - param->peripheral_mask, - DIAG_LOCAL_PROC); - *change_mode = 0; - return err; + param->peripheral_mask, DIAG_LOCAL_PROC); } + *change_mode = 1; + return err; } return -EINVAL; } @@ -1477,17 +1504,14 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) if (!param) return -EINVAL; - if (param->mode_param == DIAG_MD_PERIPHERAL && - param->peripheral_mask == 0) { + if (!param->peripheral_mask) { DIAG_LOG(DIAG_DEBUG_USERSPACE, - "asking for peripehral mode with no mask being set\n"); + "asking for mode switch with no peripheral mask set\n"); return -EINVAL; } - if (param->mode_param == DIAG_MD_PERIPHERAL) { - peripheral_mask = diag_translate_mask(param->peripheral_mask); - param->peripheral_mask = peripheral_mask; - } + peripheral_mask = diag_translate_mask(param->peripheral_mask); + param->peripheral_mask = peripheral_mask; switch (param->req_mode) { case CALLBACK_MODE: @@ -1507,8 +1531,8 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) curr_mode = driver->logging_mode; DIAG_LOG(DIAG_DEBUG_USERSPACE, - "request to switch logging from: %d to %d\n", - curr_mode, new_mode); + "request to switch logging from %d mask:%0x to %d mask:%0x\n", + curr_mode, driver->md_session_mask, new_mode, peripheral_mask); err = diag_md_session_check(curr_mode, new_mode, param, &do_switch); if (err) { @@ -1525,7 +1549,7 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) } diag_ws_reset(DIAG_WS_MUX); - err = diag_mux_switch_logging(new_mode); + err = diag_mux_switch_logging(&new_mode, &peripheral_mask); if (err) { pr_err("diag: In %s, unable to switch mode from %d to %d, err: %d\n", __func__, curr_mode, new_mode, err); @@ -1533,7 +1557,11 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) goto fail; } driver->logging_mode = new_mode; + driver->logging_mask = peripheral_mask; + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "Switch logging to %d mask:%0x\n", new_mode, peripheral_mask); + /* Update to take peripheral_mask */ if (new_mode != DIAG_MEMORY_DEVICE_MODE) { diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE, MODE_REALTIME, ALL_PROC); @@ -1839,10 +1867,8 @@ static int diag_ioctl_register_callback(unsigned long ioarg) return -EINVAL; } - if (driver->md_session_mode == DIAG_MD_NORMAL || - driver->md_session_mode == DIAG_MD_PERIPHERAL) { + if (driver->md_session_mode == DIAG_MD_PERIPHERAL) return -EIO; - } return err; } @@ -2737,7 +2763,8 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, mutex_lock(&driver->diagchar_mutex); if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && - (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE)) { + (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || + driver->logging_mode == DIAG_MULTI_MODE)) { pr_debug("diag: process woken up\n"); /*Copy the type of data being passed*/ data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE; diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index aa394f517163..aec4f965b13e 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -234,7 +234,7 @@ void chk_logging_wakeup(void) * index as all the indices point to the same session * structure. */ - if (driver->md_session_mode == DIAG_MD_NORMAL && j == 0) + if ((driver->md_session_mask == DIAG_CON_ALL) && (j == 0)) break; } } @@ -278,7 +278,8 @@ static void pack_rsp_and_send(unsigned char *buf, int len) * for responses. Make sure we don't miss previous wakeups for * draining responses when we are in Memory Device Mode. */ - if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) + if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || + driver->logging_mode == DIAG_MULTI_MODE) chk_logging_wakeup(); } if (driver->rsp_buf_busy) { @@ -346,7 +347,8 @@ static void encode_rsp_and_send(unsigned char *buf, int len) * for responses. Make sure we don't miss previous wakeups for * draining responses when we are in Memory Device Mode. */ - if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) + if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || + driver->logging_mode == DIAG_MULTI_MODE) chk_logging_wakeup(); } @@ -919,8 +921,13 @@ int diag_process_apps_pkt(unsigned char *buf, int len, if (MD_PERIPHERAL_MASK(reg_item->proc) & info->peripheral_mask) write_len = diag_send_data(reg_item, buf, len); - } else - write_len = diag_send_data(reg_item, buf, len); + } else { + if (MD_PERIPHERAL_MASK(reg_item->proc) & + driver->logging_mask) + diag_send_error_rsp(buf, len); + else + write_len = diag_send_data(reg_item, buf, len); + } mutex_unlock(&driver->cmd_reg_mutex); return write_len; } @@ -1228,10 +1235,9 @@ static int diagfwd_mux_close(int id, int mode) return -EINVAL; } - if ((mode == DIAG_USB_MODE && - driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) || - (mode == DIAG_MEMORY_DEVICE_MODE && - driver->logging_mode == DIAG_USB_MODE)) { + if ((driver->logging_mode == DIAG_MULTI_MODE && + driver->md_session_mode == DIAG_MD_NONE) || + (driver->md_session_mode == DIAG_MD_PERIPHERAL)) { /* * In this case the channel must not be closed. This case * indicates that the USB is removed but there is a client -- cgit v1.2.3 From 8a2e028a6da46dc27534344ef58459b83ab0225e Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Mon, 14 Apr 2014 19:42:04 -0700 Subject: arm: Allow remapping lowmem as 4K pages Lowmem is currently mapped with sections (1MB/2MB) whenever possible due to TLB performance boosts. Sections cannot easily be changed at runtime however which makes implementing certain features annoying. Add an option to map lowmem with 4K patches. This is intended to be used as a debugging feature and should NOT be used for performance testing. Change-Id: I9612a99b8e05a022f5ba7e568f21307cf66b5667 Signed-off-by: Laura Abbott Signed-off-by: Susheel Khiani --- arch/arm/Kconfig.debug | 11 ++++++ arch/arm/mm/mmu.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/pageattr.c | 11 +++--- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 71afa854e1c4..b87d5d924238 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -76,6 +76,17 @@ config DEBUG_USER 8 - SIGSEGV faults 16 - SIGBUS faults +config FORCE_PAGES + bool "Force lowmem to be mapped with 4K pages" + help + There are some advanced debug features that can only be done when + memory is mapped with pages instead of sections. Enable this option + to always map lowmem pages with pages. This may have a performance + cost due to increased TLB pressure. + + If unsure say N. + + # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL bool "Kernel low-level debugging functions (read help!)" diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9ab506ebff59..be812c734296 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1574,6 +1574,100 @@ void __init early_paging_init(const struct machine_desc *mdesc) #endif +#ifdef CONFIG_FORCE_PAGES +/* + * remap a PMD into pages + * We split a single pmd here none of this two pmd nonsense + */ +static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn, + const struct mem_type *type) +{ + pte_t *pte, *start_pte; + + start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); + + pte = start_pte; + + do { + set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); + + *pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1); + mb(); /* let pmd be programmed */ + flush_pmd_entry(pmd); + flush_tlb_all(); +} + +/* + * It's significantly easier to remap as pages later after all memory is + * mapped. Everything is sections so all we have to do is split + */ +static void __init remap_pages(void) +{ + struct memblock_region *reg; + + for_each_memblock(memory, reg) { + phys_addr_t phys_start = reg->base; + phys_addr_t phys_end = reg->base + reg->size; + unsigned long addr = (unsigned long)__va(phys_start); + unsigned long end = (unsigned long)__va(phys_end); + pmd_t *pmd = NULL; + unsigned long next; + unsigned long pfn = __phys_to_pfn(phys_start); + bool fixup = false; + unsigned long saved_start = addr; + + if (phys_end > arm_lowmem_limit) + end = (unsigned long)__va(arm_lowmem_limit); + if (phys_start >= phys_end) + break; + + pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + +#ifndef CONFIG_ARM_LPAE + if (addr & SECTION_SIZE) { + fixup = true; + pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK); + pmd++; + } + + if (end & SECTION_SIZE) + pmd_empty_section_gap(end); +#endif + + do { + next = addr + SECTION_SIZE; + + if (pmd_none(*pmd) || pmd_bad(*pmd)) + split_pmd(pmd, addr, next, pfn, + &mem_types[MT_MEMORY_RWX]); + pmd++; + pfn += SECTION_SIZE >> PAGE_SHIFT; + + } while (addr = next, addr < end); + + if (fixup) { + /* + * Put a faulting page table here to avoid detecting no + * pmd when accessing an odd section boundary. This + * needs to be faulting to help catch errors and avoid + * speculation + */ + pmd = pmd_off_k(saved_start); + pmd[0] = pmd[1] & ~1; + } + } +} +#else +static void __init remap_pages(void) +{ + +} +#endif + static void __init early_fixmap_shutdown(void) { int i; @@ -1617,6 +1711,7 @@ void __init paging_init(const struct machine_desc *mdesc) memblock_set_current_limit(arm_lowmem_limit); dma_contiguous_remap(); early_fixmap_shutdown(); + remap_pages(); devicemaps_init(mdesc); kmap_init(); tcm_init(); diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c index cf30daff8932..ad5d4bfa5de6 100644 --- a/arch/arm/mm/pageattr.c +++ b/arch/arm/mm/pageattr.c @@ -49,11 +49,14 @@ static int change_memory_common(unsigned long addr, int numpages, WARN_ON_ONCE(1); } - if (start < MODULES_VADDR || start >= MODULES_END) - return -EINVAL; + if (!IS_ENABLED(CONFIG_FORCE_PAGES)) { - if (end < MODULES_VADDR || start >= MODULES_END) - return -EINVAL; + if (start < MODULES_VADDR || start >= MODULES_END) + return -EINVAL; + + if (end < MODULES_VADDR || start >= MODULES_END) + return -EINVAL; + } data.set_mask = set_mask; data.clear_mask = clear_mask; -- cgit v1.2.3 From 3b2670ae0cea55e759f6d35148c58623df117229 Mon Sep 17 00:00:00 2001 From: Susheel Khiani Date: Fri, 4 Sep 2015 15:24:58 +0530 Subject: Kconfig: Add menu choice option to reclaim virtual memory Add menu choice options for reclaiming virtual memory belonging to any subsystem expected to have a lifetime of the entire system. By default virtual memory is not reclaimed. Change-Id: I1b8a1492062bb9532700122878618989e5148647 Signed-off-by: Neeti Desai Signed-off-by: Susheel Khiani --- arch/arm/Kconfig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6b09a67c9a0d..863f2cd9096a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1768,6 +1768,29 @@ config ARM_MODULE_PLTS source "mm/Kconfig" +choice + prompt "Virtual Memory Reclaim" + default NO_VM_RECLAIM + help + Select the method of reclaiming virtual memory + +config ENABLE_VMALLOC_SAVING + bool "Reclaim memory for each subsystem" + help + Enable this config to reclaim the virtual space belonging + to any subsystem which is expected to have a lifetime of + the entire system. This feature allows lowmem to be non- + contiguous. + +config NO_VM_RECLAIM + bool "Do not reclaim memory" + help + Do not reclaim any memory. This might result in less lowmem + and wasting virtual memory space which could otherwise be + reclaimed by using any of the other two config options. + +endchoice + config FORCE_MAX_ZONEORDER int "Maximum zone order" default "12" if SOC_AM33XX -- cgit v1.2.3 From 14c44670eaf9d8b0e0b34dcbc3ea96919eae9262 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 21 May 2014 09:35:08 +0530 Subject: arm: mm: fix pte allocation with CONFIG_FORCE_PAGES feature CONFIG_FORCE_PAGES introduces a debug option to mark free pages as read only in order to trigger a fault if any code attempts to write to a page on the buddy list. In order to achieve this it splits all section mappings in to PAGE_SIZE pages during boot. While doing this split, it wrongly allocates a pte (of page size) for each pmd. Linux however in armv7 short descriptor format, uses same second level pte for 2 consecutive pmds offset by the actual second level table size. Refer comments in kernel file arch/arm/include/asm/pgtable-2level.h for details. Fix this by allocating pte for a section mapped pmd while providing required offset if pte already exists. Change-Id: Iadbaa5e71e4b220208a7275bf039a2a413349e42 Signed-off-by: Shiraz Hashim --- arch/arm/mm/mmu.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index be812c734296..74457c13db72 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1584,8 +1584,25 @@ static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr, const struct mem_type *type) { pte_t *pte, *start_pte; + pmd_t *base_pmd; - start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); + base_pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + + if (pmd_none(*base_pmd) || pmd_bad(*base_pmd)) { + start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); +#ifndef CONFIG_ARM_LPAE + /* + * Following is needed when new pte is allocated for pmd[1] + * cases, which may happen when base (start) address falls + * under pmd[1]. + */ + if (addr & SECTION_SIZE) + start_pte += pte_index(addr); +#endif + } else { + start_pte = pte_offset_kernel(base_pmd, addr); + } pte = start_pte; -- cgit v1.2.3 From 24edbd9fd473502abe34f7c14f138a3f1bc0d65f Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Tue, 30 Jun 2015 09:14:46 +0530 Subject: arm: mm: consider only lowmem regions while remap Consider only those memory blocks with lowmem while remapping into 4KB regions using CONFIG_FORCE_PAGES feature. Change-Id: Ie209fce6c310f911d8cf02d977e226660684a6ab Signed-off-by: Shiraz Hashim --- arch/arm/mm/mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 74457c13db72..14bb5ac67588 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1636,6 +1636,8 @@ static void __init remap_pages(void) bool fixup = false; unsigned long saved_start = addr; + if (phys_start > arm_lowmem_limit) + break; if (phys_end > arm_lowmem_limit) end = (unsigned long)__va(arm_lowmem_limit); if (phys_start >= phys_end) -- cgit v1.2.3 From 2e9944e96294b9ad2115020150129fcf680da085 Mon Sep 17 00:00:00 2001 From: Osvaldo Banuelos Date: Mon, 18 Apr 2016 16:28:08 -0700 Subject: clk: msm: osm: add panic handler to dump status registers Add a panic handler to dump the OS performance state, program counter OSM watchdog registers, and the APM status register when the device crashes due to a kernel panic. These are critical registers that are useful for debug. CRs-Fixed: 1033031 Change-Id: I2bbf6884cf83457bfb7e5369bb97614bd4beb150 Signed-off-by: Osvaldo Banuelos --- drivers/clk/msm/clock-osm.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 9e9368b197d8..598e52b54c99 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -105,6 +105,9 @@ enum clk_osm_trace_packet_id { #define OSM_CORE_TABLE_SIZE 8192 #define OSM_REG_SIZE 32 +#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00 +#define WDOG_PROGRAM_COUNTER 0x1c74 + #define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8) #define PLL_MODE 0x0 #define PLL_L_VAL 0x4 @@ -323,6 +326,7 @@ struct clk_osm { enum clk_osm_trace_method trace_method; enum clk_osm_trace_packet_id trace_id; + struct notifier_block panic_notifier; u32 trace_periodic_timer; bool trace_en; }; @@ -2248,6 +2252,45 @@ exit: debugfs_remove_recursive(c->debugfs); } +static int clk_osm_panic_callback(struct notifier_block *nfb, + unsigned long event, + void *data) +{ + void __iomem *virt_addr; + u32 value, reg; + struct clk_osm *c = container_of(nfb, + struct clk_osm, + panic_notifier); + + reg = c->pbases[OSM_BASE] + WDOG_DOMAIN_PSTATE_STATUS; + virt_addr = ioremap(reg, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("DOM%d_PSTATE_STATUS[0x%08x]=0x%08x\n", c->cluster_num, + reg, value); + iounmap(virt_addr); + } + + reg = c->pbases[OSM_BASE] + WDOG_PROGRAM_COUNTER; + virt_addr = ioremap(reg, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("DOM%d_PROGRAM_COUNTER[0x%08x]=0x%08x\n", c->cluster_num, + reg, value); + iounmap(virt_addr); + } + + virt_addr = ioremap(c->apm_ctrl_status, 0x4); + if (virt_addr != NULL) { + value = readl_relaxed(virt_addr); + pr_err("APM_CTLER_STATUS_%d[0x%08x]=0x%08x\n", c->cluster_num, + c->apm_ctrl_status, value); + iounmap(virt_addr); + } + + return NOTIFY_OK; +} + static unsigned long init_rate = 300000000; static unsigned long osm_clk_init_rate = 200000000; @@ -2393,6 +2436,13 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) spin_lock_init(&pwrcl_clk.lock); spin_lock_init(&perfcl_clk.lock); + pwrcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback; + atomic_notifier_chain_register(&panic_notifier_list, + &pwrcl_clk.panic_notifier); + perfcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback; + atomic_notifier_chain_register(&panic_notifier_list, + &perfcl_clk.panic_notifier); + rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm, ARRAY_SIZE(cpu_clocks_osm)); if (rc) { -- cgit v1.2.3 From fb5706b7462b0b855d10da12ed88ebf10a2e8643 Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Mon, 6 Jul 2015 18:20:22 -0700 Subject: cfg80211: Bypass checkin the CHAN_RADAR if DFS_OFFLOAD is enabled When WIPHY_FLAG_DFS_OFFLOAD is defined, driver would take care the DFS related operation, hence the Kernel needs to ignore the DFS states checking. CRs-fixed:1032889 Change-Id: I02fa5e3e25427c0ca474455fa2d2be9eb6ea4bd9 Signed-off-by: Ryan Hsu --- net/wireless/chan.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index aaa590c0b491..cf14c7e22fb3 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -593,10 +593,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, for (freq = start_freq; freq <= end_freq; freq += 20) { c = ieee80211_get_channel(wiphy, freq); - if (!c || c->flags & prohibited_flags) + + if (!c) + return false; + + if ((!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD)) && + (c->flags & prohibited_flags & IEEE80211_CHAN_RADAR)) return false; - } + if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) + return false; + } return true; } -- cgit v1.2.3