diff options
234 files changed, 3010 insertions, 834 deletions
@@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 71 +SUBLEVEL = 72 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts index fee184663336..9f8d432a3112 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts @@ -46,6 +46,14 @@ status = "disabled"; }; }; + + qcom,adv7481@70 { + status = "disabled"; + }; + + qcom,msm-ba { + status = "disabled"; + }; }; &dsi_adv_7533_2 { diff --git a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts index 022841b5e769..bd29c0307576 100644 --- a/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts @@ -90,6 +90,7 @@ &snd_9335 { qcom,msm-mi2s-master = <1>, <1>, <1>, <0>; + qcom,msm-mbhc-hphl-swh = <1>; }; &wcd_usbc_analog_en1_gpio { diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi index da28e56bc2df..e4e488597efd 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi @@ -155,6 +155,7 @@ interrupts = <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 331 IRQ_TYPE_EDGE_RISING>; + qcom,deferred-regulator-disable-delay = <80>; vdd-supply = <&gdsc_gpu_cx>; clocks = <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>, <&clock_gcc clk_gcc_bimc_gfx_clk>, diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 3c9b8e445ff3..4bcf64185038 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -542,6 +542,7 @@ &mdss_hdmi_cec_active>; pinctrl-4 = <&mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; + /delete-property/ qcom,pluggable; }; #include "msm8996-sde-display.dtsi" diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 7c3f035a841b..80b3437beac6 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -1064,6 +1064,7 @@ qcom,pm-qos-irq-cpu = <0>; qcom,pm-qos-irq-latency = <70 70>; + non-removable; status = "disabled"; }; @@ -1268,6 +1269,7 @@ qcom,pm-qos-cpu-group-latency-us = <70 70>; qcom,pm-qos-default-cpu = <0>; + non-removable; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts index 1cf61486c9e8..48d5cb78611b 100644 --- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts +++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts @@ -46,6 +46,14 @@ status = "disabled"; }; }; + + qcom,adv7481@70 { + status = "disabled"; + }; + + qcom,msm-ba { + status = "disabled"; + }; }; &pil_modem { diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts index 55255261a827..ce1c62d9c2ae 100644 --- a/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts +++ b/arch/arm/boot/dts/qcom/msm8998-qrd-overlay.dts @@ -17,6 +17,7 @@ #include <dt-bindings/clock/msm-clocks-8998.h> #include <dt-bindings/interrupt-controller/irq.h> +#include "msm8998-mdss-panels.dtsi" #include "msm8998-qrd.dtsi" / { diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index fc546512992d..3f8962de22be 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3063,8 +3063,8 @@ qcom,msm-core@780000 { compatible = "qcom,apss-core-ea"; reg = <0x780000 0x1000>; - qcom,low-hyst-temp = <10>; - qcom,high-hyst-temp = <5>; + qcom,low-hyst-temp = <100>; + qcom,high-hyst-temp = <100>; qcom,polling-interval = <50>; ea0: ea0 { diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts index 227a8999a745..4c4c758daa29 100644 --- a/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda630-pm660a-qrd-hdk.dts @@ -60,6 +60,19 @@ /delete-node/ &tasha_hph_en0; /delete-node/ &tasha_hph_en1; +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; + &tasha_snd { qcom,model = "sdm660-tasha-skus-snd-card"; qcom,audio-routing = diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts index 7fb0c9d03825..604823ff416e 100644 --- a/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts +++ b/arch/arm/boot/dts/qcom/sda660-pm660a-qrd-hdk.dts @@ -218,4 +218,14 @@ <0x00188018 0x4>; reg-names = "qusb_phy_base", "ref_clk_addr"; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 09528da7ca09..56a6d5105568 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -811,8 +811,8 @@ qcom,msm-core@780000 { compatible = "qcom,apss-core-ea"; reg = <0x780000 0x1000>; - qcom,low-hyst-temp = <10>; - qcom,high-hyst-temp = <5>; + qcom,low-hyst-temp = <100>; + qcom,high-hyst-temp = <100>; ea0: ea0 { sensor = <&sensor_information3>; diff --git a/arch/arm/boot/dts/qcom/sdm660-pm.dtsi b/arch/arm/boot/dts/qcom/sdm660-pm.dtsi index 21fab4923331..cdf1e47665fb 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-pm.dtsi @@ -39,7 +39,7 @@ qcom,vctl-timeout-us = <500>; qcom,vctl-port = <0x0>; qcom,phase-port = <0x1>; - qcom,saw2-avs-ctl = <0x1010031>; + qcom,saw2-avs-ctl = <0x101c031>; qcom,saw2-avs-limit = <0x4580458>; qcom,pfm-port = <0x2>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi index 66bea3050586..a4111f6d1b94 100644 --- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi @@ -744,8 +744,8 @@ < (-4000) 4000 7000 19000 (-8000)>; qcom,cpr-closed-loop-voltage-fuse-adjustment = - <(-32000) (-30000) (-29000) (-23000) - (-21000)>; + <(-32000) (-30000) (-29000) (-38000) + (-36000)>; qcom,cpr-floor-to-ceiling-max-range = <32000 32000 32000 40000 44000 diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 0a0350cb8c2b..207cc57e8e49 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -865,8 +865,8 @@ qcom,msm-core@780000 { compatible = "qcom,apss-core-ea"; reg = <0x780000 0x1000>; - qcom,low-hyst-temp = <10>; - qcom,high-hyst-temp = <5>; + qcom,low-hyst-temp = <100>; + qcom,high-hyst-temp = <100>; ea0: ea0 { sensor = <&sensor_information1>; @@ -1232,9 +1232,17 @@ compatible = "qcom,clk-cpu-osm"; reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, <0x17816000 0x1000>, <0x179d1000 0x1000>, - <0x00784130 0x8>; + <0x00784130 0x8>, <0x17914800 0x800>; reg-names = "osm", "pwrcl_pll", "perfcl_pll", - "apcs_common", "perfcl_efuse"; + "apcs_common", "perfcl_efuse", + "pwrcl_acd"; + + qcom,acdtd-val = <0x0000a111 0x0000a111>; + qcom,acdcr-val = <0x002c5ffd 0x002c5ffd>; + qcom,acdsscr-val = <0x00000901 0x00000901>; + qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>; + qcom,acdextint1-val = <0x2cf9afe 0x2cf9afe>; + qcom,acdautoxfer-val = <0x00000015 0x00000015>; vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; vdd-perfcl-supply = <&apc1_perfcl_vreg>; diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 5964c77c593d..a1898c6092d1 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -175,6 +175,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { __save_stack_trace(tsk, trace, 1); } +EXPORT_SYMBOL(save_stack_trace_tsk); void save_stack_trace(struct stack_trace *trace) { diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S index 3988e72d16ff..bfc5aae0c280 100644 --- a/arch/arm/kvm/init.S +++ b/arch/arm/kvm/init.S @@ -110,7 +110,6 @@ __do_hyp_init: @ - Write permission implies XN: disabled @ - Instruction cache: enabled @ - Data/Unified cache: enabled - @ - Memory alignment checks: enabled @ - MMU: enabled (this code must be run from an identity mapping) mrc p15, 4, r0, c1, c0, 0 @ HSCR ldr r2, =HSCTLR_MASK @@ -118,8 +117,8 @@ __do_hyp_init: mrc p15, 0, r1, c1, c0, 0 @ SCTLR ldr r2, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C) and r1, r1, r2 - ARM( ldr r2, =(HSCTLR_M | HSCTLR_A) ) - THUMB( ldr r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) ) + ARM( ldr r2, =(HSCTLR_M) ) + THUMB( ldr r2, =(HSCTLR_M | HSCTLR_TE) ) orr r1, r1, r2 orr r0, r0, r1 isb diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 33ee522bb76f..e4a774f7aba1 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -876,6 +876,9 @@ static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache pmd_t *pmd; pud = stage2_get_pud(kvm, cache, addr); + if (!pud) + return NULL; + if (pud_none(*pud)) { if (!cache) return NULL; diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig index 6d6fd23095d5..b6cb1a4b8574 100644 --- a/arch/arm64/configs/sdm660-perf_defconfig +++ b/arch/arm64/configs/sdm660-perf_defconfig @@ -310,6 +310,7 @@ CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS_MSM_NGD=y diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig index 25566e45c46f..ccef87ff6a04 100644 --- a/arch/arm64/configs/sdm660_defconfig +++ b/arch/arm64/configs/sdm660_defconfig @@ -319,6 +319,7 @@ CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS_MSM_NGD=y diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h new file mode 100644 index 000000000000..be2d2347d995 --- /dev/null +++ b/arch/arm64/include/asm/asm-uaccess.h @@ -0,0 +1,13 @@ +#ifndef __ASM_ASM_UACCESS_H +#define __ASM_ASM_UACCESS_H + +/* + * Remove the address tag from a virtual address, if present. + */ + .macro clear_address_tag, dst, addr + tst \addr, #(1 << 55) + bic \dst, \addr, #(0xff << 56) + csel \dst, \dst, \addr, eq + .endm + +#endif diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index c5dbc5cb8f10..0671711b46ab 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -44,23 +44,33 @@ #define smp_store_release(p, v) \ do { \ + union { typeof(*p) __val; char __c[1]; } __u = \ + { .__val = (__force typeof(*p)) (v) }; \ compiletime_assert_atomic_type(*p); \ switch (sizeof(*p)) { \ case 1: \ asm volatile ("stlrb %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u8 *)__u.__c) \ + : "memory"); \ break; \ case 2: \ asm volatile ("stlrh %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u16 *)__u.__c) \ + : "memory"); \ break; \ case 4: \ asm volatile ("stlr %w1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u32 *)__u.__c) \ + : "memory"); \ break; \ case 8: \ asm volatile ("stlr %1, %0" \ - : "=Q" (*p) : "r" (v) : "memory"); \ + : "=Q" (*p) \ + : "r" (*(__u64 *)__u.__c) \ + : "memory"); \ break; \ } \ } while (0) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index ac177d96e773..064cef9ae2d1 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -27,6 +27,7 @@ /* * User space memory access functions */ +#include <linux/bitops.h> #include <linux/string.h> #include <linux/thread_info.h> @@ -119,6 +120,13 @@ static inline void set_fs(mm_segment_t fs) flag; \ }) +/* + * When dealing with data aborts, watchpoints, or instruction traps we may end + * up with a tagged userland pointer. Clear the tag to get a sane pointer to + * pass on to access_ok(), for instance. + */ +#define untagged_addr(addr) sign_extend64(addr, 55) + #define access_ok(type, addr, size) __range_ok(addr, size) #define user_addr_max get_fs diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 884b317e56c3..10d3642deb7c 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -299,7 +299,8 @@ do { \ _ASM_EXTABLE(0b, 4b) \ _ASM_EXTABLE(1b, 4b) \ : "=&r" (res), "+r" (data), "=&r" (temp) \ - : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "r" ((unsigned long)addr), "i" (-EAGAIN), \ + "i" (-EFAULT) \ : "memory"); \ uaccess_disable(); \ } while (0) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 0ea65307f866..7822e36d87fb 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -32,6 +32,7 @@ #include <asm/ptrace.h> #include <asm/thread_info.h> #include <asm/uaccess.h> +#include <asm/asm-uaccess.h> #include <asm/unistd.h> /* @@ -437,12 +438,13 @@ el1_da: /* * Data abort handling */ - mrs x0, far_el1 + mrs x3, far_el1 enable_dbg // re-enable interrupts if they were enabled in the aborted context tbnz x23, #7, 1f // PSR_I_BIT enable_irq 1: + clear_address_tag x0, x3 mov x2, sp // struct pt_regs bl do_mem_abort @@ -604,7 +606,7 @@ el0_da: // enable interrupts before calling the main handler enable_dbg_and_irq ct_user_exit - bic x0, x26, #(0xff << 56) + clear_address_tag x0, x26 mov x1, x25 mov x2, sp bl do_mem_abort diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index f4dfd8c41e06..1c694f3c643c 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -36,6 +36,7 @@ #include <asm/traps.h> #include <asm/cputype.h> #include <asm/system_misc.h> +#include <asm/uaccess.h> /* Breakpoint currently in use for each BRP. */ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index cb3eec8e8e50..1fd1a9a6596f 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -184,6 +184,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; } +EXPORT_SYMBOL(save_stack_trace_tsk); void save_stack_trace(struct stack_trace *trace) { diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 8b3b46b7b0f2..329771559cbb 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -44,8 +44,22 @@ extern void __init dump_numa_cpu_topology(void); extern int sysfs_add_device_to_node(struct device *dev, int nid); extern void sysfs_remove_device_from_node(struct device *dev, int nid); +static inline int early_cpu_to_node(int cpu) +{ + int nid; + + nid = numa_cpu_lookup_table[cpu]; + + /* + * Fall back to node 0 if nid is unset (it should be, except bugs). + * This allows callers to safely do NODE_DATA(early_cpu_to_node(cpu)). + */ + return (nid < 0) ? 0 : nid; +} #else +static inline int early_cpu_to_node(int cpu) { return 0; } + static inline void dump_numa_cpu_topology(void) {} static inline int sysfs_add_device_to_node(struct device *dev, int nid) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index c314db8b798c..9837c98caabe 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -655,7 +655,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) */ #define MAX_WAIT_FOR_RECOVERY 300 -static void eeh_handle_normal_event(struct eeh_pe *pe) +static bool eeh_handle_normal_event(struct eeh_pe *pe) { struct pci_bus *frozen_bus; int rc = 0; @@ -665,7 +665,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) if (!frozen_bus) { pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n", __func__, pe->phb->global_number, pe->addr); - return; + return false; } eeh_pe_update_time_stamp(pe); @@ -790,7 +790,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe) pr_info("EEH: Notify device driver to resume\n"); eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); - return; + return false; excess_failures: /* @@ -831,7 +831,11 @@ perm_error: pci_lock_rescan_remove(); pcibios_remove_pci_devices(frozen_bus); pci_unlock_rescan_remove(); + + /* The passed PE should no longer be used */ + return true; } + return false; } static void eeh_handle_special_event(void) @@ -897,7 +901,14 @@ static void eeh_handle_special_event(void) */ if (rc == EEH_NEXT_ERR_FROZEN_PE || rc == EEH_NEXT_ERR_FENCED_PHB) { - eeh_handle_normal_event(pe); + /* + * eeh_handle_normal_event() can make the PE stale if it + * determines that the PE cannot possibly be recovered. + * Don't modify the PE state if that's the case. + */ + if (eeh_handle_normal_event(pe)) + continue; + eeh_pe_state_clear(pe, EEH_PE_RECOVERING); } else { pci_lock_rescan_remove(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index a20823210ac0..fe6e800c1357 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -751,7 +751,7 @@ void __init setup_arch(char **cmdline_p) static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align) { - return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align, + return __alloc_bootmem_node(NODE_DATA(early_cpu_to_node(cpu)), size, align, __pa(MAX_DMA_ADDRESS)); } @@ -762,7 +762,7 @@ static void __init pcpu_fc_free(void *ptr, size_t size) static int pcpu_cpu_distance(unsigned int from, unsigned int to) { - if (cpu_to_node(from) == cpu_to_node(to)) + if (early_cpu_to_node(from) == early_cpu_to_node(to)) return LOCAL_DISTANCE; else return REMOTE_DISTANCE; diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index e9ff44cd5d86..e8b1027e1b5b 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -110,6 +110,7 @@ static struct property *dlpar_clone_drconf_property(struct device_node *dn) for (i = 0; i < num_lmbs; i++) { lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr); lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index); + lmbs[i].aa_index = be32_to_cpu(lmbs[i].aa_index); lmbs[i].flags = be32_to_cpu(lmbs[i].flags); } @@ -553,6 +554,7 @@ static void dlpar_update_drconf_property(struct device_node *dn, for (i = 0; i < num_lmbs; i++) { lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr); lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index); + lmbs[i].aa_index = cpu_to_be32(lmbs[i].aa_index); lmbs[i].flags = cpu_to_be32(lmbs[i].flags); } diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 3736be630113..894bcaed002e 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -183,9 +183,9 @@ config NR_CPUS int "Maximum number of CPUs" depends on SMP range 2 32 if SPARC32 - range 2 1024 if SPARC64 + range 2 4096 if SPARC64 default 32 if SPARC32 - default 64 if SPARC64 + default 4096 if SPARC64 source kernel/Kconfig.hz diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h index f7de0dbc38af..83b36a5371ff 100644 --- a/arch/sparc/include/asm/mmu_64.h +++ b/arch/sparc/include/asm/mmu_64.h @@ -52,7 +52,7 @@ #define CTX_NR_MASK TAG_CONTEXT_BITS #define CTX_HW_MASK (CTX_NR_MASK | CTX_PGSZ_MASK) -#define CTX_FIRST_VERSION ((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL)) +#define CTX_FIRST_VERSION BIT(CTX_VERSION_SHIFT) #define CTX_VALID(__ctx) \ (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK)) #define CTX_HWBITS(__ctx) ((__ctx.sparc64_ctx_val) & CTX_HW_MASK) diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index b84be675e507..349dd23e2876 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -17,13 +17,8 @@ extern spinlock_t ctx_alloc_lock; extern unsigned long tlb_context_cache; extern unsigned long mmu_context_bmap[]; +DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm); void get_new_mmu_context(struct mm_struct *mm); -#ifdef CONFIG_SMP -void smp_new_mmu_context_version(void); -#else -#define smp_new_mmu_context_version() do { } while (0) -#endif - int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); @@ -74,8 +69,9 @@ void __flush_tlb_mm(unsigned long, unsigned long); static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { unsigned long ctx_valid, flags; - int cpu; + int cpu = smp_processor_id(); + per_cpu(per_cpu_secondary_mm, cpu) = mm; if (unlikely(mm == &init_mm)) return; @@ -121,7 +117,6 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str * for the first time, we must flush that context out of the * local TLB. */ - cpu = smp_processor_id(); if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) { cpumask_set_cpu(cpu, mm_cpumask(mm)); __flush_tlb_mm(CTX_HWBITS(mm->context), @@ -131,26 +126,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str } #define deactivate_mm(tsk,mm) do { } while (0) - -/* Activate a new MM instance for the current task. */ -static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) -{ - unsigned long flags; - int cpu; - - spin_lock_irqsave(&mm->context.lock, flags); - if (!CTX_VALID(mm->context)) - get_new_mmu_context(mm); - cpu = smp_processor_id(); - if (!cpumask_test_cpu(cpu, mm_cpumask(mm))) - cpumask_set_cpu(cpu, mm_cpumask(mm)); - - load_secondary_context(mm); - __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); - tsb_context_switch(mm); - spin_unlock_irqrestore(&mm->context.lock, flags); -} - +#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL) #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_MMU_CONTEXT_H) */ diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h index 266937030546..522b43db2ed3 100644 --- a/arch/sparc/include/asm/pil.h +++ b/arch/sparc/include/asm/pil.h @@ -20,7 +20,6 @@ #define PIL_SMP_CALL_FUNC 1 #define PIL_SMP_RECEIVE_SIGNAL 2 #define PIL_SMP_CAPTURE 3 -#define PIL_SMP_CTX_NEW_VERSION 4 #define PIL_DEVICE_IRQ 5 #define PIL_SMP_CALL_FUNC_SNGL 6 #define PIL_DEFERRED_PCR_WORK 7 diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 8174f6cdbbbb..9dca7a892978 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -327,6 +327,7 @@ struct vio_dev { int compat_len; u64 dev_no; + u64 id; unsigned long channel_id; diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index e22416ce56ea..bfbde8c4ffb2 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -1034,17 +1034,26 @@ static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb) { #ifdef CONFIG_SMP unsigned long page; + void *mondo, *p; - BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); + BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE); + + /* Make sure mondo block is 64byte aligned */ + p = kzalloc(127, GFP_KERNEL); + if (!p) { + prom_printf("SUN4V: Error, cannot allocate mondo block.\n"); + prom_halt(); + } + mondo = (void *)(((unsigned long)p + 63) & ~0x3f); + tb->cpu_mondo_block_pa = __pa(mondo); page = get_zeroed_page(GFP_KERNEL); if (!page) { - prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); + prom_printf("SUN4V: Error, cannot allocate cpu list page.\n"); prom_halt(); } - tb->cpu_mondo_block_pa = __pa(page); - tb->cpu_list_pa = __pa(page + 64); + tb->cpu_list_pa = __pa(page); #endif } diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index e7f652be9e61..44f32dd4477f 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -37,7 +37,6 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr /* smp_64.c */ void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs); void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs); -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs); void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs); void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 19cd08d18672..95a9fa0d2195 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -959,37 +959,6 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) preempt_enable(); } -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) -{ - struct mm_struct *mm; - unsigned long flags; - - clear_softint(1 << irq); - - /* See if we need to allocate a new TLB context because - * the version of the one we are using is now out of date. - */ - mm = current->active_mm; - if (unlikely(!mm || (mm == &init_mm))) - return; - - spin_lock_irqsave(&mm->context.lock, flags); - - if (unlikely(!CTX_VALID(mm->context))) - get_new_mmu_context(mm); - - spin_unlock_irqrestore(&mm->context.lock, flags); - - load_secondary_context(mm); - __flush_tlb_mm(CTX_HWBITS(mm->context), - SECONDARY_CONTEXT); -} - -void smp_new_mmu_context_version(void) -{ - smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); -} - #ifdef CONFIG_KGDB void kgdb_roundup_cpus(unsigned long flags) { diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S index d568c8207af7..395ec1800530 100644 --- a/arch/sparc/kernel/tsb.S +++ b/arch/sparc/kernel/tsb.S @@ -470,13 +470,16 @@ __tsb_context_switch: .type copy_tsb,#function copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size * %o2=new_tsb_base, %o3=new_tsb_size + * %o4=page_size_shift */ sethi %uhi(TSB_PASS_BITS), %g7 srlx %o3, 4, %o3 - add %o0, %o1, %g1 /* end of old tsb */ + add %o0, %o1, %o1 /* end of old tsb */ sllx %g7, 32, %g7 sub %o3, 1, %o3 /* %o3 == new tsb hash mask */ + mov %o4, %g1 /* page_size_shift */ + 661: prefetcha [%o0] ASI_N, #one_read .section .tsb_phys_patch, "ax" .word 661b @@ -501,9 +504,9 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size /* This can definitely be computed faster... */ srlx %o0, 4, %o5 /* Build index */ and %o5, 511, %o5 /* Mask index */ - sllx %o5, PAGE_SHIFT, %o5 /* Put into vaddr position */ + sllx %o5, %g1, %o5 /* Put into vaddr position */ or %o4, %o5, %o4 /* Full VADDR. */ - srlx %o4, PAGE_SHIFT, %o4 /* Shift down to create index */ + srlx %o4, %g1, %o4 /* Shift down to create index */ and %o4, %o3, %o4 /* Mask with new_tsb_nents-1 */ sllx %o4, 4, %o4 /* Shift back up into tsb ent offset */ TSB_STORE(%o2 + %o4, %g2) /* Store TAG */ @@ -511,7 +514,7 @@ copy_tsb: /* %o0=old_tsb_base, %o1=old_tsb_size TSB_STORE(%o2 + %o4, %g3) /* Store TTE */ 80: add %o0, 16, %o0 - cmp %o0, %g1 + cmp %o0, %o1 bne,pt %xcc, 90b nop diff --git a/arch/sparc/kernel/ttable_64.S b/arch/sparc/kernel/ttable_64.S index c6dfdaa29e20..170ead662f2a 100644 --- a/arch/sparc/kernel/ttable_64.S +++ b/arch/sparc/kernel/ttable_64.S @@ -50,7 +50,7 @@ tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) -tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4) +tl0_irq4: BTRAP(0x44) #else tl0_irq1: BTRAP(0x41) tl0_irq2: BTRAP(0x42) diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index cb5789c9f961..34824ca396f0 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -284,13 +284,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, if (!id) { dev_set_name(&vdev->dev, "%s", bus_id_name); vdev->dev_no = ~(u64)0; + vdev->id = ~(u64)0; } else if (!cfg_handle) { dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id); vdev->dev_no = *id; + vdev->id = ~(u64)0; } else { dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name, *cfg_handle, *id); vdev->dev_no = *cfg_handle; + vdev->id = *id; } vdev->dev.parent = parent; @@ -333,27 +336,84 @@ static void vio_add(struct mdesc_handle *hp, u64 node) (void) vio_create_one(hp, node, &root_vdev->dev); } +struct vio_md_node_query { + const char *type; + u64 dev_no; + u64 id; +}; + static int vio_md_node_match(struct device *dev, void *arg) { + struct vio_md_node_query *query = (struct vio_md_node_query *) arg; struct vio_dev *vdev = to_vio_dev(dev); - if (vdev->mp == (u64) arg) - return 1; + if (vdev->dev_no != query->dev_no) + return 0; + if (vdev->id != query->id) + return 0; + if (strcmp(vdev->type, query->type)) + return 0; - return 0; + return 1; } static void vio_remove(struct mdesc_handle *hp, u64 node) { + const char *type; + const u64 *id, *cfg_handle; + u64 a; + struct vio_md_node_query query; struct device *dev; - dev = device_find_child(&root_vdev->dev, (void *) node, + type = mdesc_get_property(hp, node, "device-type", NULL); + if (!type) { + type = mdesc_get_property(hp, node, "name", NULL); + if (!type) + type = mdesc_node_name(hp, node); + } + + query.type = type; + + id = mdesc_get_property(hp, node, "id", NULL); + cfg_handle = NULL; + mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { + u64 target; + + target = mdesc_arc_target(hp, a); + cfg_handle = mdesc_get_property(hp, target, + "cfg-handle", NULL); + if (cfg_handle) + break; + } + + if (!id) { + query.dev_no = ~(u64)0; + query.id = ~(u64)0; + } else if (!cfg_handle) { + query.dev_no = *id; + query.id = ~(u64)0; + } else { + query.dev_no = *cfg_handle; + query.id = *id; + } + + dev = device_find_child(&root_vdev->dev, &query, vio_md_node_match); if (dev) { printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev)); device_unregister(dev); put_device(dev); + } else { + if (!id) + printk(KERN_ERR "VIO: Removed unknown %s node.\n", + type); + else if (!cfg_handle) + printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n", + type, *id); + else + printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n", + type, *cfg_handle, *id); } } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 965655afdbb6..384aba109d7c 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -656,10 +656,58 @@ EXPORT_SYMBOL(__flush_dcache_range); /* get_new_mmu_context() uses "cache + 1". */ DEFINE_SPINLOCK(ctx_alloc_lock); -unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +unsigned long tlb_context_cache = CTX_FIRST_VERSION; #define MAX_CTX_NR (1UL << CTX_NR_BITS) #define CTX_BMAP_SLOTS BITS_TO_LONGS(MAX_CTX_NR) DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR); +DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0}; + +static void mmu_context_wrap(void) +{ + unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK; + unsigned long new_ver, new_ctx, old_ctx; + struct mm_struct *mm; + int cpu; + + bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS); + + /* Reserve kernel context */ + set_bit(0, mmu_context_bmap); + + new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION; + if (unlikely(new_ver == 0)) + new_ver = CTX_FIRST_VERSION; + tlb_context_cache = new_ver; + + /* + * Make sure that any new mm that are added into per_cpu_secondary_mm, + * are going to go through get_new_mmu_context() path. + */ + mb(); + + /* + * Updated versions to current on those CPUs that had valid secondary + * contexts + */ + for_each_online_cpu(cpu) { + /* + * If a new mm is stored after we took this mm from the array, + * it will go into get_new_mmu_context() path, because we + * already bumped the version in tlb_context_cache. + */ + mm = per_cpu(per_cpu_secondary_mm, cpu); + + if (unlikely(!mm || mm == &init_mm)) + continue; + + old_ctx = mm->context.sparc64_ctx_val; + if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) { + new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver; + set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap); + mm->context.sparc64_ctx_val = new_ctx; + } + } +} /* Caller does TLB context flushing on local CPU if necessary. * The caller also ensures that CTX_VALID(mm->context) is false. @@ -675,48 +723,30 @@ void get_new_mmu_context(struct mm_struct *mm) { unsigned long ctx, new_ctx; unsigned long orig_pgsz_bits; - int new_version; spin_lock(&ctx_alloc_lock); +retry: + /* wrap might have happened, test again if our context became valid */ + if (unlikely(CTX_VALID(mm->context))) + goto out; orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); ctx = (tlb_context_cache + 1) & CTX_NR_MASK; new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); - new_version = 0; if (new_ctx >= (1 << CTX_NR_BITS)) { new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1); if (new_ctx >= ctx) { - int i; - new_ctx = (tlb_context_cache & CTX_VERSION_MASK) + - CTX_FIRST_VERSION; - if (new_ctx == 1) - new_ctx = CTX_FIRST_VERSION; - - /* Don't call memset, for 16 entries that's just - * plain silly... - */ - mmu_context_bmap[0] = 3; - mmu_context_bmap[1] = 0; - mmu_context_bmap[2] = 0; - mmu_context_bmap[3] = 0; - for (i = 4; i < CTX_BMAP_SLOTS; i += 4) { - mmu_context_bmap[i + 0] = 0; - mmu_context_bmap[i + 1] = 0; - mmu_context_bmap[i + 2] = 0; - mmu_context_bmap[i + 3] = 0; - } - new_version = 1; - goto out; + mmu_context_wrap(); + goto retry; } } + if (mm->context.sparc64_ctx_val) + cpumask_clear(mm_cpumask(mm)); mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63)); new_ctx |= (tlb_context_cache & CTX_VERSION_MASK); -out: tlb_context_cache = new_ctx; mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; +out: spin_unlock(&ctx_alloc_lock); - - if (unlikely(new_version)) - smp_new_mmu_context_version(); } static int numa_enabled = 1; diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 9cdeca0fa955..266411291634 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -451,7 +451,8 @@ retry_tsb_alloc: extern void copy_tsb(unsigned long old_tsb_base, unsigned long old_tsb_size, unsigned long new_tsb_base, - unsigned long new_tsb_size); + unsigned long new_tsb_size, + unsigned long page_size_shift); unsigned long old_tsb_base = (unsigned long) old_tsb; unsigned long new_tsb_base = (unsigned long) new_tsb; @@ -459,7 +460,9 @@ retry_tsb_alloc: old_tsb_base = __pa(old_tsb_base); new_tsb_base = __pa(new_tsb_base); } - copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size); + copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size, + tsb_index == MM_TSB_BASE ? + PAGE_SHIFT : REAL_HPAGE_SHIFT); } mm->context.tsb_block[tsb_index].tsb = new_tsb; diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index 5d2fd6cd3189..fcf4d27a38fb 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S @@ -971,11 +971,6 @@ xcall_capture: wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint retry - .globl xcall_new_mmu_context_version -xcall_new_mmu_context_version: - wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint - retry - #ifdef CONFIG_KGDB .globl xcall_kgdb_capture xcall_kgdb_capture: diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 47190bd399e7..cec49ecf5f31 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -161,8 +161,8 @@ void kvm_async_pf_task_wait(u32 token) */ rcu_irq_exit(); native_safe_halt(); - rcu_irq_enter(); local_irq_disable(); + rcu_irq_enter(); } } if (!n.halted) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 642e9c93a097..9357b29de9bc 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -737,18 +737,20 @@ out: static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i) { struct kvm_cpuid_entry2 *e = &vcpu->arch.cpuid_entries[i]; - int j, nent = vcpu->arch.cpuid_nent; + struct kvm_cpuid_entry2 *ej; + int j = i; + int nent = vcpu->arch.cpuid_nent; e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT; /* when no next entry is found, the current entry[i] is reselected */ - for (j = i + 1; ; j = (j + 1) % nent) { - struct kvm_cpuid_entry2 *ej = &vcpu->arch.cpuid_entries[j]; - if (ej->function == e->function) { - ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; - return j; - } - } - return 0; /* silence gcc, even though control never reaches here */ + do { + j = (j + 1) % nent; + ej = &vcpu->arch.cpuid_entries[j]; + } while (ej->function != e->function); + + ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; + + return j; } /* find an entry with matching function, matching index (if needed), and that diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 8eb8a934b531..1049c3c9b877 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3433,12 +3433,15 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch); } -static bool can_do_async_pf(struct kvm_vcpu *vcpu) +bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu) { if (unlikely(!lapic_in_kernel(vcpu) || kvm_event_needs_reinjection(vcpu))) return false; + if (is_guest_mode(vcpu)) + return false; + return kvm_x86_ops->interrupt_allowed(vcpu); } @@ -3454,7 +3457,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, if (!async) return false; /* *pfn has correct page already */ - if (!prefault && can_do_async_pf(vcpu)) { + if (!prefault && kvm_can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(gva, gfn); if (kvm_find_async_pf_gfn(vcpu, gfn)) { trace_kvm_async_pf_doublefault(gva, gfn); diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 55ffb7b0f95e..e60fc80f8a9c 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -74,6 +74,7 @@ enum { int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct); void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu); void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly); +bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu); static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ae2b9cd358f2..6c82792487e9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8245,8 +8245,7 @@ bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu) if (!(vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED)) return true; else - return !kvm_event_needs_reinjection(vcpu) && - kvm_x86_ops->interrupt_allowed(vcpu); + return kvm_can_do_async_pf(vcpu); } void kvm_arch_start_assignment(struct kvm *kvm) diff --git a/crypto/gcm.c b/crypto/gcm.c index 1238b3c5a321..0a12c09d7cb2 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -152,10 +152,8 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, err = crypto_ablkcipher_encrypt(&data->req); if (err == -EINPROGRESS || err == -EBUSY) { - err = wait_for_completion_interruptible( - &data->result.completion); - if (!err) - err = data->result.err; + wait_for_completion(&data->result.completion); + err = data->result.err; } if (err) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 68561696f31b..a1696e1d199f 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -311,7 +311,8 @@ static const char * const fw_path[] = { "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, - "/lib/firmware" + "/lib/firmware", + "/lib64/firmware" }; /* diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 1faebb1759e2..96be0e2f9183 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -26,6 +26,9 @@ #include <sound/tlv.h> #include <btfm_slim.h> +static int bt_soc_enable_status; + + static int btfm_slim_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -38,8 +41,31 @@ static unsigned int btfm_slim_codec_read(struct snd_soc_codec *codec, return 0; } +static int bt_soc_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = bt_soc_enable_status; + return 1; +} + +static int bt_soc_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 1; +} + +static const struct snd_kcontrol_new status_controls[] = { + SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0, + bt_soc_status_get, + bt_soc_status_put) + +}; + + static int btfm_slim_codec_probe(struct snd_soc_codec *codec) { + snd_soc_add_codec_controls(codec, status_controls, + ARRAY_SIZE(status_controls)); return 0; } @@ -130,6 +156,7 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, struct btfmslim *btfmslim = dai->dev->platform_data; struct btfmslim_ch *ch; uint8_t rxport, grp = false, nchan = 1; + bt_soc_enable_status = 0; BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name, dai->id, dai->rate); @@ -171,6 +198,10 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, } ret = btfm_slim_enable_ch(btfmslim, ch, rxport, dai->rate, grp, nchan); + + /* save the enable channel status */ + if (ret == 0) + bt_soc_enable_status = 1; return ret; } diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index 77e2973e023c..0c4e0b3d5c2e 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -88,12 +88,12 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable); if (rxport) { - if (enable && btfmslim->sample_rate == 48000) { - /* For A2DP Rx */ + if (enable) { + /* For SCO Rx, A2DP Rx */ reg_val = 0x1; port_bit = port_num - 0x10; reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit); - BTFMSLIM_DBG("writing reg_val (%d) to reg(%x) for A2DP", + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", reg_val, reg); ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) { diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 0975d23031ea..2898d19fadf5 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -346,7 +346,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT; /* It's illegal to wrap around the end of the physical address space. */ - if (offset + (phys_addr_t)size < offset) + if (offset + (phys_addr_t)size - 1 < offset) return -EINVAL; if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) diff --git a/drivers/char/random.c b/drivers/char/random.c index d93dfebae0bb..1822472dffab 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1798,13 +1798,15 @@ int random_int_secret_init(void) return 0; } +static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash) + __aligned(sizeof(unsigned long)); + /* * Get a random word for internal kernel use only. Similar to urandom but * with the goal of minimal entropy pool depletion. As a result, the random * value is not cryptographically secure but for several uses the cost of * depleting entropy is too high */ -static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash); unsigned int get_random_int(void) { __u32 *hash; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 93a5273aa459..5f0f983ce173 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2568,6 +2568,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (!(cpufreq_driver->flags & CPUFREQ_STICKY) && list_empty(&cpufreq_policy_list)) { /* if all ->init() calls failed, unregister */ + ret = -ENODEV; pr_debug("%s: No CPU initialized for driver %s\n", __func__, driver_data->name); goto err_if_unreg; diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index b69e59eeeae1..7cd1bbbe1ee8 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1119,10 +1119,14 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, bool from_idle, int predicted) { struct lpm_cluster_level *level = &cluster->levels[idx]; + struct cpumask online_cpus; int ret, i; + cpumask_and(&online_cpus, &cluster->num_children_in_sync, + cpu_online_mask); + if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus) - || is_IPI_pending(&cluster->num_children_in_sync)) { + || is_IPI_pending(&online_cpus)) { return -EPERM; } diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 57ff46284f15..c97336a2ba92 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -325,6 +325,8 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac) | M2P_CONTROL_ENABLE; m2p_set_control(edmac, control); + edmac->buffer = 0; + return 0; } diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index b1bc945f008f..56410ea75ac5 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -117,7 +117,7 @@ struct usb_dmac { #define USB_DMASWR 0x0008 #define USB_DMASWR_SWR (1 << 0) #define USB_DMAOR 0x0060 -#define USB_DMAOR_AE (1 << 2) +#define USB_DMAOR_AE (1 << 1) #define USB_DMAOR_DME (1 << 0) #define USB_DMASAR 0x0000 diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index 57a2e347f04d..0f0094b58d1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -893,6 +893,12 @@ static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev) u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300; + /* disable mclk switching if the refresh is >120Hz, even if the + * blanking period would allow it + */ + if (amdgpu_dpm_get_vrefresh(adev) > 120) + return true; + if (vblank_time < switch_limit) return true; else diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 64914585c9a5..2ee75a2c1039 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -705,13 +705,22 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) u64 clip_pclk; int rc = 0; + mutex_lock(&display->display_lock); + if (!hdmi->power_on || !display->connected) { SDE_ERROR("HDMI display is not ready\n"); + mutex_unlock(&display->display_lock); + return -EINVAL; + } + + if (!display->pll_update_enable) { + SDE_ERROR("PLL update function is not enabled\n"); + mutex_unlock(&display->display_lock); return -EINVAL; } /* get current pclk */ - cur_pclk = hdmi->pixclock; + cur_pclk = hdmi->actual_pixclock; /* get desired pclk */ dst_pclk = cur_pclk * (1000000000 + ppm); do_div(dst_pclk, 1000000000); @@ -725,13 +734,16 @@ static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm) rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk); if (rc < 0) { - SDE_ERROR("PLL update failed, reset clock rate\n"); + SDE_ERROR("HDMI PLL update failed\n"); + mutex_unlock(&display->display_lock); return rc; } - hdmi->pixclock = clip_pclk; + hdmi->actual_pixclock = clip_pclk; } + mutex_unlock(&display->display_lock); + return rc; } @@ -767,14 +779,119 @@ static const struct file_operations pll_delta_fops = { .write = _sde_hdmi_debugfs_pll_delta_write, }; +/** + * _sde_hdmi_enable_pll_update() - Enable the HDMI PLL update function + * + * @enable: non-zero to enable PLL update function, 0 to disable. + * return: 0 on success, non-zero in case of failure. + * + */ +static int _sde_hdmi_enable_pll_update(struct sde_hdmi *display, s32 enable) +{ + struct hdmi *hdmi = display->ctrl.ctrl; + int rc = 0; + + mutex_lock(&display->display_lock); + + if (!hdmi->power_on || !display->connected) { + SDE_ERROR("HDMI display is not ready\n"); + mutex_unlock(&display->display_lock); + return -EINVAL; + } + + if (!enable && hdmi->actual_pixclock != hdmi->pixclock) { + /* reset pixel clock when disable */ + rc = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock); + if (rc < 0) { + SDE_ERROR("reset clock rate failed\n"); + mutex_unlock(&display->display_lock); + return rc; + } + } + hdmi->actual_pixclock = hdmi->pixclock; + + display->pll_update_enable = !!enable; + + mutex_unlock(&display->display_lock); + + SDE_DEBUG("HDMI PLL update: %s\n", + display->pll_update_enable ? "enable" : "disable"); + + return rc; +} + +static ssize_t _sde_hdmi_debugfs_pll_enable_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_hdmi *display = file->private_data; + char *buf; + u32 len = 0; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_1K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf, SZ_4K, "%s\n", + display->pll_update_enable ? "enable" : "disable"); + + if (copy_to_user(buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + + kfree(buf); + return len; +} + +static ssize_t _sde_hdmi_debugfs_pll_enable_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_hdmi *display = file->private_data; + char buf[10]; + int enable = 0; + + if (!display) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtoint(buf, 0, &enable)) + return -EFAULT; + + _sde_hdmi_enable_pll_update(display, enable); + + return count; +} + +static const struct file_operations pll_enable_fops = { + .open = simple_open, + .read = _sde_hdmi_debugfs_pll_enable_read, + .write = _sde_hdmi_debugfs_pll_enable_write, +}; + static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) { int rc = 0; struct dentry *dir, *dump_file, *edid_modes; struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info; - struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file; + struct dentry *edid_vcdb_info, *edid_vendor_name; struct dentry *src_hdcp14_support, *src_hdcp22_support; struct dentry *sink_hdcp22_support, *hdmi_hdcp_state; + struct dentry *pll_delta_file, *pll_enable_file; dir = debugfs_create_dir(display->name, NULL); if (!dir) { @@ -796,18 +913,30 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display) goto error_remove_dir; } - pll_file = debugfs_create_file("pll_delta", + pll_delta_file = debugfs_create_file("pll_delta", 0644, dir, display, &pll_delta_fops); - if (IS_ERR_OR_NULL(pll_file)) { - rc = PTR_ERR(pll_file); + if (IS_ERR_OR_NULL(pll_delta_file)) { + rc = PTR_ERR(pll_delta_file); SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n", display->name, rc); goto error_remove_dir; } + pll_enable_file = debugfs_create_file("pll_enable", + 0644, + dir, + display, + &pll_enable_fops); + if (IS_ERR_OR_NULL(pll_enable_file)) { + rc = PTR_ERR(pll_enable_file); + SDE_ERROR("[%s]debugfs create pll_enable file failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + edid_modes = debugfs_create_file("edid_modes", 0444, dir, @@ -1738,6 +1867,106 @@ int sde_hdmi_get_info(struct msm_display_info *info, return rc; } +static void sde_hdmi_panel_set_hdr_infoframe(struct sde_hdmi *display, +struct drm_msm_ext_panel_hdr_metadata *hdr_meta) +{ + u32 packet_payload = 0; + u32 packet_header = 0; + u32 packet_control = 0; + u32 const type_code = 0x87; + u32 const version = 0x01; + u32 const length = 0x1a; + u32 const descriptor_id = 0x00; + struct hdmi *hdmi; + struct drm_connector *connector; + + if (!display || !hdr_meta) { + SDE_ERROR("invalid input\n"); + return; + } + + hdmi = display->ctrl.ctrl; + connector = display->ctrl.ctrl->connector; + + if (!hdmi || !connector) { + SDE_ERROR("invalid input\n"); + return; + } + + if (!connector->hdr_supported) { + SDE_ERROR("Sink does not support HDR\n"); + return; + } + + /* Setup Packet header and payload */ + packet_header = type_code | (version << 8) | (length << 16); + hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header); + + packet_payload = (hdr_meta->eotf << 8); + if (connector->hdr_metadata_type_one) { + packet_payload |= (descriptor_id << 16) + | (HDMI_GET_LSB(hdr_meta->display_primaries_x[0]) + << 24); + hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload); + } else { + pr_debug("Metadata Type 1 not supported\n"); + hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload); + goto enable_packet_control; + } + + packet_payload = + (HDMI_GET_MSB(hdr_meta->display_primaries_x[0])) + | (HDMI_GET_LSB(hdr_meta->display_primaries_y[0]) << 8) + | (HDMI_GET_MSB(hdr_meta->display_primaries_y[0]) << 16) + | (HDMI_GET_LSB(hdr_meta->display_primaries_x[1]) << 24); + hdmi_write(hdmi, HDMI_GENERIC0_1, packet_payload); + + packet_payload = + (HDMI_GET_MSB(hdr_meta->display_primaries_x[1])) + | (HDMI_GET_LSB(hdr_meta->display_primaries_y[1]) << 8) + | (HDMI_GET_MSB(hdr_meta->display_primaries_y[1]) << 16) + | (HDMI_GET_LSB(hdr_meta->display_primaries_x[2]) << 24); + hdmi_write(hdmi, HDMI_GENERIC0_2, packet_payload); + + packet_payload = + (HDMI_GET_MSB(hdr_meta->display_primaries_x[2])) + | (HDMI_GET_LSB(hdr_meta->display_primaries_y[2]) << 8) + | (HDMI_GET_MSB(hdr_meta->display_primaries_y[2]) << 16) + | (HDMI_GET_LSB(hdr_meta->white_point_x) << 24); + hdmi_write(hdmi, HDMI_GENERIC0_3, packet_payload); + + packet_payload = + (HDMI_GET_MSB(hdr_meta->white_point_x)) + | (HDMI_GET_LSB(hdr_meta->white_point_y) << 8) + | (HDMI_GET_MSB(hdr_meta->white_point_y) << 16) + | (HDMI_GET_LSB(hdr_meta->max_luminance) << 24); + hdmi_write(hdmi, HDMI_GENERIC0_4, packet_payload); + + packet_payload = + (HDMI_GET_MSB(hdr_meta->max_luminance)) + | (HDMI_GET_LSB(hdr_meta->min_luminance) << 8) + | (HDMI_GET_MSB(hdr_meta->min_luminance) << 16) + | (HDMI_GET_LSB(hdr_meta->max_content_light_level) << 24); + hdmi_write(hdmi, HDMI_GENERIC0_5, packet_payload); + + packet_payload = + (HDMI_GET_MSB(hdr_meta->max_content_light_level)) + | (HDMI_GET_LSB(hdr_meta->max_average_light_level) << 8) + | (HDMI_GET_MSB(hdr_meta->max_average_light_level) << 16); + hdmi_write(hdmi, HDMI_GENERIC0_6, packet_payload); + +enable_packet_control: + /* + * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND + * Setup HDMI TX generic packet control + * Enable this packet to transmit every frame + * Enable HDMI TX engine to transmit Generic packet 1 + */ + packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL); + packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16); + hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control); +} + int sde_hdmi_set_property(struct drm_connector *connector, struct drm_connector_state *state, int property_index, @@ -1749,17 +1978,42 @@ int sde_hdmi_set_property(struct drm_connector *connector, if (!connector || !display) { SDE_ERROR("connector=%pK or display=%pK is NULL\n", connector, display); - return 0; + return -EINVAL; } SDE_DEBUG("\n"); - if (property_index == CONNECTOR_PROP_PLL_DELTA) + if (property_index == CONNECTOR_PROP_PLL_ENABLE) + rc = _sde_hdmi_enable_pll_update(display, value); + else if (property_index == CONNECTOR_PROP_PLL_DELTA) rc = _sde_hdmi_update_pll_delta(display, value); return rc; } +int sde_hdmi_get_property(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t *value, + void *display) +{ + struct sde_hdmi *hdmi_display = display; + int rc = 0; + + if (!connector || !hdmi_display) { + SDE_ERROR("connector=%pK or display=%pK is NULL\n", + connector, hdmi_display); + return -EINVAL; + } + + mutex_lock(&hdmi_display->display_lock); + if (property_index == CONNECTOR_PROP_PLL_ENABLE) + *value = hdmi_display->pll_update_enable ? 1 : 0; + mutex_unlock(&hdmi_display->display_lock); + + return rc; +} + u32 sde_hdmi_get_num_of_displays(void) { u32 count = 0; @@ -2049,6 +2303,17 @@ sde_hdmi_connector_detect(struct drm_connector *connector, return status; } +int sde_hdmi_pre_kickoff(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params) +{ + + sde_hdmi_panel_set_hdr_infoframe(display, + params->hdr_metadata); + + return 0; +} + int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display) { struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index 84d8720969be..6b9bcfec031b 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -109,6 +109,7 @@ enum hdmi_tx_feature_type { * @codec_ready: If audio codec is ready. * @client_notify_pending: If there is client notification pending. * @irq_domain: IRQ domain structure. + * @pll_update_enable: if it's allowed to update HDMI PLL ppm. * @notifier: CEC notifider to convey physical address information. * @root: Debug fs root entry. */ @@ -159,6 +160,7 @@ struct sde_hdmi { struct irq_domain *irq_domain; struct cec_notifier *notifier; + bool pll_update_enable; struct delayed_work hdcp_cb_work; struct dss_io_data io[HDMI_TX_MAX_IO]; @@ -345,6 +347,22 @@ int sde_hdmi_set_property(struct drm_connector *connector, void *display); /** + * sde_hdmi_get_property() - get the connector properties + * @connector: Handle to the connector. + * @state: Handle to the connector state. + * @property_index: property index. + * @value: property value. + * @display: Handle to the display. + * + * Return: error code. + */ +int sde_hdmi_get_property(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t *value, + void *display); + +/** * sde_hdmi_bridge_init() - init sde hdmi bridge * @hdmi: Handle to the hdmi. * @@ -434,6 +452,17 @@ bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl); int sde_hdmi_start_hdcp(struct drm_connector *connector); void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl); + +/* + * sde_hdmi_pre_kickoff - program kickoff-time features + * @display: Pointer to private display structure + * @params: Parameters for kickoff-time programming + * Returns: Zero on success + */ +int sde_hdmi_pre_kickoff(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params); + #else /*#ifdef CONFIG_DRM_SDE_HDMI*/ static inline u32 sde_hdmi_get_num_of_displays(void) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 7af84f5c4229..24d2320683e4 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -494,6 +494,16 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge) static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) { + struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct sde_connector *c_conn = to_sde_connector(hdmi->connector); + struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display; + + mutex_lock(&display->display_lock); + + display->pll_update_enable = false; + + mutex_unlock(&display->display_lock); } static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h index 6b310acee0ff..8b69dd31f637 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h @@ -94,6 +94,9 @@ /* default hsyncs for 4k@60 for 200ms */ #define HDMI_DEFAULT_TIMEOUT_HSYNC 28571 +#define HDMI_GET_MSB(x)(x >> 8) +#define HDMI_GET_LSB(x)(x & 0xff) + /* * Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be * read by the hardware diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 84b578eaad47..8ca7b36ee0c8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -56,6 +56,7 @@ struct hdmi { /* video state: */ bool power_on; unsigned long int pixclock; + unsigned long int actual_pixclock; void __iomem *mmio; void __iomem *qfprom_mmio; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index a441f3d15542..367e701b59cb 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -26,11 +26,68 @@ #include "msm_gem.h" #include "msm_mmu.h" +static void msm_drm_helper_hotplug_event(struct drm_device *dev) +{ + struct drm_connector *connector; + char *event_string; + char const *connector_name; + char *envp[2]; + + if (!dev) { + DRM_ERROR("hotplug_event failed, invalid input\n"); + return; + } + + if (!dev->mode_config.poll_enabled) + return; + + event_string = kzalloc(SZ_4K, GFP_KERNEL); + if (!event_string) { + DRM_ERROR("failed to allocate event string\n"); + return; + } + + mutex_lock(&dev->mode_config.mutex); + drm_for_each_connector(connector, dev) { + /* Only handle HPD capable connectors. */ + if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) + continue; + + connector->status = connector->funcs->detect(connector, false); + + if (connector->name) + connector_name = connector->name; + else + connector_name = "unknown"; + + snprintf(event_string, SZ_4K, "name=%s status=%s\n", + connector_name, + drm_get_connector_status_name(connector->status)); + DRM_DEBUG("generating hotplug event [%s]\n", event_string); + envp[0] = event_string; + envp[1] = NULL; + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, + envp); + } + mutex_unlock(&dev->mode_config.mutex); + kfree(event_string); +} + static void msm_fb_output_poll_changed(struct drm_device *dev) { - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = NULL; + + if (!dev) { + DRM_ERROR("output_poll_changed failed, invalid input\n"); + return; + } + + priv = dev->dev_private; + if (priv->fbdev) drm_fb_helper_hotplug_event(priv->fbdev); + else + msm_drm_helper_hotplug_event(dev); } static const struct drm_mode_config_funcs mode_config_funcs = { @@ -602,7 +659,8 @@ static int msm_open(struct drm_device *dev, struct drm_file *file) if (IS_ERR(ctx)) return PTR_ERR(ctx); - INIT_LIST_HEAD(&ctx->counters); + if (ctx) + INIT_LIST_HEAD(&ctx->counters); msm_submitqueue_init(ctx); @@ -1839,6 +1897,7 @@ static struct drm_driver msm_driver = { .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = drm_gem_prime_export, .gem_prime_import = drm_gem_prime_import, + .gem_prime_res_obj = msm_gem_prime_res_obj, .gem_prime_pin = msm_gem_prime_pin, .gem_prime_unpin = msm_gem_prime_unpin, .gem_prime_get_sg_table = msm_gem_prime_get_sg_table, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index c2ccc5d462a7..d696f05e0459 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -143,6 +143,8 @@ enum msm_mdp_crtc_property { enum msm_mdp_conn_property { /* blob properties, always put these first */ CONNECTOR_PROP_SDE_INFO, + CONNECTOR_PROP_HDR_INFO, + CONNECTOR_PROP_HDR_METADATA, /* # of blob properties */ CONNECTOR_PROP_BLOBCOUNT, @@ -155,6 +157,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_DST_W, CONNECTOR_PROP_DST_H, CONNECTOR_PROP_PLL_DELTA, + CONNECTOR_PROP_PLL_ENABLE, /* enum/bitmask properties */ CONNECTOR_PROP_TOPOLOGY_NAME, @@ -233,6 +236,14 @@ struct msm_display_info { }; /** + * struct - msm_display_kickoff_params - info for display features at kickoff + * @hdr_metadata: HDR metadata info passed from userspace + */ +struct msm_display_kickoff_params { + struct drm_msm_ext_panel_hdr_metadata *hdr_metadata; +}; + +/** * struct msm_drm_event - defines custom event notification struct * @base: base object required for event notification by DRM framework. * @event: event object required for event notification by DRM framework. @@ -465,6 +476,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj); void *msm_gem_prime_vmap(struct drm_gem_object *obj); void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); +struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj); struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); int msm_gem_prime_pin(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 70af0d41f970..d66071672c62 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -1046,7 +1046,7 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev, { struct drm_gem_object *obj; struct msm_file_private *ctx = file->driver_priv; - struct msm_gem_address_space *aspace = ctx->aspace; + struct msm_gem_address_space *aspace; struct msm_gem_object *msm_obj; struct msm_gem_svm_object *msm_svm_obj; struct msm_gem_vma *domain = NULL; @@ -1056,6 +1056,9 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev, int write; int ret; + if (!ctx) + return ERR_PTR(-ENODEV); + /* if we don't have IOMMU, don't bother pretending we can import: */ if (!iommu_present(&platform_bus_type)) { dev_err_once(dev->dev, "cannot import without IOMMU\n"); @@ -1078,6 +1081,7 @@ struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev, drm_gem_private_object_init(dev, obj, size); msm_obj = to_msm_bo(obj); + aspace = ctx->aspace; domain = obj_add_domain(&msm_obj->base, aspace); if (IS_ERR(domain)) { drm_gem_object_unreference_unlocked(obj); diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 678018804f3a..9f3c097d011b 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -80,3 +80,10 @@ void msm_gem_prime_unpin(struct drm_gem_object *obj) if (!obj->import_attach) msm_gem_put_pages(obj); } + +struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + return msm_obj->resv; +} diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b9ace0d9e69b..7ccc146f3ae1 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -430,7 +430,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, return -EINVAL; gpu = priv->gpu; - if (!gpu) + if (!gpu || !ctx) return -ENXIO; queue = msm_submitqueue_get(ctx, args->queueid); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 16049e830b7a..d896e436251f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -669,6 +669,9 @@ int msm_gpu_counter_put(struct msm_gpu *gpu, struct drm_msm_counter *data, { struct msm_context_counter *entry; + if (!gpu || !ctx) + return -ENODEV; + list_for_each_entry(entry, &ctx->counters, node) { if (entry->groupid == data->groupid && entry->counterid == data->counterid) { diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 7538927a4993..0bb8298c1013 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -17,6 +17,12 @@ #include "sde_connector.h" #include "sde_backlight.h" +#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\ + (c) ? (c)->base.base.id : -1, ##__VA_ARGS__) + +#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\ + (c) ? (c)->base.base.id : -1, ##__VA_ARGS__) + static const struct drm_prop_enum_list e_topology_name[] = { {SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"}, {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"}, @@ -54,6 +60,36 @@ int sde_connector_get_info(struct drm_connector *connector, return c_conn->ops.get_info(info, c_conn->display); } +int sde_connector_pre_kickoff(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct msm_display_kickoff_params params; + int rc; + + if (!connector) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + if (!c_conn->display) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + if (!c_conn->ops.pre_kickoff) + return 0; + + params.hdr_metadata = &c_state->hdr_meta; + + rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms); + + return rc; +} + static void sde_connector_destroy(struct drm_connector *connector) { struct sde_connector *c_conn; @@ -70,7 +106,8 @@ static void sde_connector_destroy(struct drm_connector *connector) if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); - + if (c_conn->blob_hdr) + drm_property_unreference_blob(c_conn->blob_hdr); msm_property_destroy(&c_conn->property_info); drm_connector_unregister(connector); @@ -204,6 +241,68 @@ sde_connector_atomic_duplicate_state(struct drm_connector *connector) return &c_state->base; } +static int _sde_connector_set_hdr_info( + struct sde_connector *c_conn, + struct sde_connector_state *c_state, + void *usr_ptr) +{ + struct drm_connector *connector; + struct drm_msm_ext_panel_hdr_metadata *hdr_meta; + int i; + + if (!c_conn || !c_state) { + SDE_ERROR_CONN(c_conn, "invalid args\n"); + return -EINVAL; + } + + connector = &c_conn->base; + + if (!connector->hdr_supported) { + SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n"); + return -ENOTSUPP; + } + + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + + if (!usr_ptr) { + SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n"); + return 0; + } + + if (copy_from_user(&c_state->hdr_meta, + (void __user *)usr_ptr, + sizeof(*hdr_meta))) { + SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n"); + return -EFAULT; + } + + hdr_meta = &c_state->hdr_meta; + + SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", + hdr_meta->hdr_supported); + SDE_DEBUG_CONN(c_conn, "eotf %d\n", + hdr_meta->eotf); + SDE_DEBUG_CONN(c_conn, "white_point_x %d\n", + hdr_meta->white_point_x); + SDE_DEBUG_CONN(c_conn, "white_point_y %d\n", + hdr_meta->white_point_y); + SDE_DEBUG_CONN(c_conn, "max_luminance %d\n", + hdr_meta->max_luminance); + SDE_DEBUG_CONN(c_conn, "max_content_light_level %d\n", + hdr_meta->max_content_light_level); + SDE_DEBUG_CONN(c_conn, "max_average_light_level %d\n", + hdr_meta->max_average_light_level); + + for (i = 0; i < HDR_PRIMARIES_COUNT; i++) { + SDE_DEBUG_CONN(c_conn, "display_primaries_x [%d]\n", + hdr_meta->display_primaries_x[i]); + SDE_DEBUG_CONN(c_conn, "display_primaries_y [%d]\n", + hdr_meta->display_primaries_y[i]); + } + + return 0; +} + static int sde_connector_atomic_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, @@ -263,6 +362,12 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, SDE_ERROR("invalid topology_control: 0x%llX\n", val); } + if (idx == CONNECTOR_PROP_HDR_METADATA) { + rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val); + if (rc) + SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); + } + /* check for custom property handling */ if (!rc && c_conn->ops.set_property) { rc = c_conn->ops.set_property(connector, @@ -355,6 +460,32 @@ void sde_connector_complete_commit(struct drm_connector *connector) sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0); } +static void sde_connector_update_hdr_props(struct drm_connector *connector) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + struct drm_msm_ext_panel_hdr_properties hdr_prop = {}; + + hdr_prop.hdr_supported = connector->hdr_supported; + + if (hdr_prop.hdr_supported) { + hdr_prop.hdr_eotf = + connector->hdr_eotf; + hdr_prop.hdr_metadata_type_one = + connector->hdr_metadata_type_one; + hdr_prop.hdr_max_luminance = + connector->hdr_max_luminance; + hdr_prop.hdr_avg_luminance = + connector->hdr_avg_luminance; + hdr_prop.hdr_min_luminance = + connector->hdr_min_luminance; + } + msm_property_set_blob(&c_conn->property_info, + &c_conn->blob_hdr, + &hdr_prop, + sizeof(hdr_prop), + CONNECTOR_PROP_HDR_INFO); +} + static enum drm_connector_status sde_connector_detect(struct drm_connector *connector, bool force) { @@ -392,6 +523,7 @@ static const struct drm_connector_funcs sde_connector_ops = { static int sde_connector_get_modes(struct drm_connector *connector) { struct sde_connector *c_conn; + int ret = 0; if (!connector) { SDE_ERROR("invalid connector\n"); @@ -403,8 +535,11 @@ static int sde_connector_get_modes(struct drm_connector *connector) SDE_DEBUG("missing get_modes callback\n"); return 0; } + ret = c_conn->ops.get_modes(connector, c_conn->display); + if (ret) + sde_connector_update_hdr_props(connector); - return c_conn->ops.get_modes(connector, c_conn->display); + return ret; } static enum drm_mode_status @@ -575,6 +710,17 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, kfree(info); } + if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { + msm_property_install_blob(&c_conn->property_info, + "hdr_properties", + DRM_MODE_PROP_IMMUTABLE, + CONNECTOR_PROP_HDR_INFO); + } + + msm_property_install_volatile_range(&c_conn->property_info, + "hdr_metadata", 0x0, 0, ~0, 0, + CONNECTOR_PROP_HDR_METADATA); + msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); @@ -582,6 +728,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, "PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0, CONNECTOR_PROP_PLL_DELTA); + msm_property_install_volatile_range(&c_conn->property_info, + "PLL_ENABLE", 0x0, 0, 1, 0, + CONNECTOR_PROP_PLL_ENABLE); + /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, @@ -608,6 +758,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, error_destroy_property: if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); + if (c_conn->blob_hdr) + drm_property_unreference_blob(c_conn->blob_hdr); msm_property_destroy(&c_conn->property_info); error_unregister_conn: drm_connector_unregister(&c_conn->base); diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 3f26ee7d5965..19e2b8a3e41c 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -122,6 +122,19 @@ struct sde_connector_ops { int (*get_info)(struct msm_display_info *info, void *display); int (*set_backlight)(void *display, u32 bl_lvl); + + + /** + * pre_kickoff - trigger display to program kickoff-time features + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * @params: Parameter bundle of connector-stored information for + * kickoff-time programming into the display + * Returns: Zero on success + */ + int (*pre_kickoff)(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params); }; /** @@ -139,6 +152,7 @@ struct sde_connector_ops { * @property_info: Private structure for generic property handling * @property_data: Array of private data for generic property handling * @blob_caps: Pointer to blob structure for 'capabilities' property + * @blob_hdr: Pointer to blob structure for 'hdr_properties' property */ struct sde_connector { struct drm_connector base; @@ -159,6 +173,7 @@ struct sde_connector { struct msm_property_info property_info; struct msm_property_data property_data[CONNECTOR_PROP_COUNT]; struct drm_property_blob *blob_caps; + struct drm_property_blob *blob_hdr; }; /** @@ -206,12 +221,14 @@ struct sde_connector { * @out_fb: Pointer to output frame buffer, if applicable * @aspace: Address space for accessing frame buffer objects, if applicable * @property_values: Local cache of current connector property values + * @hdr_meta: HDR metadata info passed from userspace */ struct sde_connector_state { struct drm_connector_state base; struct drm_framebuffer *out_fb; struct msm_gem_address_space *aspace; uint64_t property_values[CONNECTOR_PROP_COUNT]; + struct drm_msm_ext_panel_hdr_metadata hdr_meta; }; /** @@ -303,5 +320,12 @@ void sde_connector_complete_commit(struct drm_connector *connector); int sde_connector_get_info(struct drm_connector *connector, struct msm_display_info *info); +/** + * sde_connector_pre_kickoff - trigger kickoff time feature programming + * @connector: Pointer to drm connector object + * Returns: Zero on success + */ +int sde_connector_pre_kickoff(struct drm_connector *connector); + #endif /* _SDE_CONNECTOR_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 030b192e5df4..fa03fc8f7ac9 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -795,6 +795,7 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; unsigned int i; + int rc; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); @@ -811,6 +812,14 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) if (phys && phys->ops.prepare_for_kickoff) phys->ops.prepare_for_kickoff(phys); } + + if (sde_enc->cur_master && sde_enc->cur_master->connector) { + rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); + if (rc) + SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n", + sde_enc->cur_master->connector->base.id, + rc); + } } void sde_encoder_kickoff(struct drm_encoder *drm_enc) diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c index a59ec31ba276..49b3d8e96938 100644 --- a/drivers/gpu/drm/msm/sde/sde_formats.c +++ b/drivers/gpu/drm/msm/sde/sde_formats.c @@ -11,12 +11,15 @@ */ #include <uapi/drm/drm_fourcc.h> +#include <uapi/media/msm_media_info.h> #include "sde_kms.h" #include "sde_formats.h" #define SDE_UBWC_META_MACRO_W_H 16 #define SDE_UBWC_META_BLOCK_SIZE 256 +#define SDE_UBWC_PLANE_SIZE_ALIGNMENT 4096 + #define SDE_MAX_IMG_WIDTH 0x3FFF #define SDE_MAX_IMG_HEIGHT 0x3FFF @@ -42,7 +45,7 @@ bp, flg, fm, np) \ .unpack_count = uc, \ .bpp = bp, \ .fetch_mode = fm, \ - .flag = flg, \ + .flag = {(flg)}, \ .num_planes = np \ } @@ -60,7 +63,7 @@ alpha, chroma, count, bp, flg, fm, np) \ .unpack_count = count, \ .bpp = bp, \ .fetch_mode = fm, \ - .flag = flg, \ + .flag = {(flg)}, \ .num_planes = np \ } @@ -77,7 +80,24 @@ alpha, chroma, count, bp, flg, fm, np) \ .unpack_count = 2, \ .bpp = 2, \ .fetch_mode = fm, \ - .flag = flg, \ + .flag = {(flg)}, \ + .num_planes = np \ +} + +#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 1, \ + .unpack_tight = 0, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ .num_planes = np \ } @@ -95,10 +115,20 @@ flg, fm, np) \ .unpack_count = 1, \ .bpp = bp, \ .fetch_mode = fm, \ - .flag = flg, \ + .flag = {(flg)}, \ .num_planes = np \ } +/* + * struct sde_media_color_map - maps drm format to media format + * @format: DRM base pixel format + * @color: Media API color related to DRM format + */ +struct sde_media_color_map { + uint32_t format; + uint32_t color; +}; + static const struct sde_format sde_format_map[] = { INTERLEAVED_RGB_FMT(ARGB8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, @@ -270,49 +300,49 @@ static const struct sde_format sde_format_map[] = { INTERLEAVED_RGB_FMT(BGRA1010102, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, true, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBA1010102, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, true, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(ABGR2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(ARGB2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, true, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XRGB2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, false, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(BGRX1010102, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, false, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XBGR2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBX1010102, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, false, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_LINEAR, 1), @@ -384,31 +414,31 @@ static const struct sde_format sde_format_map[] = { * the data will be passed by user-space. */ static const struct sde_format sde_format_map_ubwc[] = { - INTERLEAVED_RGB_FMT(RGB565, + INTERLEAVED_RGB_FMT(BGR565, 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, false, 2, 0, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(RGBA8888, + INTERLEAVED_RGB_FMT(ABGR8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 4, 0, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(RGBX8888, + INTERLEAVED_RGB_FMT(XBGR8888, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 4, 0, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(RGBA1010102, + INTERLEAVED_RGB_FMT(ABGR2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 4, SDE_FORMAT_FLAG_DX, SDE_FETCH_UBWC, 2), - INTERLEAVED_RGB_FMT(RGBX1010102, + INTERLEAVED_RGB_FMT(XBGR2101010, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 4, SDE_FORMAT_FLAG_DX, @@ -421,6 +451,30 @@ static const struct sde_format sde_format_map_ubwc[] = { SDE_FETCH_UBWC, 4), }; +static const struct sde_format sde_format_map_p010[] = { + PSEUDO_YUV_FMT_LOOSE(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_LINEAR, 2), +}; + +static const struct sde_format sde_format_map_p010_ubwc[] = { + PSEUDO_YUV_FMT_LOOSE(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_UBWC, 4), +}; + +static const struct sde_format sde_format_map_tp10_ubwc[] = { + PSEUDO_YUV_FMT(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_UBWC, 4), +}; + /* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support * Note: Not using the drm_format_*_subsampling since we have formats */ @@ -452,6 +506,37 @@ static void _sde_get_v_h_subsample_rate( } } +static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt) +{ + static const struct sde_media_color_map sde_media_ubwc_map[] = { + {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, + }; + int color_fmt = -1; + int i; + + if (fmt->base.pixel_format == DRM_FORMAT_NV12) { + if (SDE_FORMAT_IS_DX(fmt)) { + if (fmt->unpack_tight) + color_fmt = COLOR_FMT_NV12_BPP10_UBWC; + else + color_fmt = COLOR_FMT_P010_UBWC; + } else + color_fmt = COLOR_FMT_NV12_UBWC; + return color_fmt; + } + + for (i = 0; i < ARRAY_SIZE(sde_media_ubwc_map); ++i) + if (fmt->base.pixel_format == sde_media_ubwc_map[i].format) { + color_fmt = sde_media_ubwc_map[i].color; + break; + } + return color_fmt; +} + static int _sde_format_get_plane_sizes_ubwc( const struct sde_format *fmt, const uint32_t width, @@ -459,6 +544,7 @@ static int _sde_format_get_plane_sizes_ubwc( struct sde_hw_fmt_layout *layout) { int i; + int color; memset(layout, 0, sizeof(struct sde_hw_fmt_layout)); layout->format = fmt; @@ -466,84 +552,53 @@ static int _sde_format_get_plane_sizes_ubwc( layout->height = height; layout->num_planes = fmt->num_planes; - if (fmt->base.pixel_format == DRM_FORMAT_NV12) { - uint32_t y_stride_alignment, uv_stride_alignment; - uint32_t y_height_alignment, uv_height_alignment; - uint32_t y_tile_width = 32; - uint32_t y_tile_height = 8; - uint32_t uv_tile_width = y_tile_width / 2; - uint32_t uv_tile_height = y_tile_height; - uint32_t y_bpp_numer = 1, y_bpp_denom = 1; - uint32_t uv_bpp_numer = 1, uv_bpp_denom = 1; - - y_stride_alignment = 128; - uv_stride_alignment = 64; - y_height_alignment = 32; - uv_height_alignment = 32; - y_bpp_numer = 1; - uv_bpp_numer = 2; - y_bpp_denom = 1; - uv_bpp_denom = 1; + color = _sde_format_get_media_color_ubwc(fmt); + if (color < 0) { + DRM_ERROR("UBWC format not supported for fmt:0x%X\n", + fmt->base.pixel_format); + return -EINVAL; + } + + if (SDE_FORMAT_IS_YUV(layout->format)) { + uint32_t y_sclines, uv_sclines; + uint32_t y_meta_scanlines = 0; + uint32_t uv_meta_scanlines = 0; layout->num_planes = 4; - /* Y bitstream stride and plane size */ - layout->plane_pitch[0] = ALIGN(width, y_stride_alignment); - layout->plane_pitch[0] = (layout->plane_pitch[0] * y_bpp_numer) - / y_bpp_denom; - layout->plane_size[0] = ALIGN(layout->plane_pitch[0] * - ALIGN(height, y_height_alignment), 4096); - - /* CbCr bitstream stride and plane size */ - layout->plane_pitch[1] = ALIGN(width / 2, uv_stride_alignment); - layout->plane_pitch[1] = (layout->plane_pitch[1] * uv_bpp_numer) - / uv_bpp_denom; - layout->plane_size[1] = ALIGN(layout->plane_pitch[1] * - ALIGN(height / 2, uv_height_alignment), 4096); - - /* Y meta data stride and plane size */ - layout->plane_pitch[2] = ALIGN( - DIV_ROUND_UP(width, y_tile_width), 64); - layout->plane_size[2] = ALIGN(layout->plane_pitch[2] * - ALIGN(DIV_ROUND_UP(height, y_tile_height), 16), 4096); - - /* CbCr meta data stride and plane size */ - layout->plane_pitch[3] = ALIGN( - DIV_ROUND_UP(width / 2, uv_tile_width), 64); - layout->plane_size[3] = ALIGN(layout->plane_pitch[3] * - ALIGN(DIV_ROUND_UP(height / 2, uv_tile_height), 16), - 4096); - - } else if (fmt->base.pixel_format == DRM_FORMAT_ABGR8888 || - fmt->base.pixel_format == DRM_FORMAT_XBGR8888 || - fmt->base.pixel_format == DRM_FORMAT_BGRA1010102 || - fmt->base.pixel_format == DRM_FORMAT_BGRX1010102 || - fmt->base.pixel_format == DRM_FORMAT_BGR565) { - - uint32_t stride_alignment, aligned_bitstream_width; - - if (fmt->base.pixel_format == DRM_FORMAT_BGR565) - stride_alignment = 128; - else - stride_alignment = 64; - layout->num_planes = 3; + layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); + y_sclines = VENUS_Y_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + y_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); + uv_sclines = VENUS_UV_SCANLINES(color, height); + layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * + uv_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + y_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); + layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * + uv_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); - /* Nothing in plane[1] */ + } else { + uint32_t rgb_scanlines, rgb_meta_scanlines; - /* RGB bitstream stride and plane size */ - aligned_bitstream_width = ALIGN(width, stride_alignment); - layout->plane_pitch[0] = aligned_bitstream_width * fmt->bpp; - layout->plane_size[0] = ALIGN(fmt->bpp * aligned_bitstream_width - * ALIGN(height, 16), 4096); + layout->num_planes = 3; - /* RGB meta data stride and plane size */ - layout->plane_pitch[2] = ALIGN(DIV_ROUND_UP( - aligned_bitstream_width, 16), 64); - layout->plane_size[2] = ALIGN(layout->plane_pitch[2] * - ALIGN(DIV_ROUND_UP(height, 4), 16), 4096); - } else { - DRM_ERROR("UBWC format not supported for fmt:0x%X\n", - fmt->base.pixel_format); - return -EINVAL; + layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); + rgb_scanlines = VENUS_RGB_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + rgb_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); + rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + rgb_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); } for (i = 0; i < SDE_MAX_PLANES; i++) @@ -574,6 +629,7 @@ static int _sde_format_get_plane_sizes_linear( } else { uint32_t v_subsample, h_subsample; uint32_t chroma_samp; + uint32_t bpp = 1; chroma_samp = fmt->chroma_sample; _sde_get_v_h_subsample_rate(chroma_samp, &v_subsample, @@ -584,8 +640,11 @@ static int _sde_format_get_plane_sizes_linear( return -EINVAL; } - layout->plane_pitch[0] = width; - layout->plane_pitch[1] = width / h_subsample; + if ((fmt->base.pixel_format == DRM_FORMAT_NV12) && + (SDE_FORMAT_IS_DX(fmt))) + bpp = 2; + layout->plane_pitch[0] = width * bpp; + layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; layout->plane_size[0] = layout->plane_pitch[0] * height; layout->plane_size[1] = layout->plane_pitch[1] * (height / v_subsample); @@ -874,7 +933,8 @@ int sde_format_check_modified_format( DRM_ERROR("invalid handle for plane %d\n", i); return -EINVAL; } - bos_total_size += bos[i]->size; + if ((i == 0) || (bos[i] != bos[0])) + bos_total_size += bos[i]->size; } if (bos_total_size < layout.total_size) { @@ -926,6 +986,23 @@ const struct sde_format *sde_get_sde_format_ext( map_size = ARRAY_SIZE(sde_format_map_ubwc); DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED", format); break; + case DRM_FORMAT_MOD_QCOM_DX: + map = sde_format_map_p010; + map_size = ARRAY_SIZE(sde_format_map_p010); + DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_DX", format); + break; + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED): + map = sde_format_map_p010_ubwc; + map_size = ARRAY_SIZE(sde_format_map_p010_ubwc); + DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED/DX", format); + break; + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_TIGHT): + map = sde_format_map_tp10_ubwc; + map_size = ARRAY_SIZE(sde_format_map_tp10_ubwc); + DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED/DX/TIGHT", + format); + break; default: DRM_ERROR("unsupported format modifier %llX\n", mod0); return NULL; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 17b678cfca46..4f84e31db5f6 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -405,6 +405,38 @@ static struct sde_prop_type vbif_prop[] = { /************************************************************* * static API list *************************************************************/ + +/** + * _sde_copy_formats - copy formats from src_list to dst_list + * @dst_list: pointer to destination list where to copy formats + * @dst_list_size: size of destination list + * @dst_list_pos: starting position on the list where to copy formats + * @src_list: pointer to source list where to copy formats from + * @src_list_size: size of source list + * Return: number of elements populated + */ +static uint32_t _sde_copy_formats( + struct sde_format_extended *dst_list, + uint32_t dst_list_size, + uint32_t dst_list_pos, + const struct sde_format_extended *src_list, + uint32_t src_list_size) +{ + uint32_t cur_pos, i; + + if (!dst_list || !src_list || (dst_list_pos >= (dst_list_size - 1))) + return 0; + + for (i = 0, cur_pos = dst_list_pos; + (cur_pos < (dst_list_size - 1)) && src_list[i].fourcc_format + && (i < src_list_size); ++i, ++cur_pos) + dst_list[cur_pos] = src_list[i]; + + dst_list[cur_pos].fourcc_format = 0; + + return i; +} + static int _parse_dt_u32_handler(struct device_node *np, char *prop_name, u32 *offsets, int len, bool mandatory) { @@ -658,7 +690,7 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg, sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; sspp->id = SSPP_VIG0 + *vig_count; sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count; - sblk->format_list = plane_formats_yuv; + sspp->type = SSPP_TYPE_VIG; set_bit(SDE_SSPP_QOS, &sspp->features); (*vig_count)++; @@ -728,7 +760,7 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg, sblk->maxdwnscale = MAX_SSPP_DOWNSCALE; sspp->id = SSPP_RGB0 + *rgb_count; sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count; - sblk->format_list = plane_formats; + sspp->type = SSPP_TYPE_RGB; set_bit(SDE_SSPP_QOS, &sspp->features); (*rgb_count)++; @@ -768,7 +800,7 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg, sblk->maxdwnscale = SSPP_UNITY_SCALE; sspp->id = SSPP_CURSOR0 + *cursor_count; sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count; - sblk->format_list = plane_formats; + sspp->type = SSPP_TYPE_CURSOR; (*cursor_count)++; snprintf(sspp->name, sizeof(sspp->name), "cursor%d", *cursor_count-1); } @@ -781,7 +813,7 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg, sblk->maxdwnscale = SSPP_UNITY_SCALE; sspp->id = SSPP_DMA0 + *dma_count; sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count; - sblk->format_list = plane_formats; + sspp->type = SSPP_TYPE_DMA; set_bit(SDE_SSPP_QOS, &sspp->features); (*dma_count)++; snprintf(sspp->name, sizeof(sspp->name), "dma%d", *dma_count-1); @@ -1258,7 +1290,6 @@ static int sde_wb_parse_dt(struct device_node *np, wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i); wb->vbif_idx = VBIF_NRT; wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0); - wb->format_list = wb2_formats; if (!prop_exists[WB_LEN]) wb->len = DEFAULT_SDE_HW_BLOCK_LEN; sblk->maxlinewidth = sde_cfg->max_wb_linewidth; @@ -1988,9 +2019,124 @@ end: return rc; } -static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, +static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) { + int i, rc = 0; + uint32_t dma_list_size, vig_list_size, wb2_list_size; + uint32_t cursor_list_size = 0; + struct sde_sspp_sub_blks *sblk; + uint32_t index = 0; + + if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300)) { + cursor_list_size = ARRAY_SIZE(cursor_formats); + sde_cfg->cursor_formats = kcalloc(cursor_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->cursor_formats) { + rc = -ENOMEM; + goto end; + } + index = _sde_copy_formats(sde_cfg->cursor_formats, + cursor_list_size, 0, cursor_formats, + ARRAY_SIZE(cursor_formats)); + } + + dma_list_size = ARRAY_SIZE(plane_formats); + vig_list_size = ARRAY_SIZE(plane_formats_yuv); + wb2_list_size = ARRAY_SIZE(wb2_formats); + + dma_list_size += ARRAY_SIZE(rgb_10bit_formats); + vig_list_size += ARRAY_SIZE(rgb_10bit_formats) + + ARRAY_SIZE(tp10_ubwc_formats) + + ARRAY_SIZE(p010_formats); + wb2_list_size += ARRAY_SIZE(rgb_10bit_formats) + + ARRAY_SIZE(tp10_ubwc_formats); + + sde_cfg->dma_formats = kcalloc(dma_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->dma_formats) { + rc = -ENOMEM; + goto end; + } + + sde_cfg->vig_formats = kcalloc(vig_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->vig_formats) { + rc = -ENOMEM; + goto end; + } + + sde_cfg->wb_formats = kcalloc(wb2_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->wb_formats) { + SDE_ERROR("failed to allocate wb format list\n"); + rc = -ENOMEM; + goto end; + } + + index = _sde_copy_formats(sde_cfg->dma_formats, dma_list_size, + 0, plane_formats, ARRAY_SIZE(plane_formats)); + index += _sde_copy_formats(sde_cfg->dma_formats, dma_list_size, + index, rgb_10bit_formats, + ARRAY_SIZE(rgb_10bit_formats)); + + index = _sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + 0, plane_formats_yuv, ARRAY_SIZE(plane_formats_yuv)); + index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + index, rgb_10bit_formats, + ARRAY_SIZE(rgb_10bit_formats)); + index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + index, p010_formats, ARRAY_SIZE(p010_formats)); + + index += _sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + index, tp10_ubwc_formats, + ARRAY_SIZE(tp10_ubwc_formats)); + + index = _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size, + 0, wb2_formats, ARRAY_SIZE(wb2_formats)); + index += _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size, + index, rgb_10bit_formats, + ARRAY_SIZE(rgb_10bit_formats)); + index += _sde_copy_formats(sde_cfg->wb_formats, wb2_list_size, + index, tp10_ubwc_formats, + ARRAY_SIZE(tp10_ubwc_formats)); + + for (i = 0; i < sde_cfg->sspp_count; ++i) { + struct sde_sspp_cfg *sspp = &sde_cfg->sspp[i]; + + sblk = (struct sde_sspp_sub_blks *)sspp->sblk; + switch (sspp->type) { + case SSPP_TYPE_VIG: + sblk->format_list = sde_cfg->vig_formats; + break; + case SSPP_TYPE_CURSOR: + if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300)) + sblk->format_list = sde_cfg->cursor_formats; + else + SDE_ERROR("invalid sspp type %d, xin id %d\n", + sspp->type, sspp->xin_id); + break; + case SSPP_TYPE_DMA: + sblk->format_list = sde_cfg->dma_formats; + break; + default: + SDE_ERROR("invalid sspp type %d\n", sspp->type); + rc = -EINVAL; + goto end; + } + } + + for (i = 0; i < sde_cfg->wb_count; ++i) + sde_cfg->wb[i].format_list = sde_cfg->wb_formats; + +end: + return rc; +} + +static int sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) +{ + int rc = 0; + switch (hw_rev) { case SDE_HW_VER_170: case SDE_HW_VER_171: @@ -1998,10 +2144,14 @@ static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, /* update msm8996 target here */ break; case SDE_HW_VER_300: + case SDE_HW_VER_301: case SDE_HW_VER_400: /* update cobalt and skunk target here */ + rc = sde_hardware_format_caps(sde_cfg, hw_rev); break; } + + return rc; } void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg) @@ -2040,6 +2190,11 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg) } } + kfree(sde_cfg->dma_formats); + kfree(sde_cfg->cursor_formats); + kfree(sde_cfg->vig_formats); + kfree(sde_cfg->wb_formats); + kfree(sde_cfg); } @@ -2109,7 +2264,9 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, if (rc) SDE_DEBUG("virtual plane is not supported.\n"); - sde_hardware_caps(sde_cfg, hw_rev); + rc = sde_hardware_caps(sde_cfg, hw_rev); + if (rc) + goto end; return sde_cfg; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index bca221d2a959..01204df48871 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -42,7 +42,8 @@ #define SDE_HW_VER_170 SDE_HW_VER(1, 7, 0) /* 8996 v1.0 */ #define SDE_HW_VER_171 SDE_HW_VER(1, 7, 1) /* 8996 v2.0 */ #define SDE_HW_VER_172 SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */ -#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* cobalt v1.0 */ +#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */ +#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */ #define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* msmskunk v1.0 */ #define IS_MSMSKUNK_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400) @@ -457,7 +458,8 @@ struct sde_ctl_cfg { * @sblk: SSPP sub-blocks information * @xin_id: bus client identifier * @clk_ctrl clock control identifier - *@name source pipe name + * @name source pipe name + * @type sspp type identifier */ struct sde_sspp_cfg { SDE_HW_BLK_INFO; @@ -465,6 +467,7 @@ struct sde_sspp_cfg { u32 xin_id; enum sde_clk_ctrl_type clk_ctrl; char name[SSPP_NAME_SIZE]; + u32 type; }; /** @@ -652,6 +655,10 @@ struct sde_vp_cfg { * @csc_type csc or csc_10bit support. * @has_src_split source split feature status * @has_cdp Client driver prefetch feature status + * @dma_formats Supported formats for dma pipe + * @cursor_formats Supported formats for cursor pipe + * @vig_formats Supported formats for vig pipe + * @wb_formats Supported formats for wb */ struct sde_mdss_cfg { u32 hwversion; @@ -704,6 +711,11 @@ struct sde_mdss_cfg { u32 vp_count; struct sde_vp_cfg vp[MAX_BLOCKS]; + + struct sde_format_extended *dma_formats; + struct sde_format_extended *cursor_formats; + struct sde_format_extended *vig_formats; + struct sde_format_extended *wb_formats; }; struct sde_mdss_hw_cfg_handler { diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h index 296694422653..dbc8981a7f8f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,17 +16,17 @@ static const struct sde_format_extended plane_formats[] = { {DRM_FORMAT_ARGB8888, 0}, {DRM_FORMAT_ABGR8888, 0}, {DRM_FORMAT_RGBA8888, 0}, - {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_BGRA8888, 0}, {DRM_FORMAT_XRGB8888, 0}, {DRM_FORMAT_RGBX8888, 0}, {DRM_FORMAT_BGRX8888, 0}, {DRM_FORMAT_XBGR8888, 0}, - {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_RGB888, 0}, {DRM_FORMAT_BGR888, 0}, {DRM_FORMAT_RGB565, 0}, - {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_BGR565, 0}, {DRM_FORMAT_ARGB1555, 0}, {DRM_FORMAT_ABGR1555, 0}, @@ -52,16 +52,16 @@ static const struct sde_format_extended plane_formats_yuv[] = { {DRM_FORMAT_ABGR8888, 0}, {DRM_FORMAT_RGBA8888, 0}, {DRM_FORMAT_BGRX8888, 0}, - {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_BGRA8888, 0}, {DRM_FORMAT_XRGB8888, 0}, {DRM_FORMAT_XBGR8888, 0}, {DRM_FORMAT_RGBX8888, 0}, - {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_RGB888, 0}, {DRM_FORMAT_BGR888, 0}, {DRM_FORMAT_RGB565, 0}, - {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_BGR565, 0}, {DRM_FORMAT_ARGB1555, 0}, {DRM_FORMAT_ABGR1555, 0}, @@ -94,13 +94,33 @@ static const struct sde_format_extended plane_formats_yuv[] = { {0, 0}, }; +static const struct sde_format_extended cursor_formats[] = { + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {0, 0}, +}; + static const struct sde_format_extended wb2_formats[] = { {DRM_FORMAT_RGB565, 0}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_RGB888, 0}, {DRM_FORMAT_ARGB8888, 0}, {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_XRGB8888, 0}, {DRM_FORMAT_RGBX8888, 0}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_ARGB1555, 0}, {DRM_FORMAT_RGBA5551, 0}, {DRM_FORMAT_XRGB1555, 0}, @@ -127,8 +147,31 @@ static const struct sde_format_extended wb2_formats[] = { {DRM_FORMAT_YUV420, 0}, {DRM_FORMAT_NV12, 0}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, {DRM_FORMAT_NV16, 0}, {DRM_FORMAT_YUYV, 0}, {0, 0}, }; + +static const struct sde_format_extended rgb_10bit_formats[] = { + {DRM_FORMAT_BGRA1010102, 0}, + {DRM_FORMAT_BGRX1010102, 0}, + {DRM_FORMAT_RGBA1010102, 0}, + {DRM_FORMAT_RGBX1010102, 0}, + {DRM_FORMAT_ABGR2101010, 0}, + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XBGR2101010, 0}, + {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ARGB2101010, 0}, + {DRM_FORMAT_XRGB2101010, 0}, +}; + +static const struct sde_format_extended p010_formats[] = { + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_DX}, +}; + +static const struct sde_format_extended tp10_ubwc_formats[] = { + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT}, +}; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index dcba248d27b0..7a5e7ad79f0f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -41,11 +41,18 @@ #define SDE_MAX_DE_CURVES 3 #endif -#define SDE_FORMAT_FLAG_YUV (1 << 0) -#define SDE_FORMAT_FLAG_DX (1 << 1) +enum sde_format_flags { + SDE_FORMAT_FLAG_YUV_BIT, + SDE_FORMAT_FLAG_DX_BIT, + SDE_FORMAT_FLAG_BIT_MAX, +}; -#define SDE_FORMAT_IS_YUV(X) ((X)->flag & SDE_FORMAT_FLAG_YUV) -#define SDE_FORMAT_IS_DX(X) ((X)->flag & SDE_FORMAT_FLAG_DX) +#define SDE_FORMAT_FLAG_YUV BIT(SDE_FORMAT_FLAG_YUV_BIT) +#define SDE_FORMAT_FLAG_DX BIT(SDE_FORMAT_FLAG_DX_BIT) +#define SDE_FORMAT_IS_YUV(X) \ + (test_bit(SDE_FORMAT_FLAG_YUV_BIT, (X)->flag)) +#define SDE_FORMAT_IS_DX(X) \ + (test_bit(SDE_FORMAT_FLAG_DX_BIT, (X)->flag)) #define SDE_FORMAT_IS_LINEAR(X) ((X)->fetch_mode == SDE_FETCH_LINEAR) #define SDE_FORMAT_IS_UBWC(X) ((X)->fetch_mode == SDE_FETCH_UBWC) @@ -357,7 +364,7 @@ struct sde_format { u8 alpha_enable; u8 num_planes; enum sde_fetch_type fetch_mode; - u32 flag; + DECLARE_BITMAP(flag, SDE_FORMAT_FLAG_BIT_MAX); u16 tile_width; u16 tile_height; }; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 45a87456e5ec..031493aa42b8 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -601,6 +601,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .mode_valid = sde_hdmi_mode_valid, .get_info = sde_hdmi_get_info, .set_property = sde_hdmi_set_property, + .get_property = sde_hdmi_get_property, + .pre_kickoff = sde_hdmi_pre_kickoff, }; struct msm_display_info info = {0}; struct drm_encoder *encoder; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index 82d3e28918fd..7e4f24ae7de8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -4,6 +4,7 @@ struct nvkm_alarm { struct list_head head; + struct list_head exec; u64 timestamp; void (*func)(struct nvkm_alarm *); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index 79fcdb43e174..46033909d950 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -50,7 +50,8 @@ nvkm_timer_alarm_trigger(struct nvkm_timer *tmr) /* Move to completed list. We'll drop the lock before * executing the callback so it can reschedule itself. */ - list_move_tail(&alarm->head, &exec); + list_del_init(&alarm->head); + list_add(&alarm->exec, &exec); } /* Shut down interrupt if no more pending alarms. */ @@ -59,8 +60,8 @@ nvkm_timer_alarm_trigger(struct nvkm_timer *tmr) spin_unlock_irqrestore(&tmr->lock, flags); /* Execute completed callbacks. */ - list_for_each_entry_safe(alarm, atemp, &exec, head) { - list_del_init(&alarm->head); + list_for_each_entry_safe(alarm, atemp, &exec, exec) { + list_del(&alarm->exec); alarm->func(alarm); } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index b6a0806b06bf..a1c68e6a689e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -368,6 +368,8 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, return fifo_state->static_buffer; else { fifo_state->dynamic_buffer = vmalloc(bytes); + if (!fifo_state->dynamic_buffer) + goto out_err; return fifo_state->dynamic_buffer; } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index c9c04ccccdd9..027987023400 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1288,11 +1288,14 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; int ret; uint32_t size; - uint32_t backup_handle; + uint32_t backup_handle = 0; if (req->multisample_count != 0) return -EINVAL; + if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS) + return -EINVAL; + if (unlikely(vmw_user_surface_size == 0)) vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + 128; @@ -1328,12 +1331,16 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, &res->backup, &user_srf->backup_base); - if (ret == 0 && res->backup->base.num_pages * PAGE_SIZE < - res->backup_size) { - DRM_ERROR("Surface backup buffer is too small.\n"); - vmw_dmabuf_unreference(&res->backup); - ret = -EINVAL; - goto out_unlock; + if (ret == 0) { + if (res->backup->base.num_pages * PAGE_SIZE < + res->backup_size) { + DRM_ERROR("Surface backup buffer is too small.\n"); + vmw_dmabuf_unreference(&res->backup); + ret = -EINVAL; + goto out_unlock; + } else { + backup_handle = req->buffer_handle; + } } } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) ret = vmw_user_dmabuf_alloc(dev_priv, tfile, diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 6bf89d8f3741..b9d1e5c58ec5 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -74,9 +74,9 @@ static const int int_time_mapping[] = {100000, 50000, 200000, 400000}; static const struct reg_field reg_field_it = REG_FIELD(LTR501_ALS_MEAS_RATE, 3, 4); static const struct reg_field reg_field_als_intr = - REG_FIELD(LTR501_INTR, 0, 0); -static const struct reg_field reg_field_ps_intr = REG_FIELD(LTR501_INTR, 1, 1); +static const struct reg_field reg_field_ps_intr = + REG_FIELD(LTR501_INTR, 0, 0); static const struct reg_field reg_field_als_rate = REG_FIELD(LTR501_ALS_MEAS_RATE, 0, 2); static const struct reg_field reg_field_ps_rate = diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index bf0bd7e03aff..9e6d1cdb7fcd 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -40,9 +40,9 @@ #define AS3935_AFE_PWR_BIT BIT(0) #define AS3935_INT 0x03 -#define AS3935_INT_MASK 0x07 +#define AS3935_INT_MASK 0x0f #define AS3935_EVENT_INT BIT(3) -#define AS3935_NOISE_INT BIT(1) +#define AS3935_NOISE_INT BIT(0) #define AS3935_DATA 0x07 #define AS3935_DATA_MASK 0x3F diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index e6b7556d5221..cbc4216091c9 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -2088,8 +2088,10 @@ send_last: ret = qib_get_rwqe(qp, 1); if (ret < 0) goto nack_op_err; - if (!ret) + if (!ret) { + qib_put_ss(&qp->r_sge); goto rnr_nak; + } wc.ex.imm_data = ohdr->u.rc.imm_data; hdrsize += 4; wc.wc_flags = IB_WC_WITH_IMM; diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 1a2b2620421e..6f4dc0fd2ca3 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1122,8 +1122,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * Asus UX32VD 0x361f02 00, 15, 0e clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons @@ -1529,6 +1531,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { + /* Fujitsu LIFEBOOK E546 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E546"), + }, + }, + { /* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), @@ -1550,6 +1559,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { }, }, { + /* Fujitsu LIFEBOOK E557 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E557"), + }, + }, + { /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index daa35845fc0a..93c9c3c373b8 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -1495,7 +1495,7 @@ static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data, return retval; } -static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler, +static int synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler, struct synaptics_rmi4_fn_desc *fd, unsigned int intr_count) { @@ -1503,6 +1503,12 @@ static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler, unsigned char intr_offset; fhandler->intr_reg_num = (intr_count + 7) / 8; + if (fhandler->intr_reg_num >= MAX_INTR_REGISTERS) { + fhandler->intr_reg_num = 0; + fhandler->num_of_data_sources = 0; + fhandler->intr_mask = 0; + return -EINVAL; + } if (fhandler->intr_reg_num != 0) fhandler->intr_reg_num -= 1; @@ -1515,7 +1521,7 @@ static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler, ii++) fhandler->intr_mask |= 1 << ii; - return; + return 0; } static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data, @@ -1523,12 +1529,17 @@ static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_fn_desc *fd, unsigned int intr_count) { + int retval; + fhandler->fn_number = fd->fn_number; fhandler->num_of_data_sources = fd->intr_src_count; fhandler->data = NULL; fhandler->extra = NULL; - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + if (retval < 0) + return retval; + rmi4_data->f01_query_base_addr = fd->query_base_addr; rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr; @@ -1653,7 +1664,9 @@ static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data, if (retval < 0) return retval; - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + if (retval < 0) + return retval; abs_data_size = query[5] & MASK_2BIT; abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0)); @@ -1934,7 +1947,9 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, if (retval < 0) goto free_function_handler_mem; - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + if (retval < 0) + return retval; /* Allocate memory for finger data storage space */ fhandler->data_size = num_of_fingers * size_of_2d_data; @@ -2092,7 +2107,9 @@ static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data, fhandler->fn_number = fd->fn_number; fhandler->num_of_data_sources = fd->intr_src_count; - synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + retval = synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); + if (retval < 0) + return retval; retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler); if (retval < 0) @@ -2491,6 +2508,8 @@ flash_prog_mode: dev_dbg(rmi4_data->pdev->dev.parent, "%s: Number of interrupt registers = %d\n", __func__, rmi4_data->num_of_intr_regs); + if (rmi4_data->num_of_intr_regs >= MAX_INTR_REGISTERS) + return -EINVAL; retval = synaptics_rmi4_reg_read(rmi4_data, rmi4_data->f01_query_base_addr, diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c index 3e2c13b9cbbe..3c2e28eaa4f9 100644 --- a/drivers/media/platform/msm/ais/msm.c +++ b/drivers/media/platform/msm/ais/msm.c @@ -283,22 +283,47 @@ void msm_delete_stream(unsigned int session_id, unsigned int stream_id) struct msm_session *session = NULL; struct msm_stream *stream = NULL; unsigned long flags; + int try_count = 0; session = msm_queue_find(msm_session_q, struct msm_session, list, __msm_queue_find_session, &session_id); + if (!session) return; - stream = msm_queue_find(&session->stream_q, struct msm_stream, - list, __msm_queue_find_stream, &stream_id); - if (!stream) - return; - spin_lock_irqsave(&(session->stream_q.lock), flags); - list_del_init(&stream->list); - session->stream_q.len--; - kfree(stream); - stream = NULL; - spin_unlock_irqrestore(&(session->stream_q.lock), flags); + while (1) { + + if (try_count > 5) { + pr_err("%s : not able to delete stream %d\n", + __func__, __LINE__); + break; + } + + write_lock(&session->stream_rwlock); + try_count++; + stream = msm_queue_find(&session->stream_q, struct msm_stream, + list, __msm_queue_find_stream, &stream_id); + + if (!stream) { + write_unlock(&session->stream_rwlock); + return; + } + + if (msm_vb2_get_stream_state(stream) != 1) { + write_unlock(&session->stream_rwlock); + continue; + } + + spin_lock_irqsave(&(session->stream_q.lock), flags); + list_del_init(&stream->list); + session->stream_q.len--; + kfree(stream); + stream = NULL; + spin_unlock_irqrestore(&(session->stream_q.lock), flags); + write_unlock(&session->stream_rwlock); + break; + } + } EXPORT_SYMBOL(msm_delete_stream); @@ -446,6 +471,7 @@ int msm_create_session(unsigned int session_id, struct video_device *vdev) mutex_init(&session->lock); mutex_init(&session->lock_q); mutex_init(&session->close_lock); + rwlock_init(&session->stream_rwlock); return 0; } EXPORT_SYMBOL(msm_create_session); @@ -1040,17 +1066,25 @@ static struct v4l2_file_operations msm_fops = { #endif }; -struct msm_stream *msm_get_stream(unsigned int session_id, - unsigned int stream_id) +struct msm_session *msm_get_session(unsigned int session_id) { struct msm_session *session; - struct msm_stream *stream; session = msm_queue_find(msm_session_q, struct msm_session, list, __msm_queue_find_session, &session_id); if (!session) return ERR_PTR(-EINVAL); + return session; +} +EXPORT_SYMBOL(msm_get_session); + + +struct msm_stream *msm_get_stream(struct msm_session *session, + unsigned int stream_id) +{ + struct msm_stream *stream; + stream = msm_queue_find(&session->stream_q, struct msm_stream, list, __msm_queue_find_stream, &stream_id); @@ -1108,6 +1142,34 @@ struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) } EXPORT_SYMBOL(msm_get_stream_from_vb2q); +struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q) +{ + struct msm_session *session; + struct msm_stream *stream; + unsigned long flags1; + unsigned long flags2; + + spin_lock_irqsave(&msm_session_q->lock, flags1); + list_for_each_entry(session, &(msm_session_q->list), list) { + spin_lock_irqsave(&(session->stream_q.lock), flags2); + list_for_each_entry( + stream, &(session->stream_q.list), list) { + if (stream->vb2_q == q) { + spin_unlock_irqrestore + (&(session->stream_q.lock), flags2); + spin_unlock_irqrestore + (&msm_session_q->lock, flags1); + return session; + } + } + spin_unlock_irqrestore(&(session->stream_q.lock), flags2); + } + spin_unlock_irqrestore(&msm_session_q->lock, flags1); + return NULL; +} +EXPORT_SYMBOL(msm_get_session_from_vb2q); + + #ifdef CONFIG_COMPAT long msm_copy_camera_private_ioctl_args(unsigned long arg, struct msm_camera_private_ioctl_arg *k_ioctl, diff --git a/drivers/media/platform/msm/ais/msm.h b/drivers/media/platform/msm/ais/msm.h index d8b2d5871fc2..5d456310c301 100644 --- a/drivers/media/platform/msm/ais/msm.h +++ b/drivers/media/platform/msm/ais/msm.h @@ -114,6 +114,7 @@ struct msm_session { struct mutex lock; struct mutex lock_q; struct mutex close_lock; + rwlock_t stream_rwlock; }; static inline bool msm_is_daemon_present(void) @@ -131,11 +132,13 @@ int msm_create_stream(unsigned int session_id, void msm_delete_stream(unsigned int session_id, unsigned int stream_id); int msm_create_command_ack_q(unsigned int session_id, unsigned int stream_id); void msm_delete_command_ack_q(unsigned int session_id, unsigned int stream_id); -struct msm_stream *msm_get_stream(unsigned int session_id, +struct msm_session *msm_get_session(unsigned int session_id); +struct msm_stream *msm_get_stream(struct msm_session *session, unsigned int stream_id); struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, unsigned int stream_id); struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); +struct msm_session *msm_get_session_from_vb2q(struct vb2_queue *q); struct msm_session *msm_session_find(unsigned int session_id); #ifdef CONFIG_COMPAT long msm_copy_camera_private_ioctl_args(unsigned long arg, diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c index 2c1c0a34389a..36aa3f62fbec 100644 --- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.c @@ -44,17 +44,25 @@ static int msm_vb2_queue_setup(struct vb2_queue *q, static int msm_vb2_buf_init(struct vb2_buffer *vb) { struct msm_stream *stream; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return -EINVAL; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s: Couldn't find stream\n", __func__); + read_unlock(&session->stream_rwlock); return -EINVAL; } msm_vb2_buf = container_of(vbuf, struct msm_vb2_buffer, vb2_v4l2_buf); msm_vb2_buf->in_freeq = 0; - + read_unlock(&session->stream_rwlock); return 0; } @@ -62,6 +70,7 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) { struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -71,21 +80,30 @@ static void msm_vb2_buf_queue(struct vb2_buffer *vb) return; } + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return; } spin_lock_irqsave(&stream->stream_lock, flags); list_add_tail(&msm_vb2->list, &stream->queued_list); spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); } static void msm_vb2_buf_finish(struct vb2_buffer *vb) { struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; struct msm_vb2_buffer *msm_vb2_entry, *temp; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -96,9 +114,16 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) return; } + session = msm_get_session_from_vb2q(vb->vb2_queue); + if (IS_ERR_OR_NULL(session)) + return; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(vb->vb2_queue); if (!stream) { pr_err("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return; } @@ -111,18 +136,27 @@ static void msm_vb2_buf_finish(struct vb2_buffer *vb) } } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); } static void msm_vb2_stop_stream(struct vb2_queue *q) { struct msm_vb2_buffer *msm_vb2, *temp; struct msm_stream *stream; + struct msm_session *session; unsigned long flags; struct vb2_v4l2_buffer *vb2_v4l2_buf; + session = msm_get_session_from_vb2q(q); + if (IS_ERR_OR_NULL(session)) + return; + + read_lock(&session->stream_rwlock); + stream = msm_get_stream_from_vb2q(q); if (!stream) { pr_err_ratelimited("%s:%d] NULL stream", __func__, __LINE__); + read_unlock(&session->stream_rwlock); return; } @@ -142,8 +176,28 @@ static void msm_vb2_stop_stream(struct vb2_queue *q) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); } +int msm_vb2_get_stream_state(struct msm_stream *stream) +{ + struct msm_vb2_buffer *msm_vb2, *temp; + unsigned long flags; + int rc = 1; + + spin_lock_irqsave(&stream->stream_lock, flags); + list_for_each_entry_safe(msm_vb2, temp, &(stream->queued_list), list) { + if (msm_vb2->in_freeq != 0) { + rc = 0; + break; + } + } + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} +EXPORT_SYMBOL(msm_vb2_get_stream_state); + + static struct vb2_ops msm_vb2_get_q_op = { .queue_setup = msm_vb2_queue_setup, .buf_init = msm_vb2_buf_init, @@ -199,13 +253,22 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, { struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return NULL; + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return NULL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (!stream->vb2_q) { @@ -228,6 +291,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -236,12 +300,22 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, { struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) + return NULL; + + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); return NULL; + } spin_lock_irqsave(&stream->stream_lock, flags); @@ -263,6 +337,7 @@ static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, vb2_v4l2_buf = NULL; end: spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return vb2_v4l2_buf; } @@ -270,15 +345,24 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id) { struct msm_stream *stream; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; int rc = 0; unsigned long flags; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return -EINVAL; + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (vb) { list_for_each_entry(msm_vb2, &(stream->queued_list), list) { @@ -306,6 +390,7 @@ static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -317,11 +402,21 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_session *session; int rc = 0; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return -EINVAL; + + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (vb) { list_for_each_entry(msm_vb2, &(stream->queued_list), list) { @@ -353,6 +448,7 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, rc = -EINVAL; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return rc; } @@ -361,14 +457,23 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, { struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_session *session; struct msm_vb2_buffer *msm_vb2 = NULL; unsigned long flags; long rc = -EINVAL; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) return rc; + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); + return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); if (!stream->vb2_q) { @@ -394,6 +499,7 @@ long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, end: spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return rc; } EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); @@ -404,10 +510,20 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) struct msm_vb2_buffer *msm_vb2; struct msm_stream *stream; struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_session *session; + + session = msm_get_session(session_id); + if (IS_ERR_OR_NULL(session)) + return -EINVAL; - stream = msm_get_stream(session_id, stream_id); - if (IS_ERR_OR_NULL(stream)) + read_lock(&session->stream_rwlock); + + stream = msm_get_stream(session, stream_id); + if (IS_ERR_OR_NULL(stream)) { + read_unlock(&session->stream_rwlock); return -EINVAL; + } + spin_lock_irqsave(&stream->stream_lock, flags); list_for_each_entry(msm_vb2, &(stream->queued_list), list) { vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf); @@ -416,6 +532,7 @@ static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) msm_vb2->in_freeq = 0; } spin_unlock_irqrestore(&stream->stream_lock, flags); + read_unlock(&session->stream_rwlock); return 0; } diff --git a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h index 3dbb21332857..0f57112e82f2 100644 --- a/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h +++ b/drivers/media/platform/msm/ais/msm_vb2/msm_vb2.h @@ -68,5 +68,6 @@ struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, uint32_t index); +int msm_vb2_get_stream_state(struct msm_stream *stream); #endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index e2f068a21c28..0352ae9cb595 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -2296,6 +2296,8 @@ static void msm_isp_input_disable(struct vfe_device *vfe_dev, int cmd_type) ms_res->src_info[src_info->dual_hw_ms_info.index] = NULL; ms_res->num_src--; + if (ms_res->num_src == 0) + ms_res->dual_sync_mode = MSM_ISP_DUAL_CAM_ASYNC; src_info->dual_hw_ms_info.sync_state = MSM_ISP_DUAL_CAM_ASYNC; src_info->dual_hw_type = DUAL_NONE; diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 5376e1e4b6a4..491b8d31935a 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1144,13 +1144,13 @@ static long msm_flash_subdev_do_ioctl( sd = vdev_to_v4l2_subdev(vdev); u32 = (struct msm_flash_cfg_data_t32 *)arg; - flash_data.cfg_type = u32->cfg_type; - for (i = 0; i < MAX_LED_TRIGGERS; i++) { - flash_data.flash_current[i] = u32->flash_current[i]; - flash_data.flash_duration[i] = u32->flash_duration[i]; - } switch (cmd) { case VIDIOC_MSM_FLASH_CFG32: + flash_data.cfg_type = u32->cfg_type; + for (i = 0; i < MAX_LED_TRIGGERS; i++) { + flash_data.flash_current[i] = u32->flash_current[i]; + flash_data.flash_duration[i] = u32->flash_duration[i]; + } cmd = VIDIOC_MSM_FLASH_CFG; switch (flash_data.cfg_type) { case CFG_FLASH_OFF: diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c index b3e5dc7f9cb8..c5cdee1bf706 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_tz_i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -520,14 +520,16 @@ int32_t msm_camera_tz_i2c_power_up( msm_camera_tz_get_ta_handle(), sensor_id, &sensor_secure); - if (!rc && sensor_secure) + if (!rc && sensor_secure) { /* Sensor validated by TA*/ sensor_info[sensor_id].ready++; + msm_camera_tz_unlock(); + } else { + msm_camera_tz_unlock(); msm_camera_tz_unload_ta(); rc = -EFAULT; } - msm_camera_tz_unlock(); } } else rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c index c94ee509631f..bfb15846e73c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c +++ b/drivers/media/platform/msm/camera_v2/sensor/ois/msm_ois.c @@ -774,11 +774,10 @@ static long msm_ois_subdev_do_ioctl( u32 = (struct msm_ois_cfg_data32 *)arg; parg = arg; - ois_data.cfgtype = u32->cfgtype; - switch (cmd) { case VIDIOC_MSM_OIS_CFG32: cmd = VIDIOC_MSM_OIS_CFG; + ois_data.cfgtype = u32->cfgtype; switch (u32->cfgtype) { case CFG_OIS_CONTROL: @@ -812,7 +811,6 @@ static long msm_ois_subdev_do_ioctl( settings.reg_setting = compat_ptr(settings32.reg_setting); - ois_data.cfgtype = u32->cfgtype; ois_data.cfg.settings = &settings; parg = &ois_data; break; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 62980f345f60..42519be35aa9 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -984,6 +984,7 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr) { int i, size, ret = 0; char name[32]; + struct sched_param param = { .sched_priority = 5 }; size = sizeof(struct sde_rot_queue) * mgr->queue_count; mgr->commitq = devm_kzalloc(mgr->device, size, GFP_KERNEL); @@ -994,11 +995,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr) snprintf(name, sizeof(name), "rot_commitq_%d_%d", mgr->device->id, i); SDEROT_DBG("work queue name=%s\n", name); - mgr->commitq[i].rot_work_queue = - alloc_ordered_workqueue("%s", - WQ_MEM_RECLAIM | WQ_HIGHPRI, name); - if (!mgr->commitq[i].rot_work_queue) { + init_kthread_worker(&mgr->commitq[i].rot_kw); + mgr->commitq[i].rot_thread = kthread_run(kthread_worker_fn, + &mgr->commitq[i].rot_kw, name); + if (IS_ERR(mgr->commitq[i].rot_thread)) { ret = -EPERM; + mgr->commitq[i].rot_thread = NULL; + break; + } + + ret = sched_setscheduler(mgr->commitq[i].rot_thread, + SCHED_FIFO, ¶m); + if (ret) { + SDEROT_ERR( + "failed to set kthread priority for commitq %d\n", + ret); break; } @@ -1015,10 +1026,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr) snprintf(name, sizeof(name), "rot_doneq_%d_%d", mgr->device->id, i); SDEROT_DBG("work queue name=%s\n", name); - mgr->doneq[i].rot_work_queue = alloc_ordered_workqueue("%s", - WQ_MEM_RECLAIM | WQ_HIGHPRI, name); - if (!mgr->doneq[i].rot_work_queue) { + init_kthread_worker(&mgr->doneq[i].rot_kw); + mgr->doneq[i].rot_thread = kthread_run(kthread_worker_fn, + &mgr->doneq[i].rot_kw, name); + if (IS_ERR(mgr->doneq[i].rot_thread)) { ret = -EPERM; + mgr->doneq[i].rot_thread = NULL; + break; + } + + ret = sched_setscheduler(mgr->doneq[i].rot_thread, + SCHED_FIFO, ¶m); + if (ret) { + SDEROT_ERR( + "failed to set kthread priority for doneq %d\n", + ret); break; } @@ -1034,18 +1056,20 @@ static void sde_rotator_deinit_queue(struct sde_rot_mgr *mgr) if (mgr->commitq) { for (i = 0; i < mgr->queue_count; i++) { - if (mgr->commitq[i].rot_work_queue) - destroy_workqueue( - mgr->commitq[i].rot_work_queue); + if (mgr->commitq[i].rot_thread) { + flush_kthread_worker(&mgr->commitq[i].rot_kw); + kthread_stop(mgr->commitq[i].rot_thread); + } } devm_kfree(mgr->device, mgr->commitq); mgr->commitq = NULL; } if (mgr->doneq) { for (i = 0; i < mgr->queue_count; i++) { - if (mgr->doneq[i].rot_work_queue) - destroy_workqueue( - mgr->doneq[i].rot_work_queue); + if (mgr->doneq[i].rot_thread) { + flush_kthread_worker(&mgr->doneq[i].rot_kw); + kthread_stop(mgr->doneq[i].rot_thread); + } } devm_kfree(mgr->device, mgr->doneq); mgr->doneq = NULL; @@ -1166,7 +1190,7 @@ void sde_rotator_queue_request(struct sde_rot_mgr *mgr, if (entry->item.ts) entry->item.ts[SDE_ROTATOR_TS_QUEUE] = ktime_get(); - queue_work(queue->rot_work_queue, &entry->commit_work); + queue_kthread_work(&queue->rot_kw, &entry->commit_work); } } @@ -1377,12 +1401,13 @@ static void sde_rotator_release_entry(struct sde_rot_mgr *mgr, * * Note this asynchronous handler is protected by hal lock. */ -static void sde_rotator_commit_handler(struct work_struct *work) +static void sde_rotator_commit_handler(struct kthread_work *work) { struct sde_rot_entry *entry; struct sde_rot_entry_container *request; struct sde_rot_hw_resource *hw; struct sde_rot_mgr *mgr; + struct sched_param param = { .sched_priority = 5 }; int ret; entry = container_of(work, struct sde_rot_entry, commit_work); @@ -1393,6 +1418,12 @@ static void sde_rotator_commit_handler(struct work_struct *work) return; } + ret = sched_setscheduler(entry->fenceq->rot_thread, SCHED_FIFO, ¶m); + if (ret) { + SDEROT_WARN("Fail to set kthread priority for fenceq: %d\n", + ret); + } + mgr = entry->private->mgr; SDEROT_EVTLOG( @@ -1466,7 +1497,7 @@ static void sde_rotator_commit_handler(struct work_struct *work) if (entry->item.ts) entry->item.ts[SDE_ROTATOR_TS_FLUSH] = ktime_get(); - queue_work(entry->doneq->rot_work_queue, &entry->done_work); + queue_kthread_work(&entry->doneq->rot_kw, &entry->done_work); sde_rot_mgr_unlock(mgr); return; error: @@ -1478,8 +1509,8 @@ get_hw_res_err: sde_rotator_release_entry(mgr, entry); atomic_dec(&request->pending_count); atomic_inc(&request->failed_count); - if (request->retireq && request->retire_work) - queue_work(request->retireq, request->retire_work); + if (request->retire_kw && request->retire_work) + queue_kthread_work(request->retire_kw, request->retire_work); sde_rot_mgr_unlock(mgr); } @@ -1493,7 +1524,7 @@ get_hw_res_err: * * Note this asynchronous handler is protected by hal lock. */ -static void sde_rotator_done_handler(struct work_struct *work) +static void sde_rotator_done_handler(struct kthread_work *work) { struct sde_rot_entry *entry; struct sde_rot_entry_container *request; @@ -1551,8 +1582,8 @@ static void sde_rotator_done_handler(struct work_struct *work) ATRACE_INT("sde_rot_done", 1); sde_rotator_release_entry(mgr, entry); atomic_dec(&request->pending_count); - if (request->retireq && request->retire_work) - queue_work(request->retireq, request->retire_work); + if (request->retire_kw && request->retire_work) + queue_kthread_work(request->retire_kw, request->retire_work); if (entry->item.ts) entry->item.ts[SDE_ROTATOR_TS_RETIRE] = ktime_get(); sde_rot_mgr_unlock(mgr); @@ -1918,8 +1949,10 @@ static int sde_rotator_add_request(struct sde_rot_mgr *mgr, entry->request = req; - INIT_WORK(&entry->commit_work, sde_rotator_commit_handler); - INIT_WORK(&entry->done_work, sde_rotator_done_handler); + init_kthread_work(&entry->commit_work, + sde_rotator_commit_handler); + init_kthread_work(&entry->done_work, + sde_rotator_done_handler); SDEROT_DBG("Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%u\n" "dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->wb_idx, item->src_rect.x, item->src_rect.y, @@ -1957,24 +1990,26 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr, struct sde_rot_entry *entry; int i; - /* - * To avoid signal the rotation entry output fence in the wrong - * order, all the entries in the same request needs to be canceled - * first, before signaling the output fence. - */ - SDEROT_DBG("cancel work start\n"); - sde_rot_mgr_unlock(mgr); - for (i = req->count - 1; i >= 0; i--) { - entry = req->entries + i; - cancel_work_sync(&entry->commit_work); - cancel_work_sync(&entry->done_work); - } - sde_rot_mgr_lock(mgr); - SDEROT_DBG("cancel work done\n"); - for (i = req->count - 1; i >= 0; i--) { - entry = req->entries + i; - sde_rotator_signal_output(entry); - sde_rotator_release_entry(mgr, entry); + if (atomic_read(&req->pending_count)) { + /* + * To avoid signal the rotation entry output fence in the wrong + * order, all the entries in the same request needs to be + * canceled first, before signaling the output fence. + */ + SDEROT_DBG("cancel work start\n"); + sde_rot_mgr_unlock(mgr); + for (i = req->count - 1; i >= 0; i--) { + entry = req->entries + i; + flush_kthread_worker(&entry->commitq->rot_kw); + flush_kthread_worker(&entry->doneq->rot_kw); + } + sde_rot_mgr_lock(mgr); + SDEROT_DBG("cancel work done\n"); + for (i = req->count - 1; i >= 0; i--) { + entry = req->entries + i; + sde_rotator_signal_output(entry); + sde_rotator_release_entry(mgr, entry); + } } list_del_init(&req->list); @@ -1999,7 +2034,7 @@ static void sde_rotator_free_completed_request(struct sde_rot_mgr *mgr, list_for_each_entry_safe(req, req_next, &private->req_list, list) { if ((atomic_read(&req->pending_count) == 0) && - (!req->retire_work && !req->retireq)) { + (!req->retire_work && !req->retire_kw)) { list_del_init(&req->list); devm_kfree(&mgr->pdev->dev, req); } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index 2073c6d9f115..41918dd9b43e 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -21,6 +21,7 @@ #include <linux/types.h> #include <linux/cdev.h> #include <linux/pm_runtime.h> +#include <linux/kthread.h> #include "sde_rotator_base.h" #include "sde_rotator_util.h" @@ -184,7 +185,8 @@ struct sde_rot_hw_resource { }; struct sde_rot_queue { - struct workqueue_struct *rot_work_queue; + struct kthread_worker rot_kw; + struct task_struct *rot_thread; struct sde_rot_timeline *timeline; struct sde_rot_hw_resource *hw; }; @@ -195,8 +197,8 @@ struct sde_rot_entry_container { u32 count; atomic_t pending_count; atomic_t failed_count; - struct workqueue_struct *retireq; - struct work_struct *retire_work; + struct kthread_worker *retire_kw; + struct kthread_work *retire_work; struct sde_rot_entry *entries; }; @@ -205,8 +207,8 @@ struct sde_rot_file_private; struct sde_rot_entry { struct sde_rotation_item item; - struct work_struct commit_work; - struct work_struct done_work; + struct kthread_work commit_work; + struct kthread_work done_work; struct sde_rot_queue *commitq; struct sde_rot_queue *fenceq; struct sde_rot_queue *doneq; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index cfee4efb6f16..4298163e37d5 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -53,8 +53,8 @@ #define SDE_ROTATOR_DEGREE_180 180 #define SDE_ROTATOR_DEGREE_90 90 -static void sde_rotator_submit_handler(struct work_struct *work); -static void sde_rotator_retire_handler(struct work_struct *work); +static void sde_rotator_submit_handler(struct kthread_work *work); +static void sde_rotator_retire_handler(struct kthread_work *work); #ifdef CONFIG_COMPAT static long sde_rotator_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg); @@ -466,8 +466,8 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q) sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private); sde_rot_mgr_unlock(rot_dev->mgr); mutex_unlock(q->lock); - cancel_work_sync(&ctx->submit_work); - cancel_work_sync(&ctx->retire_work); + flush_kthread_work(&ctx->submit_work); + flush_kthread_work(&ctx->retire_work); mutex_lock(q->lock); } @@ -480,7 +480,7 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q) struct sde_rotator_vbinfo *vbinfo = &ctx->vbinfo_cap[i]; - if (vbinfo->fence && vbinfo->fd < 0) { + if (vbinfo->fence) { /* fence is not used */ SDEDEV_DBG(rot_dev->dev, "put fence s:%d t:%d i:%d\n", @@ -765,8 +765,6 @@ static ssize_t sde_rotator_ctx_show(struct kobject *kobj, ctx->format_cap.fmt.pix.sizeimage); SPRINT("abort_pending=%d\n", ctx->abort_pending); SPRINT("command_pending=%d\n", atomic_read(&ctx->command_pending)); - SPRINT("submit_work=%d\n", work_busy(&ctx->submit_work)); - SPRINT("retire_work=%d\n", work_busy(&ctx->retire_work)); SPRINT("sequence=%u\n", sde_rotator_get_timeline_commit_ts(ctx->work_queue.timeline)); SPRINT("timestamp=%u\n", @@ -923,8 +921,8 @@ static int sde_rotator_open(struct file *file) ctx->crop_out.width = 640; ctx->crop_out.height = 480; init_waitqueue_head(&ctx->wait_queue); - INIT_WORK(&ctx->submit_work, sde_rotator_submit_handler); - INIT_WORK(&ctx->retire_work, sde_rotator_retire_handler); + init_kthread_work(&ctx->submit_work, sde_rotator_submit_handler); + init_kthread_work(&ctx->retire_work, sde_rotator_retire_handler); v4l2_fh_init(&ctx->fh, video); file->private_data = &ctx->fh; @@ -954,14 +952,16 @@ static int sde_rotator_open(struct file *file) snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id, ctx->session_id); - ctx->work_queue.rot_work_queue = alloc_ordered_workqueue("%s", - WQ_MEM_RECLAIM | WQ_HIGHPRI, name); - if (!ctx->work_queue.rot_work_queue) { - SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate workqueue\n"); + init_kthread_worker(&ctx->work_queue.rot_kw); + ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn, + &ctx->work_queue.rot_kw, name); + if (IS_ERR(ctx->work_queue.rot_thread)) { + SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n"); ret = -EPERM; + ctx->work_queue.rot_thread = NULL; goto error_alloc_workqueue; } - SDEDEV_DBG(ctx->rot_dev->dev, "work queue name=%s\n", name); + SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name); snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id, ctx->session_id); @@ -1010,7 +1010,8 @@ error_ctrl_handler: error_open_session: sde_rot_mgr_unlock(rot_dev->mgr); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - destroy_workqueue(ctx->work_queue.rot_work_queue); + flush_kthread_worker(&ctx->work_queue.rot_kw); + kthread_stop(ctx->work_queue.rot_thread); error_alloc_workqueue: sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); error_create_sysfs: @@ -1045,20 +1046,17 @@ static int sde_rotator_release(struct file *file) v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); mutex_unlock(&rot_dev->lock); - SDEDEV_DBG(rot_dev->dev, "release submit work s:%d w:%x\n", - session_id, work_busy(&ctx->submit_work)); - cancel_work_sync(&ctx->submit_work); + SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id); + flush_kthread_worker(&ctx->work_queue.rot_kw); SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id); sde_rot_mgr_lock(rot_dev->mgr); sde_rotator_session_close(rot_dev->mgr, ctx->private, session_id); sde_rot_mgr_unlock(rot_dev->mgr); - SDEDEV_DBG(rot_dev->dev, "release retire work s:%d w:%x\n", - session_id, work_busy(&ctx->retire_work)); - cancel_work_sync(&ctx->retire_work); + SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", session_id); mutex_lock(&rot_dev->lock); SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - destroy_workqueue(ctx->work_queue.rot_work_queue); + kthread_stop(ctx->work_queue.rot_thread); sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); kobject_put(&ctx->kobj); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); @@ -1459,7 +1457,7 @@ static int sde_rotator_dqbuf(struct file *file, && (buf->index < ctx->nbuf_cap)) { int idx = buf->index; - if (ctx->vbinfo_cap[idx].fence && ctx->vbinfo_cap[idx].fd < 0) { + if (ctx->vbinfo_cap[idx].fence) { /* fence is not used */ SDEDEV_DBG(ctx->rot_dev->dev, "put fence s:%d i:%d\n", ctx->session_id, idx); @@ -1856,6 +1854,7 @@ static long sde_rotator_private_ioctl(struct file *file, void *fh, ctx->session_id); return vbinfo->fd; } + vbinfo->fence = NULL; } fence->fd = vbinfo->fd; @@ -2023,7 +2022,7 @@ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { * * This function is scheduled in work queue context. */ -static void sde_rotator_retire_handler(struct work_struct *work) +static void sde_rotator_retire_handler(struct kthread_work *work) { struct vb2_v4l2_buffer *src_buf; struct vb2_v4l2_buffer *dst_buf; @@ -2209,7 +2208,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx, goto error_init_request; } - req->retireq = ctx->work_queue.rot_work_queue; + req->retire_kw = &ctx->work_queue.rot_kw; req->retire_work = &ctx->retire_work; ret = sde_rotator_handle_request_common( @@ -2238,7 +2237,7 @@ error_null_buffer: * * This function is scheduled in work queue context. */ -static void sde_rotator_submit_handler(struct work_struct *work) +static void sde_rotator_submit_handler(struct kthread_work *work) { struct sde_rotator_ctx *ctx; struct sde_rotator_device *rot_dev; @@ -2325,7 +2324,7 @@ static void sde_rotator_device_run(void *priv) /* disconnect request (will be freed by core layer) */ sde_rot_mgr_lock(rot_dev->mgr); - ctx->request->retireq = NULL; + ctx->request->retire_kw = NULL; ctx->request->retire_work = NULL; ctx->request = NULL; sde_rot_mgr_unlock(rot_dev->mgr); @@ -2364,7 +2363,7 @@ static void sde_rotator_device_run(void *priv) /* disconnect request (will be freed by core layer) */ sde_rot_mgr_lock(rot_dev->mgr); - ctx->request->retireq = NULL; + ctx->request->retire_kw = NULL; ctx->request->retire_work = NULL; ctx->request = ERR_PTR(-EIO); sde_rot_mgr_unlock(rot_dev->mgr); @@ -2471,7 +2470,7 @@ static int sde_rotator_job_ready(void *priv) v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx), atomic_read(&ctx->command_pending)); atomic_inc(&ctx->command_pending); - queue_work(ctx->work_queue.rot_work_queue, &ctx->submit_work); + queue_kthread_work(&ctx->work_queue.rot_kw, &ctx->submit_work); } else if (!atomic_read(&ctx->request->pending_count)) { /* if pending request completed, forward to device run state */ SDEDEV_DBG(rot_dev->dev, diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h index c8dcdeee9ca0..8e4d86083508 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #include <linux/iommu.h> #include <linux/dma-buf.h> #include <linux/msm-bus.h> +#include <linux/kthread.h> #include <media/v4l2-device.h> #include <media/v4l2-fh.h> #include <media/v4l2-ctrls.h> @@ -131,8 +132,8 @@ struct sde_rotator_ctx { struct sde_rotator_vbinfo *vbinfo_cap; struct sde_rotator_vbinfo *vbinfo_out; wait_queue_head_t wait_queue; - struct work_struct submit_work; - struct work_struct retire_work; + struct kthread_work submit_work; + struct kthread_work retire_work; struct sde_rot_queue work_queue; struct sde_rot_entry_container *request; struct sde_rot_file_private *private; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c index 3e269576c126..9bc313adb10a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_dcvs.c @@ -407,8 +407,10 @@ static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst) if (dcvs->etb_counter < total_input_buf) { dcvs->etb_counter++; - if (dcvs->etb_counter != total_input_buf) - return rc; + if (dcvs->etb_counter != total_input_buf) { + return msm_comm_scale_clocks_load(core, dcvs->load, + LOAD_CALC_NO_QUIRKS); + } } dprintk(VIDC_PROF, @@ -425,7 +427,7 @@ static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst) } if (fw_pending_bufs >= DCVS_ENC_HIGH_THR && - dcvs->load <= dcvs->load_low) { + dcvs->load < dcvs->load_high) { dcvs->load = dcvs->load_high; dcvs->prev_freq_increased = true; } else { diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 783337d22f36..10a02934bfc0 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -158,11 +158,8 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, /* Do this outside the status_mutex to avoid a circular dependency with * the locking in cxl_mmap_fault() */ - if (copy_from_user(&work, uwork, - sizeof(struct cxl_ioctl_start_work))) { - rc = -EFAULT; - goto out; - } + if (copy_from_user(&work, uwork, sizeof(work))) + return -EFAULT; mutex_lock(&ctx->status_mutex); if (ctx->status != OPENED) { diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 500185546599..7cdcd69cecf4 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4379,9 +4379,9 @@ int qseecom_start_app(struct qseecom_handle **handle, return -EINVAL; } - if (strlen(app_name) >= MAX_APP_NAME_SIZE) { + if (strnlen(app_name, MAX_APP_NAME_SIZE) == MAX_APP_NAME_SIZE) { pr_err("The app_name (%s) with length %zu is not valid\n", - app_name, strlen(app_name)); + app_name, strnlen(app_name, MAX_APP_NAME_SIZE)); return -EINVAL; } diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 091370f4ea40..3c9d311106cd 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -94,7 +94,7 @@ static struct uid_entry *find_or_register_uid(uid_t uid) static int uid_cputime_show(struct seq_file *m, void *v) { - struct uid_entry *uid_entry; + struct uid_entry *uid_entry = NULL; struct task_struct *task, *temp; struct user_namespace *user_ns = current_user_ns(); cputime_t utime; @@ -112,7 +112,8 @@ static int uid_cputime_show(struct seq_file *m, void *v) read_lock(&tasklist_lock); do_each_thread(temp, task) { uid = from_kuid_munged(user_ns, task_uid(task)); - uid_entry = find_or_register_uid(uid); + if (!uid_entry || uid_entry->uid != uid) + uid_entry = find_or_register_uid(uid); if (!uid_entry) { read_unlock(&tasklist_lock); rt_mutex_unlock(&uid_lock); @@ -251,7 +252,7 @@ static void compute_uid_io_bucket_stats(struct io_stats *io_bucket, static void update_io_stats_all_locked(void) { - struct uid_entry *uid_entry; + struct uid_entry *uid_entry = NULL; struct task_struct *task, *temp; struct user_namespace *user_ns = current_user_ns(); unsigned long bkt; @@ -264,7 +265,8 @@ static void update_io_stats_all_locked(void) rcu_read_lock(); do_each_thread(temp, task) { uid = from_kuid_munged(user_ns, task_uid(task)); - uid_entry = find_or_register_uid(uid); + if (!uid_entry || uid_entry->uid != uid) + uid_entry = find_or_register_uid(uid); if (!uid_entry) continue; add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index c82ab87fcbe8..e5911ccb2148 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1949,7 +1949,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, } /* select a non-FCoE queue */ - return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp); + return fallback(dev, skb) % (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos); } void bnx2x_set_num_queues(struct bnx2x *bp) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 0d147610a06f..090e00650601 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2714,10 +2714,14 @@ static int cxgb_up(struct adapter *adap) if (err) goto irq_err; } + + mutex_lock(&uld_mutex); enable_rx(adap); t4_sge_start(adap); t4_intr_enable(adap); adap->flags |= FULL_INIT_DONE; + mutex_unlock(&uld_mutex); + notify_ulds(adap, CXGB4_STATE_UP); #if IS_ENABLED(CONFIG_IPV6) update_clip(adap); diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index ff665493ca97..52f2230062e7 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -713,6 +713,8 @@ static int ethoc_open(struct net_device *dev) if (ret) return ret; + napi_enable(&priv->napi); + ethoc_init_ring(priv, dev->mem_start); ethoc_reset(priv); @@ -725,7 +727,6 @@ static int ethoc_open(struct net_device *dev) } phy_start(priv->phy); - napi_enable(&priv->napi); if (netif_msg_ifup(priv)) { dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n", diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 590750ab6564..9a986ccd42e5 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -77,6 +77,8 @@ static const u8 all_zeros_mac[ETH_ALEN]; static int vxlan_sock_add(struct vxlan_dev *vxlan); +static void vxlan_vs_del_dev(struct vxlan_dev *vxlan); + /* per-network namespace private data for this module */ struct vxlan_net { struct list_head vxlan_list; @@ -1052,6 +1054,8 @@ static void __vxlan_sock_release(struct vxlan_sock *vs) static void vxlan_sock_release(struct vxlan_dev *vxlan) { + vxlan_vs_del_dev(vxlan); + __vxlan_sock_release(vxlan->vn4_sock); #if IS_ENABLED(CONFIG_IPV6) __vxlan_sock_release(vxlan->vn6_sock); @@ -2255,6 +2259,15 @@ static void vxlan_cleanup(unsigned long arg) mod_timer(&vxlan->age_timer, next_timer); } +static void vxlan_vs_del_dev(struct vxlan_dev *vxlan) +{ + struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); + + spin_lock(&vn->sock_lock); + hlist_del_init_rcu(&vxlan->hlist); + spin_unlock(&vn->sock_lock); +} + static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); @@ -3028,12 +3041,6 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, static void vxlan_dellink(struct net_device *dev, struct list_head *head) { struct vxlan_dev *vxlan = netdev_priv(dev); - struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); - - spin_lock(&vn->sock_lock); - if (!hlist_unhashed(&vxlan->hlist)) - hlist_del_rcu(&vxlan->hlist); - spin_unlock(&vn->sock_lock); gro_cells_destroy(&vxlan->gro_cells); list_del(&vxlan->next); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 95412139e7f6..6906bddb229f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1550,6 +1550,7 @@ static void ath10k_core_restart(struct work_struct *work) complete(&ar->offchan_tx_completed); complete(&ar->install_key_done); complete(&ar->vdev_setup_done); + complete(&ar->vdev_delete_done); complete(&ar->thermal.wmi_sync); complete(&ar->bss_survey_done); wake_up(&ar->htt.empty_tx_wq); @@ -2373,6 +2374,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); init_completion(&ar->thermal.wmi_sync); init_completion(&ar->bss_survey_done); init_completion(&ar->peer_delete_done); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fa2e226ec085..8ddbae96794d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -365,7 +365,8 @@ struct ath10k_sta { #endif }; -#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +#define ATH10K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ) enum ath10k_beacon_state { ATH10K_BEACON_SCHEDULED = 0, @@ -853,6 +854,7 @@ struct ath10k { struct completion install_key_done; struct completion vdev_setup_done; + struct completion vdev_delete_done; struct workqueue_struct *workqueue; /* Auxiliary workqueue */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0f0826291ab4..24485466704b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -994,6 +994,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { @@ -1043,6 +1044,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ar->monitor_vdev_id, ret); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) @@ -1349,6 +1351,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { @@ -1385,6 +1388,7 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); arg.vdev_id = arvif->vdev_id; arg.dtim_period = arvif->dtim_period; @@ -5123,6 +5127,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_peer *peer; + unsigned long time_left; int ret; int i; @@ -5162,6 +5167,16 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); + if (QCA_REV_WCN3990(ar)) { + time_left = wait_for_completion_timeout( + &ar->vdev_delete_done, + ATH10K_VDEV_DELETE_TIMEOUT_HZ); + if (time_left == 0) { + ath10k_warn(ar, "Timeout in receiving vdev delete resp\n"); + return; + } + } + /* Some firmware revisions don't notify host about self-peer removal * until after associated vdev is deleted. */ @@ -5215,6 +5230,26 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static int ath10k_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + struct ath10k *ar = hw->priv; + int ret = 0; + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "change_interface new: %d (%d), old: %d (%d)\n", new_type, + p2p, vif->type, vif->p2p); + + if (new_type != vif->type || vif->p2p != p2p) { + ath10k_remove_interface(hw, vif); + vif->type = new_type; + vif->p2p = p2p; + ret = ath10k_add_interface(hw, vif); + } + return ret; +} + /* * FIXME: Has to be verified. */ @@ -7456,6 +7491,7 @@ static const struct ieee80211_ops ath10k_ops = { .stop = ath10k_stop, .config = ath10k_config, .add_interface = ath10k_add_interface, + .change_interface = ath10k_change_interface, .remove_interface = ath10k_remove_interface, .configure_filter = ath10k_configure_filter, .bss_info_changed = ath10k_bss_info_changed, @@ -7752,6 +7788,81 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { }, }; +static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit ath10k_wcn3990_qcs_if_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit ath10k_wcn3990_if_limit_ibss[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +static struct ieee80211_iface_combination ath10k_wcn3990_qcs_if_comb[] = { + { + .limits = ath10k_wcn3990_if_limit, + .num_different_channels = 1, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_wcn3990_if_limit), + }, + { + .limits = ath10k_wcn3990_qcs_if_limit, + .num_different_channels = 2, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_wcn3990_qcs_if_limit), + }, + { + .limits = ath10k_wcn3990_if_limit_ibss, + .num_different_channels = 1, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(ath10k_wcn3990_if_limit_ibss), + }, +}; + static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { { .max = 1, @@ -7983,6 +8094,14 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); break; case ATH10K_FW_WMI_OP_VERSION_TLV: + ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + if (QCA_REV_WCN3990(ar)) { + ar->hw->wiphy->iface_combinations = + ath10k_wcn3990_qcs_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_wcn3990_qcs_if_comb); + break; + } if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { ar->hw->wiphy->iface_combinations = ath10k_tlv_qcs_if_comb; @@ -7993,7 +8112,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_tlv_if_comb); } - ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 36026a15f721..1544eb175c7f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -477,6 +477,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_VDEV_STOPPED_EVENTID: ath10k_wmi_event_vdev_stopped(ar, skb); break; + case WMI_TLV_VDEV_DELETE_RESP_EVENTID: + ath10k_wmi_event_vdev_delete_resp(ar, skb); + break; case WMI_TLV_PEER_STA_KICKOUT_EVENTID: ath10k_wmi_event_peer_sta_kickout(ar, skb); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index f8139bcf79cc..86b24c24d9f1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -308,6 +308,8 @@ enum wmi_tlv_event_id { WMI_TLV_VDEV_STOPPED_EVENTID, WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + WMI_TLV_VDEV_TSF_REPORT_EVENTID, + WMI_TLV_VDEV_DELETE_RESP_EVENTID, WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), WMI_TLV_PEER_INFO_EVENTID, WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cbbba8d79e6b..c36b0fc435d4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3120,6 +3120,12 @@ void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb) complete(&ar->vdev_setup_done); } +void ath10k_wmi_event_vdev_delete_resp(struct ath10k *ar, struct sk_buff *skb) +{ + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_DELETE_RESP_EVENTID\n"); + complete(&ar->vdev_delete_done); +} + static int ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_peer_kick_ev_arg *arg) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 74398b45e365..13cac69581d6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6599,6 +6599,7 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_delete_resp(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb); diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 48d358c4722a..22c59d8c3c45 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -134,6 +134,7 @@ static DEFINE_SPINLOCK(pci_link_down_lock); #define FW_IMAGE_MISSION (0x02) #define FW_IMAGE_BDATA (0x03) #define FW_IMAGE_PRINT (0x04) +#define FW_SETUP_DELAY 2000 #define SEG_METADATA (0x01) #define SEG_NON_PAGED (0x02) @@ -244,7 +245,7 @@ static struct cnss_data { struct pci_saved_state *saved_state; u16 revision_id; bool recovery_in_progress; - bool fw_available; + atomic_t fw_available; struct codeswap_codeseg_info *cnss_seg_info; /* Virtual Address of the DMA page */ void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS]; @@ -273,6 +274,10 @@ static struct cnss_data { u32 fw_dma_size; u32 fw_seg_count; struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS]; + atomic_t fw_store_in_progress; + /* Firmware setup complete lock */ + struct mutex fw_setup_stat_lock; + struct completion fw_setup_complete; void *bdata_cpu; dma_addr_t bdata_dma; u32 bdata_dma_size; @@ -1369,10 +1374,21 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info) !penv->fw_seg_count || !penv->bdata_seg_count) return -EINVAL; + /* Check for firmware setup trigger by usersapce is in progress + * and wait for complition of firmware setup. + */ + + if (atomic_read(&penv->fw_store_in_progress)) { + wait_for_completion_timeout(&penv->fw_setup_complete, + msecs_to_jiffies(FW_SETUP_DELAY)); + } + + mutex_lock(&penv->fw_setup_stat_lock); image_desc_info->fw_addr = penv->fw_dma; image_desc_info->fw_size = penv->fw_dma_size; image_desc_info->bdata_addr = penv->bdata_dma; image_desc_info->bdata_size = penv->bdata_dma_size; + mutex_unlock(&penv->fw_setup_stat_lock); return 0; } @@ -1552,7 +1568,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, penv->pdev = pdev; penv->id = id; - penv->fw_available = false; + atomic_set(&penv->fw_available, 0); penv->device_id = pdev->device; if (penv->smmu_iova_len) { @@ -1858,8 +1874,19 @@ static ssize_t fw_image_setup_store(struct device *dev, if (!penv) return -ENODEV; - if (sscanf(buf, "%d", &val) != 1) + if (atomic_read(&penv->fw_store_in_progress)) { + pr_info("%s: Firmware setup in progress\n", __func__); + return 0; + } + + atomic_set(&penv->fw_store_in_progress, 1); + init_completion(&penv->fw_setup_complete); + + if (kstrtoint(buf, 0, &val)) { + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); return -EINVAL; + } if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION || val == FW_IMAGE_BDATA) { @@ -1868,6 +1895,8 @@ static ssize_t fw_image_setup_store(struct device *dev, if (ret != 0) { pr_err("%s: Invalid parsing of FW image files %d", __func__, ret); + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); return -EINVAL; } penv->fw_image_setup = val; @@ -1877,6 +1906,9 @@ static ssize_t fw_image_setup_store(struct device *dev, penv->bmi_test = val; } + atomic_set(&penv->fw_store_in_progress, 0); + complete(&penv->fw_setup_complete); + return count; } @@ -1979,7 +2011,7 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg) swap_seg = NULL; return -ENOENT; } - if (!penv->fw_available) { + if (!atomic_read(&penv->fw_available)) { pr_debug("%s: fw is not available\n", __func__); return -ENOENT; } @@ -2003,6 +2035,16 @@ static void cnss_wlan_memory_expansion(void) u_int32_t total_length = 0; struct pci_dev *pdev; + /* Check for firmware setup trigger by usersapce is in progress + * and wait for complition of firmware setup. + */ + + if (atomic_read(&penv->fw_store_in_progress)) { + wait_for_completion_timeout(&penv->fw_setup_complete, + msecs_to_jiffies(FW_SETUP_DELAY)); + } + + mutex_lock(&penv->fw_setup_stat_lock); filename = cnss_wlan_get_evicted_data_file(); pdev = penv->pdev; dev = &pdev->dev; @@ -2010,21 +2052,25 @@ static void cnss_wlan_memory_expansion(void) if (!cnss_seg_info) { pr_debug("cnss: cnss_seg_info is NULL\n"); + mutex_unlock(&penv->fw_setup_stat_lock); goto end; } - if (penv->fw_available) { + if (atomic_read(&penv->fw_available)) { pr_debug("cnss: fw code already copied to host memory\n"); + mutex_unlock(&penv->fw_setup_stat_lock); goto end; } if (request_firmware(&fw_entry, filename, dev) != 0) { pr_debug("cnss: failed to get fw: %s\n", filename); + mutex_unlock(&penv->fw_setup_stat_lock); goto end; } if (!fw_entry || !fw_entry->data) { pr_err("%s: INVALID FW entries\n", __func__); + mutex_unlock(&penv->fw_setup_stat_lock); goto release_fw; } @@ -2059,7 +2105,9 @@ static void cnss_wlan_memory_expansion(void) } pr_debug("cnss: total_bytes copied: %d\n", total_length); cnss_seg_info->codeseg_total_bytes = total_length; - penv->fw_available = 1; + + atomic_set(&penv->fw_available, 1); + mutex_unlock(&penv->fw_setup_stat_lock); release_fw: release_firmware(fw_entry); @@ -2968,6 +3016,8 @@ skip_ramdump: memset(phys_to_virt(0), 0, SZ_4K); #endif + atomic_set(&penv->fw_store_in_progress, 0); + mutex_init(&penv->fw_setup_stat_lock); ret = device_create_file(dev, &dev_attr_fw_image_setup); if (ret) { pr_err("cnss: fw_image_setup sys file creation failed\n"); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 1f445f357da1..888e9cfef51a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -304,7 +304,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) queue->rx_skbs[id] = skb; ref = gnttab_claim_grant_reference(&queue->gref_rx_head); - BUG_ON((signed short)ref < 0); + WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref)); queue->grant_rx_ref[id] = ref; page = skb_frag_page(&skb_shinfo(skb)->frags[0]); @@ -437,7 +437,7 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); + WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref)); gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, gfn, GNTMAP_readonly); diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 39400dda27c2..63ec68e6ac2a 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -552,7 +552,6 @@ static void armpmu_init(struct arm_pmu *armpmu) .stop = armpmu_stop, .read = armpmu_read, .filter_match = armpmu_filter_match, - .events_across_hotplug = 1, }; } diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 08bffc344429..b111a5904952 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1319,6 +1319,35 @@ int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl, } EXPORT_SYMBOL(gsi_query_evt_ring_db_addr); +int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value) +{ + struct gsi_evt_ctx *ctx; + + if (!gsi_ctx) { + pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); + return -GSI_STATUS_NODEV; + } + + if (evt_ring_hdl >= gsi_ctx->max_ev) { + GSIERR("bad params evt_ring_hdl=%lu\n", evt_ring_hdl); + return -GSI_STATUS_INVALID_PARAMS; + } + + ctx = &gsi_ctx->evtr[evt_ring_hdl]; + + if (ctx->state != GSI_EVT_RING_STATE_ALLOCATED) { + GSIERR("bad state %d\n", + gsi_ctx->evtr[evt_ring_hdl].state); + return -GSI_STATUS_UNSUPPORTED_OP; + } + + ctx->ring.wp_local = value; + gsi_ring_evt_doorbell(ctx); + + return GSI_STATUS_SUCCESS; +} +EXPORT_SYMBOL(gsi_ring_evt_ring_db); + int gsi_reset_evt_ring(unsigned long evt_ring_hdl) { uint32_t val; diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index a02247d3e938..5aa39b699bd6 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1059,6 +1059,7 @@ static void ipa_mhi_gsi_ev_err_cb(struct gsi_evt_err_notify *notify) IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id); } IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc); + ipa_assert(); } static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify) @@ -1090,6 +1091,7 @@ static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify) IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id); } IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc); + ipa_assert(); } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 2214dfe89df3..f2909110d09f 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -857,12 +857,16 @@ int ipa2_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in) return -EINVAL; } + mutex_lock(&ipa_ctx->lock); /* check if this table exists */ entry = __ipa_find_rt_tbl(in->ip, in->name); - if (!entry) + if (!entry) { + mutex_unlock(&ipa_ctx->lock); return -EFAULT; + } in->idx = entry->idx; + mutex_unlock(&ipa_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index e349ade46075..bc6622d4725b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1668,8 +1668,21 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id, if (should_force_clear) { result = ipa3_enable_force_clear(qmi_req_id, false, source_pipe_bitmask); - if (result) - goto exit; + if (result) { + struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 }; + + /* + * assuming here modem SSR\shutdown, AP can remove + * the delay in this case + */ + IPAERR( + "failed to force clear %d, remove delay from SCND reg\n" + , result); + ep_ctrl_scnd.endp_delay = false; + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl, + &ep_ctrl_scnd); + } } /* with force clear, wait for emptiness */ for (i = 0; i < IPA_POLL_FOR_EMPTINESS_NUM; i++) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 9e2ffe70170c..cd027c28e597 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -255,6 +255,24 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, ep->gsi_evt_ring_hdl = *params->cached_gsi_evt_ring_hdl; } + if (params->ev_ctx_host->wp == params->ev_ctx_host->rbase) { + IPA_MHI_ERR("event ring wp is not updated. base=wp=0x%llx\n", + params->ev_ctx_host->wp); + goto fail_alloc_ch; + return res; + } + + IPA_MHI_DBG("Ring event db: evt_ring_hdl=%lu host_wp=0x%llx\n", + ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp); + res = gsi_ring_evt_ring_db(ep->gsi_evt_ring_hdl, + params->ev_ctx_host->wp); + if (res) { + IPA_MHI_ERR("fail to ring evt ring db %d. hdl=%lu wp=0x%llx\n", + res, ep->gsi_evt_ring_hdl, params->ev_ctx_host->wp); + goto fail_alloc_ch; + return res; + } + memset(&ch_props, 0, sizeof(ch_props)); ch_props.prot = GSI_CHAN_PROT_MHI; ch_props.dir = IPA_CLIENT_IS_PROD(client) ? diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 7212ba2a165c..6197c9f64ca5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -727,12 +727,15 @@ int ipa3_query_rt_index(struct ipa_ioc_get_rt_tbl_indx *in) return -EINVAL; } + mutex_lock(&ipa3_ctx->lock); /* check if this table exists */ entry = __ipa3_find_rt_tbl(in->ip, in->name); - if (!entry) + if (!entry) { + mutex_unlock(&ipa3_ctx->lock); return -EFAULT; - + } in->idx = entry->idx; + mutex_unlock(&ipa3_ctx->lock); return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index df5454e4776c..5397b6c39419 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1140,7 +1140,8 @@ send: memset(&meta, 0, sizeof(meta)); meta.pkt_init_dst_ep_valid = true; meta.pkt_init_dst_ep_remote = true; - meta.pkt_init_dst_ep = IPA_CLIENT_Q6_LAN_CONS; + meta.pkt_init_dst_ep = + ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS); ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, &meta); } else { ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL); diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index 53c85773b377..4f7d27db8dee 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -221,6 +221,11 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp, goto end; } + if (state == EXT_DISPLAY_CABLE_CONNECT) + ext_disp->current_disp = type; + else + ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; + ret = msm_ext_disp_send_cable_notification(ext_disp, state); /* positive ret value means audio node was switched */ @@ -287,7 +292,6 @@ static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp, if (ext_disp->current_disp != type) return false; end: - ext_disp->current_disp = type; return true; } @@ -369,8 +373,6 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, msm_ext_disp_process_audio(ext_disp, type, state, flags); msm_ext_disp_update_audio_ops(ext_disp, type, state, flags); msm_ext_disp_process_display(ext_disp, type, state, flags); - - ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } pr_debug("Hpd (%d) for display (%s)\n", state, diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index bd77e55bafc6..0dd6017245fa 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -46,7 +46,7 @@ static ssize_t power_supply_show_property(struct device *dev, static char *type_text[] = { "Unknown", "Battery", "UPS", "Mains", "USB", "USB_DCP", "USB_CDP", "USB_ACA", "USB_HVDCP", "USB_HVDCP_3", "USB_PD", - "Wireless", "BMS", "Parallel", "Main", "Wipower", + "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "Wipower", "TYPEC", "TYPEC_UFP", "TYPEC_DFP" }; static char *status_text[] = { diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index acea4f213484..e17c65c1e4e7 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -47,7 +47,7 @@ #define SCM_EDLOAD_MODE 0X01 #define SCM_DLOAD_CMD 0x10 #define SCM_DLOAD_MINIDUMP 0X20 - +#define SCM_DLOAD_BOTHDUMPS (SCM_DLOAD_MINIDUMP | SCM_DLOAD_FULLDUMP) static int restart_mode; static void *restart_reason; @@ -488,7 +488,8 @@ static ssize_t show_dload_mode(struct kobject *kobj, struct attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "DLOAD dump type: %s\n", - (dload_type == SCM_DLOAD_MINIDUMP) ? "mini" : "full"); + (dload_type == SCM_DLOAD_BOTHDUMPS) ? "both" : + ((dload_type == SCM_DLOAD_MINIDUMP) ? "mini" : "full")); } static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, @@ -502,8 +503,16 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, return -ENODEV; } dload_type = SCM_DLOAD_MINIDUMP; - } else { - pr_err("Invalid value. Use 'full' or 'mini'\n"); + } else if (sysfs_streq(buf, "both")) { + if (!minidump_enabled) { + pr_err("Minidump not enabled, setting fulldump only\n"); + dload_type = SCM_DLOAD_FULLDUMP; + return count; + } + dload_type = SCM_DLOAD_BOTHDUMPS; + } else{ + pr_err("Invalid Dump setup request..\n"); + pr_err("Supported dumps:'full', 'mini', or 'both'\n"); return -EINVAL; } diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index e3c85ab705c4..e03681ec13cc 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3136,6 +3136,7 @@ static int fg_psy_set_property(struct power_supply *psy, pval->intval); return -EINVAL; } + break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_set_constant_chg_voltage(chip, pval->intval); break; diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 49cd7aa6fdac..0908eea3b186 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -465,6 +465,8 @@ static int smb2_usb_get_prop(struct power_supply *psy, val->intval = 0; else val->intval = 1; + if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN) + val->intval = 0; break; case POWER_SUPPLY_PROP_VOLTAGE_MIN: val->intval = chg->voltage_min_uv; @@ -1466,15 +1468,6 @@ static int smb2_configure_typec(struct smb_charger *chg) return rc; } - /* configure power role for dual-role */ - rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, - TYPEC_POWER_ROLE_CMD_MASK, 0); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure power role for DRP rc=%d\n", rc); - return rc; - } - /* * disable Type-C factory mode and stay in Attached.SRC state when VCONN * over-current happens @@ -1852,6 +1845,16 @@ static int smb2_init_hw(struct smb2 *chip) static int smb2_post_init(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; + int rc; + + /* configure power role for dual-role */ + rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, 0); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure power role for DRP rc=%d\n", rc); + return rc; + } rerun_election(chg->usb_irq_enable_votable); @@ -2419,7 +2422,11 @@ static int smb2_probe(struct platform_device *pdev) goto cleanup; } - smb2_post_init(chip); + rc = smb2_post_init(chip); + if (rc < 0) { + pr_err("Failed in post init rc=%d\n", rc); + goto cleanup; + } smb2_create_debugfs(chip); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 22944f122c44..19be40bb4785 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -261,7 +261,7 @@ static const struct apsd_result const smblib_apsd_results[] = { [FLOAT] = { .name = "FLOAT", .bit = FLOAT_CHARGER_BIT, - .pst = POWER_SUPPLY_TYPE_USB_DCP + .pst = POWER_SUPPLY_TYPE_USB_FLOAT }, [HVDCP2] = { .name = "HVDCP2", @@ -3488,6 +3488,7 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); break; case POWER_SUPPLY_TYPE_USB_DCP: + case POWER_SUPPLY_TYPE_USB_FLOAT: vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); break; case POWER_SUPPLY_TYPE_USB_HVDCP: diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3588a56aabb4..5cbf20ab94aa 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2311,10 +2311,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (mem_only) { if (pci_enable_device_mem(pdev)) - goto probe_out; + return ret; } else { if (pci_enable_device(pdev)) - goto probe_out; + return ret; } /* This may fail but that's ok */ @@ -2324,7 +2324,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (!ha) { ql_log_pci(ql_log_fatal, pdev, 0x0009, "Unable to allocate memory for ha.\n"); - goto probe_out; + goto disable_device; } ql_dbg_pci(ql_dbg_init, pdev, 0x000a, "Memory allocated for ha=%p.\n", ha); @@ -2923,7 +2923,7 @@ iospace_config_failed: kfree(ha); ha = NULL; -probe_out: +disable_device: pci_disable_device(pdev); return ret; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 544a71e7c242..a2f2cc0c2c51 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -653,7 +653,7 @@ static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, unsigned int tag, const char *str) { struct ufshcd_lrb *lrbp; - char *cmd_type; + char *cmd_type = NULL; u8 opcode = 0; u8 cmd_id = 0, idn = 0; sector_t lba = -1; diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c index ee0fe1622645..f4ffc7df1e9c 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -2884,7 +2884,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, struct channel_ctx *ctx = (struct channel_ctx *)handle; uint32_t riid; int ret = 0; - struct glink_core_tx_pkt *tx_info; + struct glink_core_tx_pkt *tx_info = NULL; size_t intent_size; bool is_atomic = tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC); @@ -2899,6 +2899,13 @@ static int glink_tx_common(void *handle, void *pkt_priv, return ret; rwref_read_get_atomic(&ctx->ch_state_lhb2, is_atomic); + tx_info = kzalloc(sizeof(struct glink_core_tx_pkt), + is_atomic ? GFP_ATOMIC : GFP_KERNEL); + if (!tx_info) { + GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__); + ret = -ENOMEM; + goto glink_tx_common_err; + } if (!(vbuf_provider || pbuf_provider)) { ret = -EINVAL; goto glink_tx_common_err; @@ -3018,14 +3025,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, GLINK_INFO_PERF_CH(ctx, "%s: R[%u]:%zu data[%p], size[%zu]. TID %u\n", __func__, riid, intent_size, data ? data : iovec, size, current->pid); - tx_info = kzalloc(sizeof(struct glink_core_tx_pkt), - is_atomic ? GFP_ATOMIC : GFP_KERNEL); - if (!tx_info) { - GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__); - ch_push_remote_rx_intent(ctx, intent_size, riid, cookie); - ret = -ENOMEM; - goto glink_tx_common_err; - } + rwref_lock_init(&tx_info->pkt_ref, glink_tx_pkt_release); INIT_LIST_HEAD(&tx_info->list_done); INIT_LIST_HEAD(&tx_info->list_node); @@ -3050,10 +3050,15 @@ static int glink_tx_common(void *handle, void *pkt_priv, else xprt_schedule_tx(ctx->transport_ptr, ctx, tx_info); + rwref_read_put(&ctx->ch_state_lhb2); + glink_put_ch_ctx(ctx, false); + return ret; + glink_tx_common_err: rwref_read_put(&ctx->ch_state_lhb2); glink_tx_common_err_2: glink_put_ch_ctx(ctx, false); + kfree(tx_info); return ret; } diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 99caa1c84dce..37193bbb23b7 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -2402,7 +2402,7 @@ static int glink_smem_native_probe(struct platform_device *pdev) einfo->tx_fifo = smem_alloc(SMEM_GLINK_NATIVE_XPRT_FIFO_0, einfo->tx_fifo_size, einfo->remote_proc_id, - SMEM_ITEM_CACHED_FLAG); + 0); if (!einfo->tx_fifo) { pr_err("%s: smem alloc of tx fifo failed\n", __func__); rc = -ENOMEM; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 9690d3c64560..21be894414bc 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -268,6 +268,7 @@ enum icnss_driver_state { ICNSS_WLFW_EXISTS, ICNSS_WDOG_BITE, ICNSS_SHUTDOWN_DONE, + ICNSS_HOST_TRIGGERED_PDR, }; struct ce_irq_list { @@ -320,6 +321,13 @@ struct icnss_stats { uint32_t disable; } ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS]; + struct { + uint32_t pdr_fw_crash; + uint32_t pdr_host_error; + uint32_t root_pd_crash; + uint32_t root_pd_shutdown; + } recovery; + uint32_t pm_suspend; uint32_t pm_suspend_err; uint32_t pm_resume; @@ -360,7 +368,6 @@ struct icnss_stats { uint32_t rejuvenate_ack_req; uint32_t rejuvenate_ack_resp; uint32_t rejuvenate_ack_err; - uint32_t trigger_recovery; }; #define MAX_NO_OF_MAC_ADDR 4 @@ -369,6 +376,20 @@ struct icnss_wlan_mac_addr { uint32_t no_of_mac_addr_set; }; +enum icnss_pdr_cause_index { + ICNSS_FW_CRASH, + ICNSS_ROOT_PD_CRASH, + ICNSS_ROOT_PD_SHUTDOWN, + ICNSS_HOST_ERROR, +}; + +static const char * const icnss_pdr_cause[] = { + [ICNSS_FW_CRASH] = "FW crash", + [ICNSS_ROOT_PD_CRASH] = "Root PD crashed", + [ICNSS_ROOT_PD_SHUTDOWN] = "Root PD shutdown", + [ICNSS_HOST_ERROR] = "Host error", +}; + struct service_notifier_context { void *handle; uint32_t instance_id; @@ -2400,6 +2421,11 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n", priv->state, notif->crashed); + if (notif->crashed) + priv->stats.recovery.root_pd_crash++; + else + priv->stats.recovery.root_pd_shutdown++; + icnss_ignore_qmi_timeout(true); event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); @@ -2479,6 +2505,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; struct icnss_uevent_fw_down_data fw_down_data; + enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH; icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", notification, priv->state); @@ -2493,26 +2520,40 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, if (state == NULL) { event_data->crashed = true; + priv->stats.recovery.root_pd_crash++; goto event_post; } - icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n", - *state, priv->state); - switch (*state) { case ROOT_PD_WDOG_BITE: event_data->crashed = true; event_data->wdog_bite = true; + priv->stats.recovery.root_pd_crash++; break; case ROOT_PD_SHUTDOWN: + cause = ICNSS_ROOT_PD_SHUTDOWN; + priv->stats.recovery.root_pd_shutdown++; + break; + case USER_PD_STATE_CHANGE: + if (test_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state)) { + cause = ICNSS_HOST_ERROR; + priv->stats.recovery.pdr_host_error++; + } else { + cause = ICNSS_FW_CRASH; + priv->stats.recovery.pdr_fw_crash++; + } break; default: event_data->crashed = true; + priv->stats.recovery.root_pd_crash++; break; } + icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n", + *state, priv->state, icnss_pdr_cause[cause]); event_post: icnss_ignore_qmi_timeout(true); + clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); fw_down_data.crashed = event_data->crashed; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); @@ -3255,7 +3296,6 @@ int icnss_trigger_recovery(struct device *dev) WARN_ON(1); icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n", priv->state); - priv->stats.trigger_recovery++; /* * Initiate PDR, required only for the first instance @@ -3263,6 +3303,9 @@ int icnss_trigger_recovery(struct device *dev) ret = service_notif_pd_restart(priv->service_notifier[0].name, priv->service_notifier[0].instance_id); + if (!ret) + set_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state); + out: return ret; } @@ -3617,9 +3660,6 @@ static ssize_t icnss_fw_debug_write(struct file *fp, if (ret) return ret; - if (ret == 0) - memset(&priv->stats, 0, sizeof(priv->stats)); - return count; } @@ -3713,6 +3753,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_SHUTDOWN_DONE: seq_puts(s, "SHUTDOWN DONE"); continue; + case ICNSS_HOST_TRIGGERED_PDR: + seq_puts(s, "HOST TRIGGERED PDR"); + continue; } seq_printf(s, "UNKNOWN-%d", i); @@ -3811,7 +3854,10 @@ static int icnss_stats_show(struct seq_file *s, void *data) ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req); ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp); ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err); - ICNSS_STATS_DUMP(s, priv, trigger_recovery); + ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash); + ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error); + ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash); + ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown); seq_puts(s, "\n<------------------ PM stats ------------------->\n"); ICNSS_STATS_DUMP(s, priv, pm_suspend); diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index a92e5c416678..0a80016f1942 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -33,7 +33,8 @@ #include <linux/termios.h> #include <soc/qcom/glink.h> - +/* This Limit ensures that auto queue will not exhaust memory on remote side */ +#define MAX_PENDING_GLINK_PKT 5 #define MODULE_NAME "msm_glinkpkt" #define DEVICE_NAME "glinkpkt" #define WAKEUPSOURCE_TIMEOUT (2000) /* two seconds */ @@ -136,6 +137,7 @@ struct glink_pkt_dev { struct glink_link_info link_info; void *link_state_handle; bool link_up; + bool auto_intent_enabled; }; /** @@ -447,8 +449,26 @@ void glink_pkt_notify_state(void *handle, const void *priv, unsigned event) bool glink_pkt_rmt_rx_intent_req_cb(void *handle, const void *priv, size_t sz) { struct queue_rx_intent_work *work_item; + int pending_pkt_count = 0; + struct glink_rx_pkt *pkt = NULL; + unsigned long flags; + struct glink_pkt_dev *devp = (struct glink_pkt_dev *)priv; + GLINK_PKT_INFO("%s(): QUEUE RX INTENT to receive size[%zu]\n", __func__, sz); + if (devp->auto_intent_enabled) { + spin_lock_irqsave(&devp->pkt_list_lock, flags); + list_for_each_entry(pkt, &devp->pkt_list, list) + pending_pkt_count++; + spin_unlock_irqrestore(&devp->pkt_list_lock, flags); + if (pending_pkt_count > MAX_PENDING_GLINK_PKT) { + GLINK_PKT_ERR("%s failed, max limit reached\n", + __func__); + return false; + } + } else { + return false; + } work_item = kzalloc(sizeof(*work_item), GFP_ATOMIC); if (!work_item) { @@ -457,7 +477,7 @@ bool glink_pkt_rmt_rx_intent_req_cb(void *handle, const void *priv, size_t sz) } work_item->intent_size = sz; - work_item->devp = (struct glink_pkt_dev *)priv; + work_item->devp = devp; INIT_WORK(&work_item->work, glink_pkt_queue_rx_intent_worker); queue_work(glink_pkt_wq, &work_item->work); @@ -626,10 +646,11 @@ ssize_t glink_pkt_read(struct file *file, } mutex_lock(&devp->ch_lock); - if (!glink_rx_intent_exists(devp->handle, count)) { + if (!glink_pkt_read_avail(devp) && + !glink_rx_intent_exists(devp->handle, count)) { ret = glink_queue_rx_intent(devp->handle, devp, count); if (ret) { - GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n", + GLINK_PKT_ERR("%s: failed to queue intent ret[%d]\n", __func__, ret); mutex_unlock(&devp->ch_lock); return ret; @@ -915,6 +936,7 @@ static long glink_pkt_ioctl(struct file *file, unsigned int cmd, case GLINK_PKT_IOCTL_QUEUE_RX_INTENT: ret = get_user(size, (uint32_t *)arg); GLINK_PKT_INFO("%s: intent size[%d]\n", __func__, size); + devp->auto_intent_enabled = false; ret = glink_queue_rx_intent(devp->handle, devp, size); if (ret) { GLINK_PKT_ERR("%s: failed to QUEUE_RX_INTENT ret[%d]\n", @@ -1183,6 +1205,7 @@ static int glink_pkt_init_add_device(struct glink_pkt_dev *devp, int i) glink_pkt_link_state_cb; devp->i = i; devp->poll_mode = 0; + devp->auto_intent_enabled = true; devp->ws_locked = 0; devp->ch_state = GLINK_LOCAL_DISCONNECTED; /* Default timeout for open wait is 120sec */ diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index 36804b988d62..31de6e5c173c 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -731,10 +731,6 @@ int scm_call2_atomic(u32 fn_id, struct scm_desc *desc) x0 = fn_id | BIT(SMC_ATOMIC_SYSCALL) | scm_version_mask; - 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); - if (scm_version == SCM_ARMV8_64) ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0], desc->args[1], desc->args[2], @@ -746,9 +742,8 @@ int scm_call2_atomic(u32 fn_id, struct scm_desc *desc) desc->x5, &desc->ret[0], &desc->ret[1], &desc->ret[2]); 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], + 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) diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c index 34b46d25a823..2ef25e48ce50 100644 --- a/drivers/soc/qcom/smp2p_sleepstate.c +++ b/drivers/soc/qcom/smp2p_sleepstate.c @@ -14,6 +14,8 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/suspend.h> +#include <linux/delay.h> +#include <linux/ipc_router.h> #include "smp2p_private.h" #define SET_DELAY (2 * HZ) @@ -35,10 +37,14 @@ static int sleepstate_pm_notifier(struct notifier_block *nb, switch (event) { case PM_SUSPEND_PREPARE: gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 0); + msleep(25); /* To be tuned based on SMP2P latencies */ + msm_ipc_router_set_ws_allowed(true); break; case PM_POST_SUSPEND: gpio_set_value(slst_gpio_base_id + PROC_AWAKE_ID, 1); + msleep(25); /* To be tuned based on SMP2P latencies */ + msm_ipc_router_set_ws_allowed(false); break; } return NOTIFY_DONE; diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 3c9d8efd3956..5fe3c572628b 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -58,6 +58,7 @@ struct wdsp_glink_rsp_que { struct wdsp_glink_tx_buf { struct work_struct tx_work; + struct work_struct free_tx_work; /* Glink channel information */ struct wdsp_glink_ch *ch; @@ -125,6 +126,46 @@ static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch); static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch); /* + * wdsp_glink_free_tx_buf_work - Work function to free tx pkt + * work: Work structure + */ +static void wdsp_glink_free_tx_buf_work(struct work_struct *work) +{ + struct wdsp_glink_tx_buf *tx_buf; + + tx_buf = container_of(work, struct wdsp_glink_tx_buf, + free_tx_work); + vfree(tx_buf); +} + +/* + * wdsp_glink_free_tx_buf - Function to free tx buffer + * priv: Pointer to the channel + * pkt_priv: Pointer to the tx buffer + */ +static void wdsp_glink_free_tx_buf(const void *priv, const void *pkt_priv) +{ + struct wdsp_glink_tx_buf *tx_buf = (struct wdsp_glink_tx_buf *)pkt_priv; + struct wdsp_glink_priv *wpriv; + struct wdsp_glink_ch *ch; + + if (!priv) { + pr_err("%s: Invalid priv\n", __func__); + return; + } + if (!tx_buf) { + pr_err("%s: Invalid tx_buf\n", __func__); + return; + } + + ch = (struct wdsp_glink_ch *)priv; + wpriv = ch->wpriv; + /* Work queue to free tx pkt */ + INIT_WORK(&tx_buf->free_tx_work, wdsp_glink_free_tx_buf_work); + queue_work(wpriv->work_queue, &tx_buf->free_tx_work); +} + +/* * wdsp_glink_notify_rx - Glink notify rx callback for responses * handle: Opaque Channel handle returned by GLink * priv: Private pointer to the channel @@ -183,14 +224,8 @@ static void wdsp_glink_notify_rx(void *handle, const void *priv, static void wdsp_glink_notify_tx_done(void *handle, const void *priv, const void *pkt_priv, const void *ptr) { - if (!pkt_priv) { - pr_err("%s: Invalid parameter\n", __func__); - return; - } - /* Free tx pkt */ - vfree(pkt_priv); + wdsp_glink_free_tx_buf(priv, pkt_priv); } - /* * wdsp_glink_notify_tx_abort - Glink notify tx abort callback to * free tx buffer @@ -201,12 +236,7 @@ static void wdsp_glink_notify_tx_done(void *handle, const void *priv, static void wdsp_glink_notify_tx_abort(void *handle, const void *priv, const void *pkt_priv) { - if (!pkt_priv) { - pr_err("%s: Invalid parameter\n", __func__); - return; - } - /* Free tx pkt */ - vfree(pkt_priv); + wdsp_glink_free_tx_buf(priv, pkt_priv); } /* @@ -555,7 +585,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv, goto done; } ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *), - GFP_KERNEL); + GFP_ATOMIC); if (!ch) { ret = -ENOMEM; goto done; diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 2fb1e974cc70..e11b1001d1f6 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -399,18 +399,10 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm, struct lov_mds_md *lmmk = NULL; int rc, lmm_size; int lum_size; - mm_segment_t seg; if (!lsm) return -ENODATA; - /* - * "Switch to kernel segment" to allow copying from kernel space by - * copy_{to,from}_user(). - */ - seg = get_fs(); - set_fs(KERNEL_DS); - /* we only need the header part from user space to get lmm_magic and * lmm_stripe_count, (the header part is common to v1 and v3) */ lum_size = sizeof(struct lov_user_md_v1); @@ -485,6 +477,5 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm, obd_free_diskmd(exp, &lmmk); out_set: - set_fs(seg); return rc; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index af301414a9f3..60743bf27f37 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1154,15 +1154,28 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) if (cmd->unknown_data_length) { cmd->data_length = size; } else if (size != cmd->data_length) { - pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" + pr_warn_ratelimited("TARGET_CORE[%s]: Expected Transfer Length:" " %u does not match SCSI CDB Length: %u for SAM Opcode:" " 0x%02x\n", cmd->se_tfo->get_fabric_name(), cmd->data_length, size, cmd->t_task_cdb[0]); - if (cmd->data_direction == DMA_TO_DEVICE && - cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { - pr_err("Rejecting underflow/overflow WRITE data\n"); - return TCM_INVALID_CDB_FIELD; + if (cmd->data_direction == DMA_TO_DEVICE) { + if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + pr_err_ratelimited("Rejecting underflow/overflow" + " for WRITE data CDB\n"); + return TCM_INVALID_CDB_FIELD; + } + /* + * Some fabric drivers like iscsi-target still expect to + * always reject overflow writes. Reject this case until + * full fabric driver level support for overflow writes + * is introduced tree-wide. + */ + if (size > cmd->data_length) { + pr_err_ratelimited("Rejecting overflow for" + " WRITE control CDB\n"); + return TCM_INVALID_CDB_FIELD; + } } /* * Reject READ_* or WRITE_* with overflow/underflow for diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c index c78406cb3325..2df1bf69e7c9 100644 --- a/drivers/thermal/qpnp-adc-tm.c +++ b/drivers/thermal/qpnp-adc-tm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3292,40 +3292,55 @@ static int qpnp_adc_tm_remove(struct platform_device *pdev) static void qpnp_adc_tm_shutdown(struct platform_device *pdev) { struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&pdev->dev); - int rc = 0; + int rc = 0, i = 0; u8 reg_val = 0, status1 = 0, en_ctl1 = 0; - /* Set measurement in single measurement mode */ - reg_val = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT; - rc = qpnp_adc_tm_mode_select(chip, reg_val); - if (rc < 0) - pr_err("adc-tm single mode select failed\n"); + if (!chip->adc_tm_hc) { + /* Set measurement in single measurement mode */ + reg_val = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT; + rc = qpnp_adc_tm_mode_select(chip, reg_val); + if (rc < 0) + pr_err("adc-tm single mode select failed\n"); + } /* Disable bank */ rc = qpnp_adc_tm_disable(chip); if (rc < 0) pr_err("adc-tm disable failed\n"); - /* Check if a conversion is in progress */ - rc = qpnp_adc_tm_req_sts_check(chip); - if (rc < 0) - pr_err("adc-tm req_sts check failed\n"); + if (chip->adc_tm_hc) { + for (i = 0; i < 8; i++) { + rc = qpnp_adc_tm_reg_update(chip, + QPNP_BTM_Mn_EN(i), + QPNP_BTM_Mn_MEAS_EN, false); + if (rc < 0) + pr_err("multi meas disable failed\n"); + } + } else { + /* Check if a conversion is in progress */ + rc = qpnp_adc_tm_req_sts_check(chip); + if (rc < 0) + pr_err("adc-tm req_sts check failed\n"); - /* Disable multimeasurement */ - reg_val = 0; - rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN, reg_val, 1); - if (rc < 0) - pr_err("adc-tm multi-measurement mode disable failed\n"); + /* Disable multimeasurement */ + reg_val = 0; + rc = qpnp_adc_tm_write_reg(chip, + QPNP_ADC_TM_MULTI_MEAS_EN, reg_val, 1); + if (rc < 0) + pr_err("adc-tm multi-meas mode disable failed\n"); - rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1); - if (rc < 0) - pr_err("adc-tm status1 read failed\n"); + rc = qpnp_adc_tm_read_reg(chip, + QPNP_ADC_TM_STATUS1, &status1, 1); + if (rc < 0) + pr_err("adc-tm status1 read failed\n"); - rc = qpnp_adc_tm_read_reg(chip, QPNP_EN_CTL1, &en_ctl1, 1); - if (rc < 0) - pr_err("adc-tm en_ctl1 read failed\n"); + rc = qpnp_adc_tm_read_reg(chip, + QPNP_EN_CTL1, &en_ctl1, 1); + if (rc < 0) + pr_err("adc-tm en_ctl1 read failed\n"); - pr_debug("adc-tm status1=0%x, en_ctl1=0x%x\n", status1, en_ctl1); + pr_debug("status1=0%x, en_ctl1=0x%x\n", status1, en_ctl1); + } } static int qpnp_adc_tm_suspend_noirq(struct device *dev) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 88246f7e435a..0f23dda60011 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1378,9 +1378,9 @@ static struct spi_driver ifx_spi_driver = { static void __exit ifx_spi_exit(void) { /* unregister */ + spi_unregister_driver(&ifx_spi_driver); tty_unregister_driver(tty_drv); put_tty_driver(tty_drv); - spi_unregister_driver(&ifx_spi_driver); unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 63a06ab6ba03..235e150d7b81 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1800,11 +1800,13 @@ static int sci_startup(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + sci_request_dma(port); + ret = sci_request_irq(s); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + sci_free_dma(port); return ret; - - sci_request_dma(port); + } spin_lock_irqsave(&port->lock, flags); sci_start_tx(port); @@ -1834,8 +1836,8 @@ static void sci_shutdown(struct uart_port *port) } #endif - sci_free_dma(port); sci_free_irq(s); + sci_free_dma(port); } static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7cef54334b12..1bb629ab8ecc 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2070,13 +2070,12 @@ retry_open: if (tty) { mutex_unlock(&tty_mutex); retval = tty_lock_interruptible(tty); + tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */ if (retval) { if (retval == -EINTR) retval = -ERESTARTSYS; goto err_unref; } - /* safe to drop the kref from tty_driver_lookup_tty() */ - tty_kref_put(tty); retval = tty_reopen(tty); if (retval < 0) { tty_unlock(tty); diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index d09293bc0e04..cff304abb619 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -24,10 +24,15 @@ EXPORT_SYMBOL(tty_lock); int tty_lock_interruptible(struct tty_struct *tty) { + int ret; + if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) return -EIO; tty_kref_get(tty); - return mutex_lock_interruptible(&tty->legacy_mutex); + ret = mutex_lock_interruptible(&tty->legacy_mutex); + if (ret) + tty_kref_put(tty); + return ret; } void __lockfunc tty_unlock(struct tty_struct *tty) diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 58c8485a0715..923379972707 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -295,7 +295,8 @@ static int ci_role_show(struct seq_file *s, void *data) { struct ci_hdrc *ci = s->private; - seq_printf(s, "%s\n", ci_role(ci)->name); + if (ci->role != CI_ROLE_END) + seq_printf(s, "%s\n", ci_role(ci)->name); return 0; } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d8a045fc1fdb..aff086ca97e4 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1982,6 +1982,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) int ci_hdrc_gadget_init(struct ci_hdrc *ci) { struct ci_role_driver *rdrv; + int ret; if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC)) return -ENXIO; @@ -1994,7 +1995,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci) rdrv->stop = udc_id_switch_for_host; rdrv->irq = udc_irq; rdrv->name = "gadget"; - ci->roles[CI_ROLE_GADGET] = rdrv; - return udc_start(ci); + ret = udc_start(ci); + if (!ret) + ci->roles[CI_ROLE_GADGET] = rdrv; + + return ret; } diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 325cbc9c35d8..b1298f093f13 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -949,6 +949,14 @@ int usb_get_bos_descriptor(struct usb_device *dev) dev->bos->ss_id = (struct usb_ss_container_id_descriptor *)buffer; break; + case USB_CAP_TYPE_CONFIG_SUMMARY: + /* one such desc per configuration */ + if (!dev->bos->num_config_summary_desc) + dev->bos->config_summary = + (struct usb_config_summary_descriptor *)buffer; + + dev->bos->num_config_summary_desc++; + break; default: break; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 358ca8dd784f..72d1109f13eb 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -19,6 +19,8 @@ #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v3.h> #include "usb.h" static inline const char *plural(int n) @@ -40,6 +42,36 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } +static int usb_audio_max_rev_config(struct usb_host_bos *bos) +{ + int desc_cnt, func_cnt, numfunc; + int num_cfg_desc; + struct usb_config_summary_descriptor *conf_summary; + + if (!bos || !bos->config_summary) + goto done; + + conf_summary = bos->config_summary; + num_cfg_desc = bos->num_config_summary_desc; + + for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) { + numfunc = conf_summary->bNumFunctions; + for (func_cnt = 0; func_cnt < numfunc; func_cnt++) { + /* look for BADD 3.0 */ + if (conf_summary->cs_info[func_cnt].bClass == + USB_CLASS_AUDIO && + conf_summary->cs_info[func_cnt].bProtocol == + UAC_VERSION_3 && + conf_summary->cs_info[func_cnt].bSubClass != + FULL_ADC_PROFILE) + return conf_summary->bConfigurationValue; + } + } + +done: + return -EINVAL; +} + int usb_choose_configuration(struct usb_device *udev) { int i; @@ -130,7 +162,6 @@ int usb_choose_configuration(struct usb_device *udev) best = c; break; } - /* If all the remaining configs are vendor-specific, * choose the first one. */ else if (!best) @@ -143,7 +174,10 @@ int usb_choose_configuration(struct usb_device *udev) insufficient_power, plural(insufficient_power)); if (best) { - i = best->desc.bConfigurationValue; + /* choose usb audio class preferred config if available */ + i = usb_audio_max_rev_config(udev->bos); + if (i < 0) + i = best->desc.bConfigurationValue; dev_dbg(&udev->dev, "configuration #%d chosen from %d choice%s\n", i, num_configs, plural(num_configs)); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 59d6ac67d072..9b7274821d0b 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -399,7 +399,11 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Caller must hold fsg->lock */ static void wakeup_thread(struct fsg_common *common) { - smp_wmb(); /* ensure the write of bh->state is complete */ + /* + * Ensure the reading of thread_wakeup_needed + * and the writing of bh->state are completed + */ + smp_mb(); /* Tell the main thread that something has happened */ common->thread_wakeup_needed = 1; if (common->thread_task) @@ -649,7 +653,12 @@ static int sleep_thread(struct fsg_common *common, bool can_freeze) } __set_current_state(TASK_RUNNING); common->thread_wakeup_needed = 0; - smp_rmb(); /* ensure the latest bh->state is visible */ + + /* + * Ensure the writing of thread_wakeup_needed + * and the reading of bh->state are completed + */ + smp_mb(); return rc; } diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 7d4578b08244..c8afb3a244c3 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -1674,6 +1674,8 @@ exit: int mdss_dp_on(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; + bool hpd; + int rc = 0; if (!pdata) { pr_err("Invalid input data\n"); @@ -1683,6 +1685,22 @@ int mdss_dp_on(struct mdss_panel_data *pdata) dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); + mutex_lock(&dp_drv->attention_lock); + hpd = dp_drv->cable_connected; + mutex_unlock(&dp_drv->attention_lock); + + /* In case of device coming out of PM_SUSPEND, there can be + * a corner case where the sink is turned off or the DP cable + * is disconnected almost at the same time as userspace triggering + * unblank. This can cause the UNBLANK call to be still triggered + * before the disconnect event is notified to the userspace. + * Avoid turning ON DP path in such cases. + */ + if (!hpd || !dp_drv->alt_mode.dp_status.hpd_high) { + pr_err("DP sink not connected\n"); + return -EINVAL; + } + /* * If the link already active, then nothing needs to be done here. * However, it is possible that the the power_on flag could be @@ -1707,8 +1725,11 @@ int mdss_dp_on(struct mdss_panel_data *pdata) * init/deinit during unrelated resume/suspend events, * add host initialization call before DP power-on. */ - if (!dp_drv->dp_initialized) - mdss_dp_host_init(pdata); + if (!dp_drv->dp_initialized) { + rc = mdss_dp_host_init(pdata); + if (rc < 0) + return rc; + } return mdss_dp_on_hpd(dp_drv); } @@ -1941,6 +1962,11 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) } dp_drv->orientation = usbpd_get_plug_orientation(dp_drv->pd); + if (dp_drv->orientation == ORIENTATION_NONE) { + pr_err("DP cable might be disconnected\n"); + ret = -EINVAL; + goto orientation_error; + } dp_drv->aux_sel_gpio_output = 0; if (dp_drv->orientation == ORIENTATION_CC2) @@ -1981,8 +2007,9 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) return 0; clk_error: - mdss_dp_regulator_ctrl(dp_drv, false); mdss_dp_config_gpios(dp_drv, false); +orientation_error: + mdss_dp_regulator_ctrl(dp_drv, false); vreg_error: return ret; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c index 7cc94447efdc..d412a1c66e79 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c +++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -150,7 +150,7 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - int rc, ret; + int ret; /* * iommu dynamic attach for following conditions. @@ -167,26 +167,41 @@ static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd) return -EPERM; } - rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE, + /* + * Putting handoff pending to false to ensure smmu attach happens + * with early flag attribute + */ + mdata->handoff_pending = false; + + ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 1); + if (ret) { + pr_debug("mdss set attribute failed for early map\n"); + goto end; + } + + ret = mdss_iommu_ctrl(1); + if (IS_ERR_VALUE(ret)) { + pr_err("mdss iommu attach failed\n"); + goto end; + } + + ret = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size, IOMMU_READ | IOMMU_NOEXEC); - if (rc) { - pr_debug("iommu memory mapping failed rc=%d\n", rc); + if (ret) { + pr_err("iommu memory mapping failed ret=%d\n", ret); } else { - ret = mdss_iommu_ctrl(1); - if (IS_ERR_VALUE(ret)) { - pr_err("mdss iommu attach failed\n"); - mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE, - mdp5_data->splash_mem_addr, - mdp5_data->splash_mem_size); - } else { - mfd->splash_info.iommu_dynamic_attached = true; - } + pr_debug("iommu map passed for PA=VA\n"); + mfd->splash_info.iommu_dynamic_attached = true; } - return rc; + ret = mdss_smmu_set_attribute(MDSS_IOMMU_DOMAIN_UNSECURE, EARLY_MAP, 0); +end: + mdata->handoff_pending = true; + + return ret; } static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd) @@ -194,12 +209,10 @@ static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd) struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); if (mfd->splash_info.iommu_dynamic_attached) { - mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE, mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); mdss_iommu_ctrl(0); - mfd->splash_info.iommu_dynamic_attached = false; } } diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c index 75f502415589..02e6d210b6e4 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.c +++ b/drivers/video/fbdev/msm/mdss_smmu.c @@ -280,6 +280,27 @@ end: return rc; } +int mdss_smmu_set_attribute(int domain, int flag, int val) +{ + int rc = 0, domain_attr = 0; + struct mdss_smmu_client *mdss_smmu = mdss_smmu_get_cb(domain); + + if (!mdss_smmu) { + pr_err("not able to get smmu context\n"); + return -EINVAL; + } + + if (flag == EARLY_MAP) + domain_attr = DOMAIN_ATTR_EARLY_MAP; + else + goto end; + + rc = iommu_domain_set_attr(mdss_smmu->mmu_mapping->domain, + domain_attr, &val); +end: + return rc; +} + /* * mdss_smmu_attach_v2() * diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h index a5c7af74cdbf..679e564bcbc9 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.h +++ b/drivers/video/fbdev/msm/mdss_smmu.h @@ -48,6 +48,11 @@ struct mdss_smmu_private { void mdss_smmu_register(struct device *dev); int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev); +int mdss_smmu_set_attribute(int domain, int flag, int val); + +enum smmu_attributes { + EARLY_MAP +}; static inline int mdss_smmu_dma_data_direction(int dir) { diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index df2e6f783318..527de56f832f 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -335,8 +335,8 @@ static int mmap_batch_fn(void *data, int nr, void *state) st->global_error = 1; } } - st->va += PAGE_SIZE * nr; - st->index += nr; + st->va += XEN_PAGE_SIZE * nr; + st->index += nr / XEN_PFN_PER_PAGE; return 0; } diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2a2e370399ba..c36a03fa7678 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3854,6 +3854,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, info->space_info_kobj, "%s", alloc_name(found->flags)); if (ret) { + percpu_counter_destroy(&found->total_bytes_pinned); kfree(found); return ret; } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 353f4bae658c..d4a6eef31854 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2771,7 +2771,7 @@ static long btrfs_fallocate(struct file *file, int mode, if (!ret) ret = btrfs_prealloc_file_range(inode, mode, range->start, - range->len, 1 << inode->i_blkbits, + range->len, i_blocksize(inode), offset + len, &alloc_hint); list_del(&range->list); kfree(range); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3cff6523f27d..863fa0f1972b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7318,8 +7318,8 @@ bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end) int found = false; void **pagep = NULL; struct page *page = NULL; - int start_idx; - int end_idx; + unsigned long start_idx; + unsigned long end_idx; start_idx = start >> PAGE_CACHE_SHIFT; diff --git a/fs/buffer.c b/fs/buffer.c index fc35dd27cc0f..14ce7b24f32a 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2347,7 +2347,7 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping, loff_t pos, loff_t *bytes) { struct inode *inode = mapping->host; - unsigned blocksize = 1 << inode->i_blkbits; + unsigned int blocksize = i_blocksize(inode); struct page *page; void *fsdata; pgoff_t index, curidx; @@ -2427,8 +2427,8 @@ int cont_write_begin(struct file *file, struct address_space *mapping, get_block_t *get_block, loff_t *bytes) { struct inode *inode = mapping->host; - unsigned blocksize = 1 << inode->i_blkbits; - unsigned zerofrom; + unsigned int blocksize = i_blocksize(inode); + unsigned int zerofrom; int err; err = cont_expand_zero(file, mapping, pos, bytes); @@ -2790,7 +2790,7 @@ int nobh_truncate_page(struct address_space *mapping, struct buffer_head map_bh; int err; - blocksize = 1 << inode->i_blkbits; + blocksize = i_blocksize(inode); length = offset & (blocksize - 1); /* Block boundary? Nothing to do */ @@ -2868,7 +2868,7 @@ int block_truncate_page(struct address_space *mapping, struct buffer_head *bh; int err; - blocksize = 1 << inode->i_blkbits; + blocksize = i_blocksize(inode); length = offset & (blocksize - 1); /* Block boundary? Nothing to do */ @@ -2980,7 +2980,7 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, struct inode *inode = mapping->host; tmp.b_state = 0; tmp.b_blocknr = 0; - tmp.b_size = 1 << inode->i_blkbits; + tmp.b_size = i_blocksize(inode); get_block(inode, block, &tmp, 0); return tmp.b_blocknr; } diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index b7d218a168fb..c6a1ec110c01 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -697,7 +697,7 @@ static int ceph_writepages_start(struct address_space *mapping, struct pagevec pvec; int done = 0; int rc = 0; - unsigned wsize = 1 << inode->i_blkbits; + unsigned int wsize = i_blocksize(inode); struct ceph_osd_request *req = NULL; int do_sync = 0; loff_t snap_size, i_size; diff --git a/fs/direct-io.c b/fs/direct-io.c index 0f1517d0b969..7cdf8ad1bb5b 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -589,7 +589,7 @@ static int dio_set_defer_completion(struct dio *dio) /* * Call into the fs to map some more disk blocks. We record the current number * of available blocks at sdio->blocks_available. These are in units of the - * fs blocksize, (1 << inode->i_blkbits). + * fs blocksize, i_blocksize(inode). * * The fs is allowed to map lots of blocks at once. If it wants to do that, * it uses the passed inode-relative block number as the file offset, as usual. diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 8a456f9b8a44..61d5bfc7318c 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4902,6 +4902,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, /* Zero out partial block at the edges of the range */ ret = ext4_zero_partial_blocks(handle, inode, offset, len); + if (ret >= 0) + ext4_update_inode_fsync_trans(handle, inode, 1); if (file->f_flags & O_SYNC) ext4_handle_sync(handle); @@ -5597,6 +5599,7 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) ext4_handle_sync(handle); inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); + ext4_update_inode_fsync_trans(handle, inode, 1); out_stop: ext4_journal_stop(handle); @@ -5770,6 +5773,8 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) up_write(&EXT4_I(inode)->i_data_sem); if (IS_SYNC(inode)) ext4_handle_sync(handle); + if (ret >= 0) + ext4_update_inode_fsync_trans(handle, inode, 1); out_stop: ext4_journal_stop(handle); diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 0d24ebcd7c9e..8772bfc3415b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -463,47 +463,27 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, num = min_t(pgoff_t, end - index, PAGEVEC_SIZE); nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, (pgoff_t)num); - if (nr_pages == 0) { - if (whence == SEEK_DATA) - break; - - BUG_ON(whence != SEEK_HOLE); - /* - * If this is the first time to go into the loop and - * offset is not beyond the end offset, it will be a - * hole at this offset - */ - if (lastoff == startoff || lastoff < endoff) - found = 1; + if (nr_pages == 0) break; - } - - /* - * If this is the first time to go into the loop and - * offset is smaller than the first page offset, it will be a - * hole at this offset. - */ - if (lastoff == startoff && whence == SEEK_HOLE && - lastoff < page_offset(pvec.pages[0])) { - found = 1; - break; - } for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; struct buffer_head *bh, *head; /* - * If the current offset is not beyond the end of given - * range, it will be a hole. + * If current offset is smaller than the page offset, + * there is a hole at this offset. */ - if (lastoff < endoff && whence == SEEK_HOLE && - page->index > end) { + if (whence == SEEK_HOLE && lastoff < endoff && + lastoff < page_offset(pvec.pages[i])) { found = 1; *offset = lastoff; goto out; } + if (page->index > end) + goto out; + lock_page(page); if (unlikely(page->mapping != inode->i_mapping)) { @@ -543,20 +523,18 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, unlock_page(page); } - /* - * The no. of pages is less than our desired, that would be a - * hole in there. - */ - if (nr_pages < num && whence == SEEK_HOLE) { - found = 1; - *offset = lastoff; + /* The no. of pages is less than our desired, we are done. */ + if (nr_pages < num) break; - } index = pvec.pages[i - 1]->index + 1; pagevec_release(&pvec); } while (index <= end); + if (whence == SEEK_HOLE && lastoff < endoff) { + found = 1; + *offset = lastoff; + } out: pagevec_release(&pvec); return found; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2892a799f6f8..521abc5c743d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2059,7 +2059,7 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd, { struct inode *inode = mpd->inode; int err; - ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1) + ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1) >> inode->i_blkbits; do { @@ -3855,6 +3855,8 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); + if (ret >= 0) + ext4_update_inode_fsync_trans(handle, inode, 1); out_stop: ext4_journal_stop(handle); out_dio: @@ -5230,8 +5232,9 @@ static int ext4_expand_extra_isize(struct inode *inode, /* No extended attributes present */ if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) || header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { - memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0, - new_extra_isize); + memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE + + EXT4_I(inode)->i_extra_isize, 0, + new_extra_isize - EXT4_I(inode)->i_extra_isize); EXT4_I(inode)->i_extra_isize = new_extra_isize; return 0; } diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 7861d801b048..05048fcfd602 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -187,7 +187,7 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to) if (PageUptodate(page)) return 0; - blocksize = 1 << inode->i_blkbits; + blocksize = i_blocksize(inode); if (!page_has_buffers(page)) create_empty_buffers(page, blocksize, 0); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 8f9176caf098..c8d58c5ac8ae 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -758,7 +758,7 @@ static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data, sb->s_blocksize - offset : toread; tmp_bh.b_state = 0; - tmp_bh.b_size = 1 << inode->i_blkbits; + tmp_bh.b_size = i_blocksize(inode); err = jfs_get_block(inode, blk, &tmp_bh, 0); if (err) return err; @@ -798,7 +798,7 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type, sb->s_blocksize - offset : towrite; tmp_bh.b_state = 0; - tmp_bh.b_size = 1 << inode->i_blkbits; + tmp_bh.b_size = i_blocksize(inode); err = jfs_get_block(inode, blk, &tmp_bh, 1); if (err) goto out; diff --git a/fs/mbcache.c b/fs/mbcache.c index ab1da987d1ae..de509271d031 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -222,8 +222,19 @@ __mb_cache_entry_release(struct mb_cache_entry *ce) * then reacquire the lock in the proper order. */ spin_lock(&mb_cache_spinlock); - if (list_empty(&ce->e_lru_list)) - list_add_tail(&ce->e_lru_list, &mb_cache_lru_list); + /* + * Evaluate the conditions under global lock mb_cache_spinlock, + * to check if mb_cache_entry_get() is running now + * and has already deleted the entry from mb_cache_lru_list + * and incremented ce->e_refcnt to prevent further additions + * to mb_cache_lru_list. + */ + if (!(ce->e_used || ce->e_queued || + atomic_read(&ce->e_refcnt))) { + if (list_empty(&ce->e_lru_list)) + list_add_tail(&ce->e_lru_list, + &mb_cache_lru_list); + } spin_unlock(&mb_cache_spinlock); } __spin_unlock_mb_cache_entry(ce); diff --git a/fs/mpage.c b/fs/mpage.c index 0fd48fdcc1b1..f37bb01a333b 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -147,7 +147,7 @@ map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) SetPageUptodate(page); return; } - create_empty_buffers(page, 1 << inode->i_blkbits, 0); + create_empty_buffers(page, i_blocksize(inode), 0); } head = page_buffers(page); page_bh = head; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 52ee0b73ab4a..5b21b1ca2341 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2421,6 +2421,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) } EXPORT_SYMBOL_GPL(nfs_may_open); +static int nfs_execute_ok(struct inode *inode, int mask) +{ + struct nfs_server *server = NFS_SERVER(inode); + int ret; + + if (mask & MAY_NOT_BLOCK) + ret = nfs_revalidate_inode_rcu(server, inode); + else + ret = nfs_revalidate_inode(server, inode); + if (ret == 0 && !execute_ok(inode)) + ret = -EACCES; + return ret; +} + int nfs_permission(struct inode *inode, int mask) { struct rpc_cred *cred; @@ -2438,6 +2452,9 @@ int nfs_permission(struct inode *inode, int mask) case S_IFLNK: goto out; case S_IFREG: + if ((mask & MAY_OPEN) && + nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)) + return 0; break; case S_IFDIR: /* @@ -2470,8 +2487,8 @@ force_lookup: res = PTR_ERR(cred); } out: - if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) - res = -EACCES; + if (!res && (mask & MAY_EXEC)) + res = nfs_execute_ok(inode, mask); dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n", inode->i_sb->s_id, inode->i_ino, mask, res); diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index c29d9421bd5e..0976f8dad4ce 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -50,7 +50,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, { struct nfsd4_layout_seg *seg = &args->lg_seg; struct super_block *sb = inode->i_sb; - u32 block_size = (1 << inode->i_blkbits); + u32 block_size = i_blocksize(inode); struct pnfs_block_extent *bex; struct iomap iomap; u32 device_generation = 0; @@ -151,7 +151,7 @@ nfsd4_block_proc_layoutcommit(struct inode *inode, int error; nr_iomaps = nfsd4_block_decode_layoutupdate(lcp->lc_up_layout, - lcp->lc_up_len, &iomaps, 1 << inode->i_blkbits); + lcp->lc_up_len, &iomaps, i_blocksize(inode)); if (nr_iomaps < 0) return nfserrno(nr_iomaps); diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 7d5351cd67fb..209dbfc50cd4 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1690,6 +1690,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, opdesc->op_get_currentstateid(cstate, &op->u); op->status = opdesc->op_func(rqstp, cstate, &op->u); + /* Only from SEQUENCE */ + if (cstate->status == nfserr_replay_cache) { + dprintk("%s NFS4.1 replay from cache\n", __func__); + status = op->status; + goto out; + } if (!op->status) { if (opdesc->op_set_currentstateid) opdesc->op_set_currentstateid(cstate, &op->u); @@ -1700,14 +1706,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, if (need_wrongsec_check(rqstp)) op->status = check_nfsd_access(current_fh->fh_export, rqstp); } - encode_op: - /* Only from SEQUENCE */ - if (cstate->status == nfserr_replay_cache) { - dprintk("%s NFS4.1 replay from cache\n", __func__); - status = op->status; - goto out; - } if (op->status == nfserr_replay_me) { op->replay = &cstate->replay_owner->so_replay; nfsd4_encode_replay(&resp->xdr, op); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c3e1cb481fe0..3f68a25f2169 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2753,9 +2753,16 @@ out_acl: } #endif /* CONFIG_NFSD_PNFS */ if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { - status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0, - NFSD_SUPPATTR_EXCLCREAT_WORD1, - NFSD_SUPPATTR_EXCLCREAT_WORD2); + u32 supp[3]; + + supp[0] = nfsd_suppattrs0(minorversion); + supp[1] = nfsd_suppattrs1(minorversion); + supp[2] = nfsd_suppattrs2(minorversion); + supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0; + supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1; + supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2; + + status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]); if (status) goto out; } diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index a35ae35e6932..cd39b57288c2 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -55,7 +55,7 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr) brelse(bh); BUG(); } - memset(bh->b_data, 0, 1 << inode->i_blkbits); + memset(bh->b_data, 0, i_blocksize(inode)); bh->b_bdev = inode->i_sb->s_bdev; bh->b_blocknr = blocknr; set_buffer_mapped(bh); diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index ac2f64943ff4..00877ef0b120 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -55,7 +55,7 @@ void nilfs_inode_add_blocks(struct inode *inode, int n) { struct nilfs_root *root = NILFS_I(inode)->i_root; - inode_add_bytes(inode, (1 << inode->i_blkbits) * n); + inode_add_bytes(inode, i_blocksize(inode) * n); if (root) atomic64_add(n, &root->blocks_count); } @@ -64,7 +64,7 @@ void nilfs_inode_sub_blocks(struct inode *inode, int n) { struct nilfs_root *root = NILFS_I(inode)->i_root; - inode_sub_bytes(inode, (1 << inode->i_blkbits) * n); + inode_sub_bytes(inode, i_blocksize(inode) * n); if (root) atomic64_sub(n, &root->blocks_count); } diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 1125f40233ff..612a2457243d 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -60,7 +60,7 @@ nilfs_mdt_insert_new_block(struct inode *inode, unsigned long block, set_buffer_mapped(bh); kaddr = kmap_atomic(bh->b_page); - memset(kaddr + bh_offset(bh), 0, 1 << inode->i_blkbits); + memset(kaddr + bh_offset(bh), 0, i_blocksize(inode)); if (init_block) init_block(inode, bh, kaddr); flush_dcache_page(bh->b_page); @@ -503,7 +503,7 @@ void nilfs_mdt_set_entry_size(struct inode *inode, unsigned entry_size, struct nilfs_mdt_info *mi = NILFS_MDT(inode); mi->mi_entry_size = entry_size; - mi->mi_entries_per_block = (1 << inode->i_blkbits) / entry_size; + mi->mi_entries_per_block = i_blocksize(inode) / entry_size; mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size); } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 3b65adaae7e4..2f27c935bd57 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -719,7 +719,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, lock_page(page); if (!page_has_buffers(page)) - create_empty_buffers(page, 1 << inode->i_blkbits, 0); + create_empty_buffers(page, i_blocksize(inode), 0); unlock_page(page); bh = head = page_buffers(page); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index e6795c7c76a8..e4184bd2a954 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -1103,7 +1103,7 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno, int ret = 0; struct buffer_head *head, *bh, *wait[2], **wait_bh = wait; unsigned int block_end, block_start; - unsigned int bsize = 1 << inode->i_blkbits; + unsigned int bsize = i_blocksize(inode); if (!page_has_buffers(page)) create_empty_buffers(page, bsize, 0); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 56dd3957cc91..1d738723a41a 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -808,7 +808,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from, /* We know that zero_from is block aligned */ for (block_start = zero_from; block_start < zero_to; block_start = block_end) { - block_end = block_start + (1 << inode->i_blkbits); + block_end = block_start + i_blocksize(inode); /* * block_start is block-aligned. Bump it by one to force diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 8f5ccdf81c25..38187300a2b4 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -189,7 +189,7 @@ int reiserfs_commit_page(struct inode *inode, struct page *page, int ret = 0; th.t_trans_id = 0; - blocksize = 1 << inode->i_blkbits; + blocksize = i_blocksize(inode); if (logit) { reiserfs_write_lock(s); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 3d8e7e671d5b..60ba35087d12 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -524,7 +524,7 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, * referenced in convert_tail_for_hole() that may be called from * reiserfs_get_block() */ - bh_result->b_size = (1 << inode->i_blkbits); + bh_result->b_size = i_blocksize(inode); ret = reiserfs_get_block(inode, iblock, bh_result, create | GET_BLOCK_NO_DANGLE); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 00ae21151f52..676e394e07be 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -199,7 +199,8 @@ static struct dentry *__sdcardfs_interpose(struct dentry *dentry, ret_dentry = d_splice_alias(inode, dentry); dentry = ret_dentry ?: dentry; - update_derived_permission_lock(dentry); + if (!IS_ERR(dentry)) + update_derived_permission_lock(dentry); out: return ret_dentry; } diff --git a/fs/stat.c b/fs/stat.c index d4a61d8dc021..004dd77c3b93 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -31,7 +31,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; - stat->blksize = (1 << inode->i_blkbits); + stat->blksize = i_blocksize(inode); stat->blocks = inode->i_blocks; } @@ -454,6 +454,7 @@ void __inode_add_bytes(struct inode *inode, loff_t bytes) inode->i_bytes -= 512; } } +EXPORT_SYMBOL(__inode_add_bytes); void inode_add_bytes(struct inode *inode, loff_t bytes) { diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 566df9b5a6cb..7be3166ba553 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1206,7 +1206,7 @@ int udf_setsize(struct inode *inode, loff_t newsize) { int err; struct udf_inode_info *iinfo; - int bsize = 1 << inode->i_blkbits; + int bsize = i_blocksize(inode); if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index dc5fae601c24..637e17cb0edd 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -81,7 +81,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) ufs_error (sb, "ufs_free_fragments", "bit already cleared for fragment %u", i); } - + + inode_sub_bytes(inode, count << uspi->s_fshift); fs32_add(sb, &ucg->cg_cs.cs_nffree, count); uspi->cs_total.cs_nffree += count; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); @@ -183,6 +184,7 @@ do_more: ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); } ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); + inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); @@ -494,6 +496,20 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, return 0; } +static bool try_add_frags(struct inode *inode, unsigned frags) +{ + unsigned size = frags * i_blocksize(inode); + spin_lock(&inode->i_lock); + __inode_add_bytes(inode, size); + if (unlikely((u32)inode->i_blocks != inode->i_blocks)) { + __inode_sub_bytes(inode, size); + spin_unlock(&inode->i_lock); + return false; + } + spin_unlock(&inode->i_lock); + return true; +} + static u64 ufs_add_fragments(struct inode *inode, u64 fragment, unsigned oldcount, unsigned newcount) { @@ -530,6 +546,9 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, for (i = oldcount; i < newcount; i++) if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) return 0; + + if (!try_add_frags(inode, count)) + return 0; /* * Block can be extended */ @@ -647,6 +666,7 @@ cg_found: ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; + inode_sub_bytes(inode, i << uspi->s_fshift); fs32_add(sb, &ucg->cg_cs.cs_nffree, i); uspi->cs_total.cs_nffree += i; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i); @@ -657,6 +677,8 @@ cg_found: result = ufs_bitmap_search (sb, ucpi, goal, allocsize); if (result == INVBLOCK) return 0; + if (!try_add_frags(inode, count)) + return 0; for (i = 0; i < count; i++) ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i); @@ -716,6 +738,8 @@ norot: return INVBLOCK; ucpi->c_rotor = result; gotit: + if (!try_add_frags(inode, uspi->s_fpb)) + return 0; blkno = ufs_fragstoblks(result); ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index a064cf44b143..1f69bb9b1e9d 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -235,7 +235,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, p = ufs_get_direct_data_ptr(uspi, ufsi, block); tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), - new_size, err, locked_page); + new_size - (lastfrag & uspi->s_fpbmask), err, + locked_page); return tmp != 0; } @@ -284,7 +285,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, goal += uspi->s_fpb; } tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), - goal, uspi->s_fpb, err, locked_page); + goal, nfrags, err, locked_page); if (!tmp) { *err = -ENOSPC; @@ -402,7 +403,9 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff if (!create) { phys64 = ufs_frag_map(inode, offsets, depth); - goto out; + if (phys64) + map_bh(bh_result, sb, phys64 + frag); + return 0; } /* This code entered only while writing ....? */ diff --git a/fs/ufs/super.c b/fs/ufs/super.c index f6390eec02ca..10f364490833 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -746,6 +746,23 @@ static void ufs_put_super(struct super_block *sb) return; } +static u64 ufs_max_bytes(struct super_block *sb) +{ + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + int bits = uspi->s_apbshift; + u64 res; + + if (bits > 21) + res = ~0ULL; + else + res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) + + (1LL << (3*bits)); + + if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift)) + return MAX_LFS_FILESIZE; + return res << uspi->s_bshift; +} + static int ufs_fill_super(struct super_block *sb, void *data, int silent) { struct ufs_sb_info * sbi; @@ -1212,6 +1229,7 @@ magic_found: "fast symlink size (%u)\n", uspi->s_maxsymlinklen); uspi->s_maxsymlinklen = maxsymlen; } + sb->s_maxbytes = ufs_max_bytes(sb); sb->s_max_links = UFS_LINK_MAX; inode = ufs_iget(sb, UFS_ROOTINO); diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 954175928240..3f9463f8cf2f 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -473,15 +473,19 @@ static inline unsigned _ubh_find_last_zero_bit_( static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, unsigned begin, unsigned block) { + u8 mask; switch (uspi->s_fpb) { case 8: return (*ubh_get_addr (ubh, begin + block) == 0xff); case 4: - return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2))); + mask = 0x0f << ((block & 0x01) << 2); + return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask; case 2: - return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1))); + mask = 0x03 << ((block & 0x03) << 1); + return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask; case 1: - return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07))); + mask = 0x01 << (block & 0x07); + return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask; } return 0; } diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 29e7e5dd5178..187b80267ff9 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -288,7 +288,7 @@ xfs_map_blocks( { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; - ssize_t count = 1 << inode->i_blkbits; + ssize_t count = i_blocksize(inode); xfs_fileoff_t offset_fsb, end_fsb; int error = 0; int bmapi_flags = XFS_BMAPI_ENTIRE; @@ -921,7 +921,7 @@ xfs_aops_discard_page( break; } next_buffer: - offset += 1 << inode->i_blkbits; + offset += i_blocksize(inode); } while ((bh = bh->b_this_page) != head); @@ -1363,7 +1363,7 @@ xfs_map_trim_size( offset + mapping_size >= i_size_read(inode)) { /* limit mapping to block that spans EOF */ mapping_size = roundup_64(i_size_read(inode) - offset, - 1 << inode->i_blkbits); + i_blocksize(inode)); } if (mapping_size > LONG_MAX) mapping_size = LONG_MAX; @@ -1395,7 +1395,7 @@ __xfs_get_blocks( return -EIO; offset = (xfs_off_t)iblock << inode->i_blkbits; - ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); + ASSERT(bh_result->b_size >= i_blocksize(inode)); size = bh_result->b_size; if (!create && direct && offset >= i_size_read(inode)) @@ -1968,7 +1968,7 @@ xfs_vm_set_page_dirty( if (offset < end_offset) set_buffer_dirty(bh); bh = bh->b_this_page; - offset += 1 << inode->i_blkbits; + offset += i_blocksize(inode); } while (bh != head); } /* diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index ceea444dafb4..3dd47307363f 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -947,7 +947,7 @@ xfs_file_fallocate( if (error) goto out_unlock; } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { - unsigned blksize_mask = (1 << inode->i_blkbits) - 1; + unsigned int blksize_mask = i_blocksize(inode) - 1; if (offset & blksize_mask || len & blksize_mask) { error = -EINVAL; @@ -969,7 +969,7 @@ xfs_file_fallocate( if (error) goto out_unlock; } else if (mode & FALLOC_FL_INSERT_RANGE) { - unsigned blksize_mask = (1 << inode->i_blkbits) - 1; + unsigned int blksize_mask = i_blocksize(inode) - 1; new_size = i_size_read(inode) + len; if (offset & blksize_mask || len & blksize_mask) { diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index e6dae28dfa1a..9beaf192b4bb 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -180,6 +180,7 @@ xfs_xattr_put_listent( arraytop = context->count + prefix_len + namelen + 1; if (arraytop > context->firstu) { context->count = -1; /* insufficient space */ + context->seen_enough = 1; return 0; } offset = (char *)context->alist + context->count; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index ad2bcf647b9a..210ccc4ea44b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -340,6 +340,26 @@ static inline bool css_tryget_online(struct cgroup_subsys_state *css) } /** + * css_is_dying - test whether the specified css is dying + * @css: target css + * + * Test whether @css is in the process of offlining or already offline. In + * most cases, ->css_online() and ->css_offline() callbacks should be + * enough; however, the actual offline operations are RCU delayed and this + * test returns %true also when @css is scheduled to be offlined. + * + * This is useful, for example, when the use case requires synchronous + * behavior with respect to cgroup removal. cgroup removal schedules css + * offlining but the css can seem alive while the operation is being + * delayed. If the delay affects user visible semantics, this test can be + * used to resolve the situation. + */ +static inline bool css_is_dying(struct cgroup_subsys_state *css) +{ + return !(css->flags & CSS_NO_REF) && percpu_ref_is_dying(&css->refcnt); +} + +/** * css_put - put a css reference * @css: target css * diff --git a/include/linux/fs.h b/include/linux/fs.h index 28c8f7038ae0..4b27be2038e3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -689,6 +689,11 @@ struct inode { void *i_private; /* fs or device private pointer */ }; +static inline unsigned int i_blocksize(const struct inode *node) +{ + return (1 << node->i_blkbits); +} + static inline int inode_unhashed(struct inode *inode) { return hlist_unhashed(&inode->i_hash); diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h index 04a06df66d4b..94f779f6a666 100644 --- a/include/linux/ipc_router.h +++ b/include/linux/ipc_router.h @@ -144,6 +144,7 @@ struct msm_ipc_port { uint32_t num_rx; unsigned long num_tx_bytes; unsigned long num_rx_bytes; + uint32_t last_served_svc_id; void *priv; }; diff --git a/include/linux/memblock.h b/include/linux/memblock.h index ab93174fa639..d4b56351027b 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -424,12 +424,20 @@ static inline void early_memtest(phys_addr_t start, phys_addr_t end) } #endif +extern unsigned long memblock_reserved_memory_within(phys_addr_t start_addr, + phys_addr_t end_addr); #else static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align) { return 0; } +static inline unsigned long memblock_reserved_memory_within(phys_addr_t start_addr, + phys_addr_t end_addr) +{ + return 0; +} + #endif /* CONFIG_HAVE_MEMBLOCK */ #endif /* __KERNEL__ */ diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ad7f915ddf76..9d1161a8d6b7 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -712,6 +712,7 @@ typedef struct pglist_data { * is the first PFN that needs to be initialised. */ unsigned long first_deferred_pfn; + unsigned long static_init_size; #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ } pg_data_t; diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index d4b4cc7f8737..b95ea88c2424 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -749,6 +749,18 @@ int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl, uint32_t *db_addr_wp_lsb, uint32_t *db_addr_wp_msb); /** + * gsi_ring_evt_ring_db - Peripheral should call this function for + * ringing the event ring doorbell with given value + * + * @evt_ring_hdl: Client handle previously obtained from + * gsi_alloc_evt_ring + * @value: The value to be used for ringing the doorbell + * + * @Return gsi_status + */ +int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value); + +/** * gsi_reset_evt_ring - Peripheral should call this function to * reset an event ring to recover from error state * @@ -1138,6 +1150,12 @@ static inline int gsi_query_evt_ring_db_addr(unsigned long evt_ring_hdl, return -GSI_STATUS_UNSUPPORTED_OP; } +static inline int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, + uint64_t value) +{ + return -GSI_STATUS_UNSUPPORTED_OP; +} + static inline int gsi_reset_evt_ring(unsigned long evt_ring_hdl) { return -GSI_STATUS_UNSUPPORTED_OP; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 5cc13e9fbd8f..b584e353306d 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -271,6 +271,7 @@ enum power_supply_type { POWER_SUPPLY_TYPE_USB_HVDCP_3, /* Efficient High Voltage DCP */ POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery */ POWER_SUPPLY_TYPE_WIRELESS, /* Accessory Charger Adapters */ + POWER_SUPPLY_TYPE_USB_FLOAT, /* Floating charger */ POWER_SUPPLY_TYPE_BMS, /* Battery Monitor System */ POWER_SUPPLY_TYPE_PARALLEL, /* Parallel Path */ POWER_SUPPLY_TYPE_MAIN, /* Main Path */ diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index e13bfdf7f314..81fdf4b8aba4 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -50,7 +50,8 @@ extern int ptrace_request(struct task_struct *child, long request, unsigned long addr, unsigned long data); extern void ptrace_notify(int exit_code); extern void __ptrace_link(struct task_struct *child, - struct task_struct *new_parent); + struct task_struct *new_parent, + const struct cred *ptracer_cred); extern void __ptrace_unlink(struct task_struct *child); extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead); #define PTRACE_MODE_READ 0x01 @@ -202,7 +203,7 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) if (unlikely(ptrace) && current->ptrace) { child->ptrace = current->ptrace; - __ptrace_link(child, current->parent); + __ptrace_link(child, current->parent, current->ptracer_cred); if (child->ptrace & PT_SEIZED) task_set_jobctl_pending(child, JOBCTL_TRAP_STOP); @@ -211,6 +212,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) set_tsk_thread_flag(child, TIF_SIGPENDING); } + else + child->ptracer_cred = NULL; } /** diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d443d9ab0236..3f61c647fc5c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1084,9 +1084,6 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) static inline void skb_sender_cpu_clear(struct sk_buff *skb) { -#ifdef CONFIG_XPS - skb->sender_cpu = 0; -#endif } #ifdef NET_SKBUFF_DATA_USES_OFFSET diff --git a/include/linux/usb.h b/include/linux/usb.h index a55f127d6836..e8b2ed4ad851 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -330,6 +330,8 @@ struct usb_host_bos { struct usb_ss_cap_descriptor *ss_cap; struct usb_ssp_cap_descriptor *ssp_cap; struct usb_ss_container_id_descriptor *ss_id; + struct usb_config_summary_descriptor *config_summary; + unsigned int num_config_summary_desc; }; int __usb_get_extra_descriptor(char *buffer, unsigned size, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9a5c9f013784..ad1d6039185d 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -958,6 +958,7 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row, */ extern const struct proto_ops inet6_stream_ops; extern const struct proto_ops inet6_dgram_ops; +extern const struct proto_ops inet6_sockraw_ops; struct group_source_req; struct group_filter; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 7f203a5f83cb..b3a2c62da965 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -241,8 +241,23 @@ extern "C" { */ #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +/* + * QTI DX Format + * + * Refers to a DX variant of the base format. + * Implementation may be platform and base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2) + +/* + * QTI Tight Format + * + * Refers to a tightly packed variant of the base format. + * Implementation may be platform and base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4) + #if defined(__cplusplus) } #endif - #endif /* DRM_FOURCC_H */ diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d8b8ef16b14a..a60e84ab905b 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -62,6 +62,41 @@ struct drm_msm_timespec { __s64 tv_nsec; /* nanoseconds */ }; +/* + * HDR Metadata + * These are defined as per EDID spec and shall be used by the sink + * to set the HDR metadata for playback from userspace. + */ + +#define HDR_PRIMARIES_COUNT 3 + +struct drm_msm_ext_panel_hdr_metadata { + __u32 eotf; /* electro optical transfer function */ + __u32 hdr_supported; /* HDR supported */ + __u32 display_primaries_x[HDR_PRIMARIES_COUNT]; /* Primaries x */ + __u32 display_primaries_y[HDR_PRIMARIES_COUNT]; /* Primaries y */ + __u32 white_point_x; /* white_point_x */ + __u32 white_point_y; /* white_point_y */ + __u32 max_luminance; /* Max luminance */ + __u32 min_luminance; /* Min Luminance */ + __u32 max_content_light_level; /* max content light level */ + __u32 max_average_light_level; /* max average light level */ +}; + +/** + * HDR sink properties + * These are defined as per EDID spec and shall be used by the userspace + * to determine the HDR properties to be set to the sink. + */ +struct drm_msm_ext_panel_hdr_properties { + __u8 hdr_metadata_type_one; /* static metadata type one */ + __u32 hdr_supported; /* HDR supported */ + __u32 hdr_eotf; /* electro optical transfer function */ + __u32 hdr_max_luminance; /* Max luminance */ + __u32 hdr_avg_luminance; /* Avg luminance */ + __u32 hdr_min_luminance; /* Min Luminance */ +}; + #define MSM_PARAM_GPU_ID 0x01 #define MSM_PARAM_GMEM_SIZE 0x02 #define MSM_PARAM_CHIP_ID 0x03 diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index 779a62aafafe..d3ab3f57aa9f 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -894,6 +894,29 @@ struct usb_ssp_cap_descriptor { #define USB_SSP_SUBLINK_SPEED_LSM (0xff << 16) /* Lanespeed mantissa */ } __attribute__((packed)); +/* + * Configuration Summary descriptors: Defines a list of functions in the + * configuration. This descriptor may be used by Host software to decide + * which Configuration to use to obtain the desired functionality. + */ +#define USB_CAP_TYPE_CONFIG_SUMMARY 0x10 + +struct function_class_info { + __u8 bClass; + __u8 bSubClass; + __u8 bProtocol; +}; + +struct usb_config_summary_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; + __u16 bcdVersion; + __u8 bConfigurationValue; + __u8 bMaxPower; + __u8 bNumFunctions; + struct function_class_info cs_info[]; +} __attribute__((packed)); /*-------------------------------------------------------------------------*/ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 29c7240172d3..03dbc231a4a0 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -174,9 +174,9 @@ typedef enum { } cpuset_flagbits_t; /* convenient tests for these bits */ -static inline bool is_cpuset_online(const struct cpuset *cs) +static inline bool is_cpuset_online(struct cpuset *cs) { - return test_bit(CS_ONLINE, &cs->flags); + return test_bit(CS_ONLINE, &cs->flags) && !css_is_dying(&cs->css); } static inline int is_cpu_exclusive(const struct cpuset *cs) diff --git a/kernel/events/core.c b/kernel/events/core.c index 95c447e658f7..7fee87daac56 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1693,33 +1693,7 @@ static int __perf_remove_from_context(void *info) return 0; } - -#ifdef CONFIG_SMP -static void perf_retry_remove(struct perf_event *event, - struct remove_event *rep) -{ - int up_ret; - /* - * CPU was offline. Bring it online so we can - * gracefully exit a perf context. - */ - up_ret = cpu_up(event->cpu); - if (!up_ret) - /* Try the remove call once again. */ - cpu_function_call(event->cpu, __perf_remove_from_context, - rep); - else - pr_err("Failed to bring up CPU: %d, ret: %d\n", - event->cpu, up_ret); -} -#else -static void perf_retry_remove(struct perf_event *event, - struct remove_event *rep) -{ -} -#endif - - /* +/* * Remove the event from a task's (or a CPU's) list of events. * * CPU events are removed with a smp call. For task events we only @@ -1754,9 +1728,6 @@ static void __ref perf_remove_from_context(struct perf_event *event, */ ret = cpu_function_call(event->cpu, __perf_remove_from_context, &re); - if (ret == -ENXIO) - perf_retry_remove(event, &re); - return; } @@ -6595,6 +6566,21 @@ static void perf_log_itrace_start(struct perf_event *event) perf_output_end(&handle); } +static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs) +{ + /* + * Due to interrupt latency (AKA "skid"), we may enter the + * kernel before taking an overflow, even if the PMU is only + * counting user events. + * To avoid leaking information to userspace, we must always + * reject kernel samples when exclude_kernel is set. + */ + if (event->attr.exclude_kernel && !user_mode(regs)) + return false; + + return true; +} + /* * Generic event overflow handling, sampling. */ @@ -6642,6 +6628,12 @@ static int __perf_event_overflow(struct perf_event *event, } /* + * For security, drop the skid kernel samples if necessary. + */ + if (!sample_is_allowed(event, regs)) + return ret; + + /* * XXX event_limit might not quite work as expected on inherited * events */ @@ -7117,8 +7109,6 @@ static struct pmu perf_swevent = { .start = perf_swevent_start, .stop = perf_swevent_stop, .read = perf_swevent_read, - - .events_across_hotplug = 1, }; #ifdef CONFIG_EVENT_TRACING @@ -7240,8 +7230,6 @@ static struct pmu perf_tracepoint = { .start = perf_swevent_start, .stop = perf_swevent_stop, .read = perf_swevent_read, - - .events_across_hotplug = 1, }; static inline void perf_tp_register(void) @@ -7529,8 +7517,6 @@ static struct pmu perf_cpu_clock = { .start = cpu_clock_event_start, .stop = cpu_clock_event_stop, .read = cpu_clock_event_read, - - .events_across_hotplug = 1, }; /* @@ -7612,8 +7598,6 @@ static struct pmu perf_task_clock = { .start = task_clock_event_start, .stop = task_clock_event_stop, .read = task_clock_event_read, - - .events_across_hotplug = 1, }; static void perf_pmu_nop_void(struct pmu *pmu) diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 7da5b674d16e..92ce5f4ccc26 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -614,8 +614,6 @@ static struct pmu perf_breakpoint = { .start = hw_breakpoint_start, .stop = hw_breakpoint_stop, .read = hw_breakpoint_pmu_read, - - .events_across_hotplug = 1, }; int __init init_hw_breakpoint(void) diff --git a/kernel/fork.c b/kernel/fork.c index 2845c5bdc8e3..246b8a57a32d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -370,7 +370,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) set_task_stack_end_magic(tsk); #ifdef CONFIG_CC_STACKPROTECTOR - tsk->stack_canary = get_random_int(); + tsk->stack_canary = get_random_long(); #endif /* diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c7e8ed99c953..5e2cd1030702 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -28,19 +28,25 @@ #include <linux/compat.h> +void __ptrace_link(struct task_struct *child, struct task_struct *new_parent, + const struct cred *ptracer_cred) +{ + BUG_ON(!list_empty(&child->ptrace_entry)); + list_add(&child->ptrace_entry, &new_parent->ptraced); + child->parent = new_parent; + child->ptracer_cred = get_cred(ptracer_cred); +} + /* * ptrace a task: make the debugger its new parent and * move it to the ptrace list. * * Must be called with the tasklist lock write-held. */ -void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) +static void ptrace_link(struct task_struct *child, struct task_struct *new_parent) { - BUG_ON(!list_empty(&child->ptrace_entry)); - list_add(&child->ptrace_entry, &new_parent->ptraced); - child->parent = new_parent; rcu_read_lock(); - child->ptracer_cred = get_cred(__task_cred(new_parent)); + __ptrace_link(child, new_parent, __task_cred(new_parent)); rcu_read_unlock(); } @@ -353,7 +359,7 @@ static int ptrace_attach(struct task_struct *task, long request, flags |= PT_SEIZED; task->ptrace = flags; - __ptrace_link(task, current); + ptrace_link(task, current); /* SEIZE doesn't trap tracee on attach */ if (!seize) @@ -420,7 +426,7 @@ static int ptrace_traceme(void) */ if (!ret && !(current->real_parent->flags & PF_EXITING)) { current->ptrace = PT_PTRACED; - __ptrace_link(current, current->real_parent); + ptrace_link(current, current->real_parent); } } write_unlock_irq(&tasklist_lock); diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c index 0ecef3e4690e..5e6db6b1e3bd 100644 --- a/lib/test_user_copy.c +++ b/lib/test_user_copy.c @@ -58,7 +58,9 @@ static int __init test_user_copy_init(void) usermem = (char __user *)user_addr; bad_usermem = (char *)user_addr; - /* Legitimate usage: none of these should fail. */ + /* + * Legitimate usage: none of these copies should fail. + */ ret |= test(copy_from_user(kmem, usermem, PAGE_SIZE), "legitimate copy_from_user failed"); ret |= test(copy_to_user(usermem, kmem, PAGE_SIZE), @@ -68,19 +70,33 @@ static int __init test_user_copy_init(void) ret |= test(put_user(value, (unsigned long __user *)usermem), "legitimate put_user failed"); - /* Invalid usage: none of these should succeed. */ + /* + * Invalid usage: none of these copies should succeed. + */ + + /* Reject kernel-to-kernel copies through copy_from_user(). */ ret |= test(!copy_from_user(kmem, (char __user *)(kmem + PAGE_SIZE), PAGE_SIZE), "illegal all-kernel copy_from_user passed"); + +#if 0 + /* + * When running with SMAP/PAN/etc, this will Oops the kernel + * due to the zeroing of userspace memory on failure. This needs + * to be tested in LKDTM instead, since this test module does not + * expect to explode. + */ ret |= test(!copy_from_user(bad_usermem, (char __user *)kmem, PAGE_SIZE), "illegal reversed copy_from_user passed"); +#endif ret |= test(!copy_to_user((char __user *)kmem, kmem + PAGE_SIZE, PAGE_SIZE), "illegal all-kernel copy_to_user passed"); ret |= test(!copy_to_user((char __user *)kmem, bad_usermem, PAGE_SIZE), "illegal reversed copy_to_user passed"); + ret |= test(!get_user(value, (unsigned long __user *)kmem), "illegal get_user passed"); ret |= test(!put_user(value, (unsigned long __user *)kmem), diff --git a/mm/memblock.c b/mm/memblock.c index 89e74fa82290..351a4840a407 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1688,6 +1688,30 @@ static void __init_memblock memblock_dump(struct memblock_type *type, char *name } } +extern unsigned long __init_memblock +memblock_reserved_memory_within(phys_addr_t start_addr, phys_addr_t end_addr) +{ + struct memblock_type *type = &memblock.reserved; + unsigned long size = 0; + int idx; + + for (idx = 0; idx < type->cnt; idx++) { + struct memblock_region *rgn = &type->regions[idx]; + phys_addr_t start, end; + + if (rgn->base + rgn->size < start_addr) + continue; + if (rgn->base > end_addr) + continue; + + start = rgn->base; + end = start + rgn->size; + size += end - start; + } + + return size; +} + void __init_memblock __memblock_dump_all(void) { pr_info("MEMBLOCK configuration:\n"); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 170c1486e5c9..4fbb23c1cba7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -274,6 +274,26 @@ int page_group_by_mobility_disabled __read_mostly; #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT static inline void reset_deferred_meminit(pg_data_t *pgdat) { + unsigned long max_initialise; + unsigned long reserved_lowmem; + + /* + * Initialise at least 2G of a node but also take into account that + * two large system hashes that can take up 1GB for 0.25TB/node. + */ + max_initialise = max(2UL << (30 - PAGE_SHIFT), + (pgdat->node_spanned_pages >> 8)); + + /* + * Compensate the all the memblock reservations (e.g. crash kernel) + * from the initial estimation to make sure we will initialize enough + * memory to boot. + */ + reserved_lowmem = memblock_reserved_memory_within(pgdat->node_start_pfn, + pgdat->node_start_pfn + max_initialise); + max_initialise += reserved_lowmem; + + pgdat->static_init_size = min(max_initialise, pgdat->node_spanned_pages); pgdat->first_deferred_pfn = ULONG_MAX; } @@ -307,10 +327,9 @@ static inline bool update_defer_init(pg_data_t *pgdat, /* Always populate low zones for address-contrained allocations */ if (zone_end < pgdat_end_pfn(pgdat)) return true; - /* Initialise at least 2G of the highest zone */ (*nr_initialised)++; - if (*nr_initialised > (2UL << (30 - PAGE_SHIFT)) && + if ((*nr_initialised > pgdat->static_init_size) && (pfn & (PAGES_PER_SECTION - 1)) == 0) { pgdat->first_deferred_pfn = pfn; return false; @@ -5456,7 +5475,6 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, /* pg_data_t should be reset to zero when it's allocated */ WARN_ON(pgdat->nr_zones || pgdat->classzone_idx); - reset_deferred_meminit(pgdat); pgdat->node_id = nid; pgdat->node_start_pfn = node_start_pfn; #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP @@ -5475,6 +5493,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, (unsigned long)pgdat->node_mem_map); #endif + reset_deferred_meminit(pgdat); free_area_init_core(pgdat); } diff --git a/mm/truncate.c b/mm/truncate.c index 30c2f059a488..8ca20a98c327 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -799,7 +799,7 @@ EXPORT_SYMBOL(truncate_setsize); */ void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to) { - int bsize = 1 << inode->i_blkbits; + int bsize = i_blocksize(inode); loff_t rounded_from; struct page *page; pgoff_t index; diff --git a/mm/vmstat.c b/mm/vmstat.c index b8f2eda3381d..d6b4817c4416 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -906,6 +906,7 @@ static void frag_stop(struct seq_file *m, void *arg) /* Walk all the zones in a node and print using a callback */ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, + bool nolock, void (*print)(struct seq_file *m, pg_data_t *, struct zone *)) { struct zone *zone; @@ -916,9 +917,11 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, if (!populated_zone(zone)) continue; - spin_lock_irqsave(&zone->lock, flags); + if (!nolock) + spin_lock_irqsave(&zone->lock, flags); print(m, pgdat, zone); - spin_unlock_irqrestore(&zone->lock, flags); + if (!nolock) + spin_unlock_irqrestore(&zone->lock, flags); } } #endif @@ -954,7 +957,7 @@ static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, static int frag_show(struct seq_file *m, void *arg) { pg_data_t *pgdat = (pg_data_t *)arg; - walk_zones_in_node(m, pgdat, frag_show_print); + walk_zones_in_node(m, pgdat, false, frag_show_print); return 0; } @@ -995,7 +998,7 @@ static int pagetypeinfo_showfree(struct seq_file *m, void *arg) seq_printf(m, "%6d ", order); seq_putc(m, '\n'); - walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print); + walk_zones_in_node(m, pgdat, false, pagetypeinfo_showfree_print); return 0; } @@ -1044,7 +1047,7 @@ static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg) for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) seq_printf(m, "%12s ", migratetype_names[mtype]); seq_putc(m, '\n'); - walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print); + walk_zones_in_node(m, pgdat, false, pagetypeinfo_showblockcount_print); return 0; } @@ -1088,7 +1091,11 @@ static void pagetypeinfo_showmixedcount_print(struct seq_file *m, page = pfn_to_page(pfn); if (PageBuddy(page)) { - pfn += (1UL << page_order(page)) - 1; + unsigned long freepage_order; + + freepage_order = page_order_unsafe(page); + if (freepage_order < MAX_ORDER) + pfn += (1UL << freepage_order) - 1; continue; } @@ -1143,7 +1150,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat) seq_printf(m, "%12s ", migratetype_names[mtype]); seq_putc(m, '\n'); - walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print); + walk_zones_in_node(m, pgdat, true, pagetypeinfo_showmixedcount_print); #endif /* CONFIG_PAGE_OWNER */ } @@ -1276,7 +1283,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, static int zoneinfo_show(struct seq_file *m, void *arg) { pg_data_t *pgdat = (pg_data_t *)arg; - walk_zones_in_node(m, pgdat, zoneinfo_show_print); + walk_zones_in_node(m, pgdat, false, zoneinfo_show_print); return 0; } @@ -1635,7 +1642,7 @@ static int unusable_show(struct seq_file *m, void *arg) if (!node_state(pgdat->node_id, N_MEMORY)) return 0; - walk_zones_in_node(m, pgdat, unusable_show_print); + walk_zones_in_node(m, pgdat, false, unusable_show_print); return 0; } @@ -1687,7 +1694,7 @@ static int extfrag_show(struct seq_file *m, void *arg) { pg_data_t *pgdat = (pg_data_t *)arg; - walk_zones_in_node(m, pgdat, extfrag_show_print); + walk_zones_in_node(m, pgdat, false, extfrag_show_print); return 0; } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 57be733a99bc..bcb4559e735d 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -166,7 +166,8 @@ static void br_stp_start(struct net_bridge *br) br_debug(br, "using kernel STP\n"); /* To start timers on any ports left in blocking */ - mod_timer(&br->hello_timer, jiffies + br->hello_time); + if (br->dev->flags & IFF_UP) + mod_timer(&br->hello_timer, jiffies + br->hello_time); br_port_state_selection(br); } diff --git a/net/core/dev.c b/net/core/dev.c index 57922df9c250..50e77fe096f4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -184,7 +184,7 @@ EXPORT_SYMBOL(dev_base_lock); /* protects napi_hash addition/deletion and napi_gen_id */ static DEFINE_SPINLOCK(napi_hash_lock); -static unsigned int napi_gen_id; +static unsigned int napi_gen_id = NR_CPUS; static DEFINE_HASHTABLE(napi_hash, 8); static seqcount_t devnet_rename_seq; @@ -3055,7 +3055,9 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev, int queue_index = 0; #ifdef CONFIG_XPS - if (skb->sender_cpu == 0) + u32 sender_cpu = skb->sender_cpu - 1; + + if (sender_cpu >= (u32)NR_CPUS) skb->sender_cpu = raw_smp_processor_id() + 1; #endif @@ -4745,25 +4747,22 @@ EXPORT_SYMBOL_GPL(napi_by_id); void napi_hash_add(struct napi_struct *napi) { - if (!test_and_set_bit(NAPI_STATE_HASHED, &napi->state)) { + if (test_and_set_bit(NAPI_STATE_HASHED, &napi->state)) + return; - spin_lock(&napi_hash_lock); + spin_lock(&napi_hash_lock); - /* 0 is not a valid id, we also skip an id that is taken - * we expect both events to be extremely rare - */ - napi->napi_id = 0; - while (!napi->napi_id) { - napi->napi_id = ++napi_gen_id; - if (napi_by_id(napi->napi_id)) - napi->napi_id = 0; - } + /* 0..NR_CPUS+1 range is reserved for sender_cpu use */ + do { + if (unlikely(++napi_gen_id < NR_CPUS + 1)) + napi_gen_id = NR_CPUS + 1; + } while (napi_by_id(napi_gen_id)); + napi->napi_id = napi_gen_id; - hlist_add_head_rcu(&napi->napi_hash_node, - &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]); + hlist_add_head_rcu(&napi->napi_hash_node, + &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]); - spin_unlock(&napi_hash_lock); - } + spin_unlock(&napi_hash_lock); } EXPORT_SYMBOL_GPL(napi_hash_add); diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index f08aef9509bb..5cb309a11f82 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -364,6 +364,8 @@ static void ipc_router_log_msg(void *log_ctx, uint32_t xchng_type, svcId = rport_ptr->server->name.service; svcIns = rport_ptr->server->name.instance; port_type = CLIENT_PORT; + port_ptr->last_served_svc_id = + rport_ptr->server->name.service; } else if (port_ptr && (port_ptr->type == SERVER_PORT)) { svcId = port_ptr->port_name.service; svcIns = port_ptr->port_name.instance; @@ -1329,8 +1331,9 @@ struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint, mutex_init(&port_ptr->port_rx_q_lock_lhc3); init_waitqueue_head(&port_ptr->port_rx_wait_q); snprintf(port_ptr->rx_ws_name, MAX_WS_NAME_SZ, - "ipc%08x_%s", + "ipc%08x_%d_%s", port_ptr->this_port.port_id, + task_pid_nr(current), current->comm); port_ptr->port_rx_ws = wakeup_source_register(port_ptr->rx_ws_name); if (!port_ptr->port_rx_ws) { @@ -3867,16 +3870,18 @@ static void dump_local_ports(struct seq_file *s) int j; struct msm_ipc_port *port_ptr; - seq_printf(s, "%-11s|%-11s|\n", - "Node_id", "Port_id"); + seq_printf(s, "%-11s|%-11s|%-32s|%-11s|\n", + "Node_id", "Port_id", "Wakelock", "Last SVCID"); seq_puts(s, "------------------------------------------------------------\n"); down_read(&local_ports_lock_lhc2); for (j = 0; j < LP_HASH_SIZE; j++) { list_for_each_entry(port_ptr, &local_ports[j], list) { mutex_lock(&port_ptr->port_lock_lhc3); - seq_printf(s, "0x%08x |0x%08x |\n", - port_ptr->this_port.node_id, - port_ptr->this_port.port_id); + seq_printf(s, "0x%08x |0x%08x |%-32s|0x%08x |\n", + port_ptr->this_port.node_id, + port_ptr->this_port.port_id, + port_ptr->rx_ws_name, + port_ptr->last_served_svc_id); mutex_unlock(&port_ptr->port_lock_lhc3); } } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c9ef99fbd0dd..aad274c67b5e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1035,7 +1035,7 @@ static struct inet_protosw inetsw_array[] = .type = SOCK_DGRAM, .protocol = IPPROTO_ICMP, .prot = &ping_prot, - .ops = &inet_dgram_ops, + .ops = &inet_sockraw_ops, .flags = INET_PROTOSW_REUSE, }, diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 882caa4e72bc..aafe68134763 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -183,6 +183,7 @@ void tcp_init_congestion_control(struct sock *sk) { const struct inet_connection_sock *icsk = inet_csk(sk); + tcp_sk(sk)->prior_ssthresh = 0; if (icsk->icsk_ca_ops->init) icsk->icsk_ca_ops->init(sk); if (tcp_ca_needs_ecn(sk)) diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index beb4294e9fda..c612daad9e92 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -121,8 +121,10 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, if (udpfrag) { int err = ip6_find_1stfragopt(skb, &prevhdr); - if (err < 0) + if (err < 0) { + kfree_skb_list(segs); return ERR_PTR(err); + } fptr = (struct frag_hdr *)((u8 *)ipv6h + err); fptr->frag_off = htons(offset); if (skb->next) diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 1737fc0f2988..4c753f4a3712 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -50,7 +50,7 @@ static struct inet_protosw pingv6_protosw = { .type = SOCK_DGRAM, .protocol = IPPROTO_ICMPV6, .prot = &pingv6_prot, - .ops = &inet6_dgram_ops, + .ops = &inet6_sockraw_ops, .flags = INET_PROTOSW_REUSE, }; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d13ed145e93a..0ef8e114c8ab 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1304,7 +1304,7 @@ void raw6_proc_exit(void) #endif /* CONFIG_PROC_FS */ /* Same as inet6_dgram_ops, sans udp_poll. */ -static const struct proto_ops inet6_sockraw_ops = { +const struct proto_ops inet6_sockraw_ops = { .family = PF_INET6, .owner = THIS_MODULE, .release = inet6_release, diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 0e015906f9ca..07d36573f50b 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c @@ -47,6 +47,8 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); + if (hdr_len < 0) + return hdr_len; skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_set_network_header(skb, -x->props.header_len); skb->transport_header = skb->network_header + hdr_len; diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index 4e344105b3fd..1d3bbe6e1183 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c @@ -28,6 +28,8 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) iph = ipv6_hdr(skb); hdr_len = x->type->hdr_offset(x, skb, &prevhdr); + if (hdr_len < 0) + return hdr_len; skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); skb_set_network_header(skb, -x->props.header_len); skb->transport_header = skb->network_header + hdr_len; diff --git a/security/keys/key.c b/security/keys/key.c index 534808915371..09c10b181881 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -934,12 +934,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) /* the key must be writable */ ret = key_permission(key_ref, KEY_NEED_WRITE); if (ret < 0) - goto error; + return ret; /* attempt to update it if supported */ - ret = -EOPNOTSUPP; if (!key->type->update) - goto error; + return -EOPNOTSUPP; memset(&prep, 0, sizeof(prep)); prep.data = payload; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 442e350c209d..671709d8610d 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -97,7 +97,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, /* pull the payload in if one was supplied */ payload = NULL; - if (_payload) { + if (plen) { ret = -ENOMEM; payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN); if (!payload) { @@ -327,7 +327,7 @@ long keyctl_update_key(key_serial_t id, /* pull the payload in if one was supplied */ payload = NULL; - if (_payload) { + if (plen) { ret = -ENOMEM; payload = kmalloc(plen, GFP_KERNEL); if (!payload) diff --git a/sound/core/timer.c b/sound/core/timer.c index 30b28e80c6e6..f0675acecc93 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1625,6 +1625,7 @@ static int snd_timer_user_tselect(struct file *file, if (err < 0) goto __err; + tu->qhead = tu->qtail = tu->qused = 0; kfree(tu->queue); tu->queue = NULL; kfree(tu->tqueue); @@ -1962,6 +1963,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu = file->private_data; unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { while (!tu->qused) { @@ -1977,7 +1979,9 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, add_wait_queue(&tu->qchange_sleep, &wait); spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); schedule(); + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); remove_wait_queue(&tu->qchange_sleep, &wait); @@ -1997,7 +2001,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu->qused--; spin_unlock_irq(&tu->qlock); - mutex_lock(&tu->ioctl_lock); if (tu->tread) { if (copy_to_user(buffer, &tu->tqueue[qhead], sizeof(struct snd_timer_tread))) @@ -2007,7 +2010,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, sizeof(struct snd_timer_read))) err = -EFAULT; } - mutex_unlock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); if (err < 0) @@ -2017,6 +2019,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, } _error: spin_unlock_irq(&tu->qlock); + mutex_unlock(&tu->ioctl_lock); return result > 0 ? result : err; } diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c index 61dd478b97e4..28aaf2172221 100644 --- a/sound/soc/msm/qdsp6v2/q6adm.c +++ b/sound/soc/msm/qdsp6v2/q6adm.c @@ -1999,13 +1999,11 @@ static struct cal_block_data *adm_find_cal_by_path(int cal_index, int path) if (cal_index == ADM_AUDPROC_CAL) { audproc_cal_info = cal_block->cal_info; - if ((audproc_cal_info->path == path) && - (cal_block->cal_data.size > 0)) + if (audproc_cal_info->path == path) return cal_block; } else if (cal_index == ADM_AUDVOL_CAL) { audvol_cal_info = cal_block->cal_info; - if ((audvol_cal_info->path == path) && - (cal_block->cal_data.size > 0)) + if (audvol_cal_info->path == path) return cal_block; } } @@ -2032,14 +2030,12 @@ static struct cal_block_data *adm_find_cal_by_app_type(int cal_index, int path, if (cal_index == ADM_AUDPROC_CAL) { audproc_cal_info = cal_block->cal_info; if ((audproc_cal_info->path == path) && - (audproc_cal_info->app_type == app_type) && - (cal_block->cal_data.size > 0)) + (audproc_cal_info->app_type == app_type)) return cal_block; } else if (cal_index == ADM_AUDVOL_CAL) { audvol_cal_info = cal_block->cal_info; if ((audvol_cal_info->path == path) && - (audvol_cal_info->app_type == app_type) && - (cal_block->cal_data.size > 0)) + (audvol_cal_info->app_type == app_type)) return cal_block; } } @@ -2070,15 +2066,13 @@ static struct cal_block_data *adm_find_cal(int cal_index, int path, if ((audproc_cal_info->path == path) && (audproc_cal_info->app_type == app_type) && (audproc_cal_info->acdb_id == acdb_id) && - (audproc_cal_info->sample_rate == sample_rate) && - (cal_block->cal_data.size > 0)) + (audproc_cal_info->sample_rate == sample_rate)) return cal_block; } else if (cal_index == ADM_AUDVOL_CAL) { audvol_cal_info = cal_block->cal_info; if ((audvol_cal_info->path == path) && (audvol_cal_info->app_type == app_type) && - (audvol_cal_info->acdb_id == acdb_id) && - (cal_block->cal_data.size > 0)) + (audvol_cal_info->acdb_id == acdb_id)) return cal_block; } } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cac2d4975a15..e63b4346e82e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1792,6 +1792,9 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) for (i = 0; i < card->num_aux_devs; i++) soc_remove_aux_dev(card, i); + /* free the ALSA card at first; this syncs with pending operations */ + snd_card_free(card->snd_card); + /* remove and free each DAI */ soc_remove_dai_links(card); @@ -1803,9 +1806,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) snd_soc_dapm_free(&card->dapm); - snd_card_free(card->snd_card); return 0; - } /* removes a socdev */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 70dfdd22102e..d5cc315a5eb4 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1012,6 +1012,17 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 384; } break; + + case USB_ID(0x1130, 0x1620): /* Logitech Speakers S150 */ + /* This audio device has 2 channels and it explicitly requires the + * host to send SET_CUR command on the volume control of both the + * channels. 7936 = 0x1F00 is the default value. + */ + if (cval->channels == 2) + snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, + (cval->control << 8) | 2, 7936); + break; + } } |
