Merge "msm: vidc: Free up remaining memory in close session"
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index d4a352b..18386ab 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -39,6 +39,8 @@
- System Trace Macrocell:
"arm,coresight-stm", "arm,primecell"; [1]
+ - Trigger Generation Unit:
+ "arm,primecell";
* reg: physical base address and length of the register
set(s) of the component.
@@ -86,6 +88,16 @@
* qcom,dummy-sink: Configure the device as sink.
+* Additional required property for coresight-tgu devices:
+ * tgu-steps: must be present. Indicates number of steps supported
+ by the TGU.
+ * tgu-conditions: must be present. Indicates the number of conditions
+ supported by the TGU.
+ * tgu-regs: must be present. Indicates the number of regs supported
+ by the TGU.
+ * tgu-timer-counters: must be present. Indicates the number of timers and
+ counters available in the TGU to do a comparision.
+
* Optional properties for all components:
* reg-names: names corresponding to each reg property value.
@@ -388,7 +400,7 @@
};
};
-4. CTIs
+5. CTIs
cti0: cti@6010000 {
compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x6010000 0x1000>;
@@ -400,5 +412,21 @@
clock-names = "apb_pclk";
};
+6. TGUs
+ ipcb_tgu: tgu@6b0c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b999>;
+ reg = <0x06B0C000 0x1000>;
+ reg-names = "tgu-base";
+ tgu-steps = <3>;
+ tgu-conditions = <4>;
+ tgu-regs = <4>;
+ tgu-timer-counters = <8>;
+
+ coresight-name = "coresight-tgu-ipcb";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
[1]. There is currently two version of STM: STM32 and STM500. Both
have the same HW interface and as such don't need an explicit binding name.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index b3f3431..0d955ed 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -139,6 +139,7 @@
the command DB driver.
qcom,drv-id: The DRV id associated with the RSC, used to differentiate
between RSCS owned by different execution environments.
+qcom,defer-init-qos: Flag to force defer initial QoS configuration at probe time.
Example:
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index dd668cb..c8cffb5 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -281,6 +281,18 @@
core ib calculation.
- qcom,sde-core-clk-ff: A string entry indicating the fudge factor for
core clock calculation.
+- qcom,sde-min-core-ib-kbps: This u32 value indicates the minimum mnoc ib
+ vote in Kbps that can be reduced without hitting underflow.
+ BW calculation logic will choose the IB bandwidth requirement
+ based on usecase if this floor value is not defined.
+- qcom,sde-min-llcc-ib-kbps: This u32 value indicates the minimum llcc ib
+ vote in Kbps that can be reduced without hitting underflow.
+ BW calculation logic will choose the IB bandwidth requirement
+ based on usecase if this floor value is not defined.
+- qcom,sde-min-dram-ib-kbps: This u32 value indicates the minimum dram ib
+ vote in Kbps that can be reduced without hitting underflow.
+ BW calculation logic will choose the IB bandwidth requirement
+ based on usecase if this floor value is not defined.
- qcom,sde-comp-ratio-rt: A string entry indicating the compression ratio
for each supported compressed format on realtime interface.
The string is composed of one or more of
@@ -572,6 +584,9 @@
qcom,sde-core-ib-ff = "1.1";
qcom,sde-core-clk-ff = "1.0";
+ qcom,sde-min-core-ib-kbps = <2400000>;
+ qcom,sde-min-llcc-ib-kbps = <800000>;
+ qcom,sde-min-dram-ib-kbps = <800000>;
qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
qcom,sde-undersized-prefill-lines = <4>;
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index e46fd5c..ada2eab 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -10,6 +10,7 @@
"dp_mmss_cc" - Display Clock Control memory region.
"qfprom_physical" - QFPROM Phys memory region.
"dp_pll" - USB3 DP combo PLL memory region.
+ "usb3_dp_com" - USB3 DP PHY combo memory region.
"hdcp_physical" - DP HDCP memory region.
- cell-index: Specifies the controller instance.
- clocks: Clocks required for Display Port operation.
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 2e233a1..b18d573 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -211,19 +211,22 @@
and pagetable walk.
- cache-slices: phandle to the system LLC driver, cache slice index.
+
+GPU coresight info:
The following properties are optional as collecting data via coresight might
not be supported for every chipset. The documentation for coresight
properties can be found in:
Documentation/devicetree/bindings/coresight/coresight.txt
-- coresight-id Unique integer identifier for the bus.
-- coresight-name Unique descriptive name of the bus.
-- coresight-nr-inports Number of input ports on the bus.
-- coresight-outports List of output port numbers on the bus.
-- coresight-child-list List of phandles pointing to the children of this
+- qcom,gpu-coresights: Container for sets of GPU coresight sources.
+- coresight-id: Unique integer identifier for the bus.
+- coresight-name: Unique descriptive name of the bus.
+- coresight-nr-inports: Number of input ports on the bus.
+- coresight-outports: List of output port numbers on the bus.
+- coresight-child-list: List of phandles pointing to the children of this
component.
-- coresight-child-ports List of input port numbers of the children.
-- coresight-atid The unique ATID value of the coresight device
+- coresight-child-ports: List of input port numbers of the children.
+- coresight-atid: The unique ATID value of the coresight device
Example of A330 GPU in MSM8916:
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 0f8dc27..8fcdd82 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -96,6 +96,10 @@
retention. No cache invalidation operations involving asid
may be used.
+- qcom,disable-atos:
+ Some hardware may not have full support for atos debugging
+ in tandem with other features like power collapse.
+
- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
disable in ms. In case of unmap call, regulator is
enabled/disabled. This may introduce additional delay. For
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index d61606a..f0549cb 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -7,9 +7,11 @@
- compatible : one of:
- "qcom,msm-vidc"
- "qcom,sdm845-vidc" : Invokes driver specific data for SDM845.
+ - "qcom,sdm670-vidc" : Invokes driver specific data for SDM670.
Optional properties:
- reg : offset and length of the register set for the device.
+- sku-index : sku version of the hardware.
- interrupts : should contain the vidc interrupt.
- qcom,reg-presets : list of offset-value pairs for registers to be written.
The offsets are from the base offset specified in 'reg'. This is mainly
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 24c75e2..d3098be 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -85,6 +85,7 @@
On certain chipsets, coming out of the CX Power Collapse event, the SDCC registers
contents will not be retained. It is software responsibility to restore the
SDCC registers before resuming to normal operation.
+ - qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 271703f..85b0fe9 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -67,6 +67,9 @@
service.
- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem.
- qcom,override-acc: Boolean- Present if we need to override the default ACC settings
+- qcom,mss_pdc_offset: Integer- Mandatory if PDC register is specified. It is
+ used to specify which bit in the PDC register
+ corresponds to the modem.
- qcom,ahb-clk-vote: Boolean- Present if we need to remove the vote for the mss_cfg_ahb
clock after the modem boots up
- qcom,pnoc-clk-vote: Boolean- Present if the modem needs the PNOC bus to be
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index d0d878b..a3fd951 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -271,6 +271,14 @@
Definition: A boolean property that when defined holds SOC at 100% when
the battery is full.
+- qcom,linearize-soc
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property that when defined linearizes SOC when
+ the SOC drops after charge termination monotonically to
+ improve the user experience. This is applicable only if
+ "qcom,hold-soc-while-full" is specified.
+
- qcom,ki-coeff-soc-dischg
Usage: optional
Value type: <prop-encoded-array>
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 4901fa0..c3e2cab 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -23,6 +23,8 @@
with "phys" attribute, provides phandle to UFS PHY node
- vdd-hba-supply : phandle to UFS host controller supply regulator node
- vcc-supply : phandle to VCC supply regulator node
+- vcc-voltage-level : specifies voltage levels for VCC supply.
+ Should be specified in pairs (min, max), units uV.
- vccq-supply : phandle to VCCQ supply regulator node
- vccq2-supply : phandle to VCCQ2 supply regulator node
- vcc-supply-1p8 : For embedded UFS devices, valid VCC range is 1.7-1.95V
diff --git a/Makefile b/Makefile
index 3849d63..a8d289a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 41
+SUBLEVEL = 48
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/alpha/include/asm/types.h b/arch/alpha/include/asm/types.h
index 4cb4b6d..0bc66e1 100644
--- a/arch/alpha/include/asm/types.h
+++ b/arch/alpha/include/asm/types.h
@@ -1,6 +1,6 @@
#ifndef _ALPHA_TYPES_H
#define _ALPHA_TYPES_H
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
#endif /* _ALPHA_TYPES_H */
diff --git a/arch/alpha/include/uapi/asm/types.h b/arch/alpha/include/uapi/asm/types.h
index 9fd3cd4..8d1024d 100644
--- a/arch/alpha/include/uapi/asm/types.h
+++ b/arch/alpha/include/uapi/asm/types.h
@@ -9,8 +9,18 @@
* need to be careful to avoid a name clashes.
*/
-#ifndef __KERNEL__
+/*
+ * This is here because we used to use l64 for alpha
+ * and we don't want to impact user mode with our change to ll64
+ * in the kernel.
+ *
+ * However, some user programs are fine with this. They can
+ * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here.
+ */
+#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__)
#include <asm-generic/int-l64.h>
+#else
+#include <asm-generic/int-ll64.h>
#endif
#endif /* _UAPI_ALPHA_TYPES_H */
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index b3410ff..4fd6272 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -89,7 +89,9 @@
#define ARC_REG_SLC_FLUSH 0x904
#define ARC_REG_SLC_INVALIDATE 0x905
#define ARC_REG_SLC_RGN_START 0x914
+#define ARC_REG_SLC_RGN_START1 0x915
#define ARC_REG_SLC_RGN_END 0x916
+#define ARC_REG_SLC_RGN_END1 0x917
/* Bit val in SLC_CONTROL */
#define SLC_CTRL_IM 0x040
diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c
index 8147583..bbdfeb3 100644
--- a/arch/arc/mm/cache.c
+++ b/arch/arc/mm/cache.c
@@ -562,6 +562,7 @@
static DEFINE_SPINLOCK(lock);
unsigned long flags;
unsigned int ctrl;
+ phys_addr_t end;
spin_lock_irqsave(&lock, flags);
@@ -591,8 +592,16 @@
* END needs to be setup before START (latter triggers the operation)
* END can't be same as START, so add (l2_line_sz - 1) to sz
*/
- write_aux_reg(ARC_REG_SLC_RGN_END, (paddr + sz + l2_line_sz - 1));
- write_aux_reg(ARC_REG_SLC_RGN_START, paddr);
+ end = paddr + sz + l2_line_sz - 1;
+ if (is_pae40_enabled())
+ write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end));
+
+ write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end));
+
+ if (is_pae40_enabled())
+ write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr));
+
+ write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr));
while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index 895fa6c..563901e 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -75,7 +75,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pca0_pins>;
interrupt-parent = <&gpio0>;
- interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
@@ -87,7 +87,7 @@
compatible = "nxp,pca9555";
pinctrl-names = "default";
interrupt-parent = <&gpio0>;
- interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <18 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
index 5ea4915..10d3074 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2-emmc.dts
@@ -56,7 +56,7 @@
};
&pio {
- mmc2_pins_nrst: mmc2@0 {
+ mmc2_pins_nrst: mmc2-rst-pin {
allwinner,pins = "PC16";
allwinner,function = "gpio_out";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
diff --git a/arch/arm/boot/dts/tango4-vantage-1172.dts b/arch/arm/boot/dts/tango4-vantage-1172.dts
index 4cab64c..e3a51e3 100644
--- a/arch/arm/boot/dts/tango4-vantage-1172.dts
+++ b/arch/arm/boot/dts/tango4-vantage-1172.dts
@@ -21,7 +21,7 @@
};
ð0 {
- phy-connection-type = "rgmii";
+ phy-connection-type = "rgmii-id";
phy-handle = <ð0_phy>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index ff8a523..bde40e0 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -276,6 +276,7 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_USB_BAM=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_SMEM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 6965607..24ae9bd 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -192,6 +192,7 @@
CONFIG_HW_RANDOM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -260,6 +261,7 @@
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_RTC_CLASS=y
CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
CONFIG_UIO=y
CONFIG_STAGING=y
CONFIG_GSI=y
@@ -271,6 +273,7 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_MAILBOX=y
CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD=y
CONFIG_QCOM_SCM=y
diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h
index bfe2a2f..22b7311 100644
--- a/arch/arm/include/asm/ftrace.h
+++ b/arch/arm/include/asm/ftrace.h
@@ -54,6 +54,24 @@
#define ftrace_return_address(n) return_address(n)
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+
+static inline bool arch_syscall_match_sym_name(const char *sym,
+ const char *name)
+{
+ if (!strcmp(sym, "sys_mmap2"))
+ sym = "sys_mmap_pgoff";
+ else if (!strcmp(sym, "sys_statfs64_wrapper"))
+ sym = "sys_statfs64";
+ else if (!strcmp(sym, "sys_fstatfs64_wrapper"))
+ sym = "sys_fstatfs64";
+ else if (!strcmp(sym, "sys_arm_fadvise64_64"))
+ sym = "sys_fadvise64_64";
+
+ /* Ignore case since sym may start with "SyS" instead of "sys" */
+ return !strcasecmp(sym, name);
+}
+
#endif /* ifndef __ASSEMBLY__ */
#endif /* _ASM_ARM_FTRACE */
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 332ce3b..2206e0e 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -829,22 +829,22 @@
* Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
* underlying level-2 and level-3 tables before freeing the actual level-1 table
* and setting the struct pointer to NULL.
- *
- * Note we don't need locking here as this is only called when the VM is
- * destroyed, which can only be done once.
*/
void kvm_free_stage2_pgd(struct kvm *kvm)
{
- if (kvm->arch.pgd == NULL)
- return;
+ void *pgd = NULL;
spin_lock(&kvm->mmu_lock);
- unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+ if (kvm->arch.pgd) {
+ unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+ pgd = READ_ONCE(kvm->arch.pgd);
+ kvm->arch.pgd = NULL;
+ }
spin_unlock(&kvm->mmu_lock);
/* Free the HW pgd, one page at a time */
- free_pages_exact(kvm->arch.pgd, S2_PGD_SIZE);
- kvm->arch.pgd = NULL;
+ if (pgd)
+ free_pages_exact(pgd, S2_PGD_SIZE);
}
static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
@@ -1664,12 +1664,16 @@
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
{
+ if (!kvm->arch.pgd)
+ return 0;
trace_kvm_age_hva(start, end);
return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
}
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
{
+ if (!kvm->arch.pgd)
+ return 0;
trace_kvm_test_age_hva(hva);
return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL);
}
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index f2cf941..779ace6 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -8,45 +8,54 @@
sdm845-mtp-overlay.dtbo \
sdm845-qrd-overlay.dtbo \
sdm845-qvr-overlay.dtbo \
- sdm845-v2-cdp-overlay.dtbo \
- sdm845-v2-mtp-overlay.dtbo \
- sdm845-v2-qrd-overlay.dtbo \
sdm845-4k-panel-mtp-overlay.dtbo \
sdm845-4k-panel-cdp-overlay.dtbo \
sdm845-4k-panel-qrd-overlay.dtbo \
+ sdm845-v2-cdp-overlay.dtbo \
+ sdm845-v2-mtp-overlay.dtbo \
+ sdm845-v2-qrd-overlay.dtbo \
+ sdm845-v2-4k-panel-mtp-overlay.dtbo \
+ sdm845-v2-4k-panel-cdp-overlay.dtbo \
+ sdm845-v2-4k-panel-qrd-overlay.dtbo \
sda845-cdp-overlay.dtbo \
sda845-mtp-overlay.dtbo \
sda845-qrd-overlay.dtbo \
- sda845-v2-cdp-overlay.dtbo \
- sda845-v2-mtp-overlay.dtbo \
- sda845-v2-qrd-overlay.dtbo \
sda845-4k-panel-mtp-overlay.dtbo \
sda845-4k-panel-cdp-overlay.dtbo \
sda845-4k-panel-qrd-overlay.dtbo \
- sdm845-interposer-sdm670-cdp-overlay.dtbo \
- sdm845-interposer-sdm670-mtp-overlay.dtbo
+ sda845-v2-cdp-overlay.dtbo \
+ sda845-v2-mtp-overlay.dtbo \
+ sda845-v2-qrd-overlay.dtbo \
+ sda845-v2-4k-panel-mtp-overlay.dtbo \
+ sda845-v2-4k-panel-cdp-overlay.dtbo \
+ sda845-v2-4k-panel-qrd-overlay.dtbo
sdm845-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-qrd-overlay.dtbo-base := sdm845.dtb
sdm845-qvr-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-qvr-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb
sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb
+sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-qrd-overlay.dtbo-base := sdm845-v2.dtb
sda845-cdp-overlay.dtbo-base := sda845.dtb
sda845-mtp-overlay.dtbo-base := sda845.dtb
sda845-qrd-overlay.dtbo-base := sda845.dtb
-sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
sda845-4k-panel-mtp-overlay.dtbo-base := sda845.dtb
sda845-4k-panel-cdp-overlay.dtbo-base := sda845.dtb
sda845-4k-panel-qrd-overlay.dtbo-base := sda845.dtb
-sdm845-interposer-sdm670-cdp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
-sdm845-interposer-sdm670-mtp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
+sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
else
dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
sdm845-rumi.dtb \
@@ -71,19 +80,55 @@
sdm670-mtp-overlay.dtbo \
sdm670-rumi-overlay.dtbo \
sdm670-pm660a-cdp-overlay.dtbo \
- sdm670-pm660a-mtp-overlay.dtbo
+ sdm670-pm660a-mtp-overlay.dtbo \
+ sdm670-external-codec-cdp-overlay.dtbo \
+ sdm670-external-codec-mtp-overlay.dtbo \
+ sdm670-external-codec-pm660a-cdp-overlay.dtbo \
+ sdm670-external-codec-pm660a-mtp-overlay.dtbo \
+ sdm670-usbc-cdp-overlay.dtbo \
+ sdm670-usbc-mtp-overlay.dtbo \
+ sdm670-usbc-pm660a-cdp-overlay.dtbo \
+ sdm670-usbc-pm660a-mtp-overlay.dtbo \
+ sdm670-usbc-external-codec-cdp-overlay.dtbo \
+ sdm670-usbc-external-codec-mtp-overlay.dtbo \
+ sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo \
+ sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo
sdm670-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-mtp-overlay.dtbo-base := sdm670.dtb
sdm670-rumi-overlay.dtbo-base := sdm670.dtb
sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
else
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
sdm670-mtp.dtb \
sdm670-cdp.dtb \
sdm670-pm660a-mtp.dtb \
- sdm670-pm660a-cdp.dtb
+ sdm670-pm660a-cdp.dtb \
+ sdm670-external-codec-cdp.dtb \
+ sdm670-external-codec-mtp.dtb \
+ sdm670-external-codec-pm660a-cdp.dtb \
+ sdm670-external-codec-pm660a-mtp.dtb \
+ sdm670-usbc-cdp.dtb \
+ sdm670-usbc-external-codec-cdp.dtb \
+ sdm670-usbc-external-codec-mtp.dtb \
+ sdm670-usbc-external-codec-pm660a-cdp.dtb \
+ sdm670-usbc-external-codec-pm660a-mtp.dtb \
+ sdm670-usbc-mtp.dtb \
+ sdm670-usbc-pm660a-cdp.dtb \
+ sdm670-usbc-pm660a-mtp.dtb
endif
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index 0d0e7f7..c83fd87 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -29,7 +29,6 @@
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
- qcom,cmd-sync-wait-broadcast;
qcom,mdss-dsi-dma-trigger = "trigger_sw";
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>;
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 5de0e44..2156a5d 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -21,6 +21,7 @@
#iommu-cells = <1>;
qcom,dynamic;
qcom,use-3-lvl-tables;
+ qcom,disable-atos;
#global-interrupts = <2>;
qcom,regulator-names = "vdd";
vdd-supply = <&gpu_cx_gdsc>;
@@ -62,6 +63,7 @@
qcom,skip-init;
qcom,use-3-lvl-tables;
qcom,no-asid-retention;
+ qcom,disable-atos;
#global-interrupts = <1>;
#size-cells = <1>;
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 48d68a7..80103cb 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -12,6 +12,7 @@
#include <dt-bindings/spmi/spmi.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
&spmi_bus {
pm660_0: qcom,pm660@0 {
@@ -58,13 +59,14 @@
};
};
- qcom,temp-alarm@2400 {
+ pm660_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm660_tz";
qcom,channel-num = <6>;
qcom,temp_alarm-vadc = <&pm660_vadc>;
+ #thermal-sensor-cells = <0>;
};
pm660_gpios: pinctrl@c000 {
@@ -249,6 +251,8 @@
compatible = "qcom,qpnp-pdphy";
reg = <0x1700 0x100>;
vdd-pdphy-supply = <&pm660l_l7>;
+ vbus-supply = <0>;
+ vconn-supply = <0>;
interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
<0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
@@ -358,18 +362,23 @@
qcom,pmic-revid = <&pm660_revid>;
};
- bcl@4200 {
+ bcl_sensor: bcl@4200 {
compatible = "qcom,msm-bcl-lmh";
reg = <0x4200 0xff>,
<0x4300 0xff>;
reg-names = "fg_user_adc",
"fg_lmh";
interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>,
- <0x0 0x42 0x2 IRQ_TYPE_NONE>;
- interrupt-names = "bcl-high-ibat-int",
- "bcl-low-vbat-int";
- qcom,vbat-polling-delay-ms = <100>;
- qcom,ibat-polling-delay-ms = <100>;
+ <0x0 0x42 0x1 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x2 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x3 IRQ_TYPE_NONE>,
+ <0x0 0x42 0x4 IRQ_TYPE_NONE>;
+ interrupt-names = "bcl-high-ibat",
+ "bcl-very-high-ibat",
+ "bcl-low-vbat",
+ "bcl-very-low-vbat",
+ "bcl-crit-low-vbat";
+ #thermal-sensor-cells = <1>;
};
};
@@ -456,4 +465,243 @@
};
};
};
+
+ ibat-high {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 0>;
+
+ trips {
+ ibat-high {
+ temperature = <4200>;
+ hysteresis = <200>;
+ type = "passive";
+ };
+ };
+ };
+
+ ibat-vhigh {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 1>;
+
+ trips {
+ ibat-vhigh {
+ temperature = <4300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+
+ vbat_adc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 2>;
+ tracks-low;
+
+ trips {
+ pm660_vbat_adc: vbat-adc {
+ temperature = <3300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ vbat_map6 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ vbat_map7 {
+ trip = <&pm660_vbat_adc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ vbat_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 3>;
+ tracks-low;
+
+ trips {
+ vbat-low {
+ temperature = <3100>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ vbat_too_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 4>;
+ tracks-low;
+
+ trips {
+ vbat-too-low {
+ temperature = <2900>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ soc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 5>;
+ tracks-low;
+
+ trips {
+ pm660_low_soc: low-soc {
+ temperature = <10>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ soc_map6 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ soc_map7 {
+ trip = <&pm660_low_soc>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
+
+ pm660_temp_alarm: pm660_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&pm660_tz>;
+
+ trips {
+ pm660_trip0: pm660-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660_trip1: pm660-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660_trip2: pm660-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ cooling-maps {
+ trip0_cpu0 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU0 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu1 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU1 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu2 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU2 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu3 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU3 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu4 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU4 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu5 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU5 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu6 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU6 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip0_cpu7 {
+ trip = <&pm660_trip0>;
+ cooling-device =
+ <&CPU7 (THERMAL_MAX_LIMIT-1)
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ trip1_cpu1 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU1 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu2 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU2 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu3 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU3 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu4 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU4 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu5 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU5 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu6 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU6 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ trip1_cpu7 {
+ trip = <&pm660_trip1>;
+ cooling-device =
+ <&CPU7 THERMAL_MAX_LIMIT
+ THERMAL_MAX_LIMIT>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 771154a..aaf5d05 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -39,11 +39,12 @@
<PON_POWER_OFF_SHUTDOWN>;
};
- qcom,temp-alarm@2400 {
+ pm660l_tz: qcom,temp-alarm@2400 {
compatible = "qcom,qpnp-temp-alarm";
reg = <0x2400 0x100>;
interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
label = "pm660l_tz";
+ #thermal-sensor-cells = <0>;
};
pm660l_gpios: pinctrl@c000 {
@@ -295,3 +296,29 @@
};
};
};
+
+&thermal_zones {
+ pm660l_tz {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660l_tz>;
+
+ trips {
+ pm660l_trip0: pm660l-trip0 {
+ temperature = <105000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660l_trip1: pm660l-trip1 {
+ temperature = <125000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ pm660l_trip2: pm660l-trip2 {
+ temperature = <145000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..9b7449e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel CDP";
+ compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..bb310d3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel MTP";
+ compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..ab61f2e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel QRD";
+ compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd";
+ qcom,msm-id = <341 0x20000>;
+ qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 4f40678..00f454c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -12,6 +12,31 @@
#include "sdm670-pmic-overlay.dtsi"
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm660l_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm660_l1>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm660l_l4>;
+ vccq2-supply = <&pm660_l8>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm660_l1>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
&qupv3_se9_2uart {
status = "disabled";
};
@@ -35,3 +60,72 @@
&qupv3_se6_4uart {
status = "disabled";
};
+
+&sdhc_1 {
+ vdd-supply = <&pm660l_l4>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ vdd-io-supply = <&pm660_l8>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm660l_l5>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pm660l_l2>;
+ qcom,vdd-io-voltage-level = <1800000 2960000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ status = "ok";
+};
+
+&pm660_charger {
+ qcom,batteryless-platform;
+};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&tlmm 91 0>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&tlmm 92 0>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 16efb4c..6cbfb57 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -400,15 +400,6 @@
};
port@4 {
- reg = <5>;
- tpda_in_funnel_lpass: endpoint {
- slave-mode;
- remote-endpoint =
- <&funnel_lpass_out_tpda>;
- };
- };
-
- port@5 {
reg = <6>;
tpda_in_funnel_turing: endpoint {
slave-mode;
@@ -417,7 +408,7 @@
};
};
- port@6 {
+ port@5 {
reg = <7>;
tpda_in_tpdm_vsense: endpoint {
slave-mode;
@@ -426,7 +417,7 @@
};
};
- port@7 {
+ port@6 {
reg = <10>;
tpda_in_tpdm_qm: endpoint {
slave-mode;
@@ -435,7 +426,7 @@
};
};
- port@8 {
+ port@7 {
reg = <11>;
tpda_in_tpdm_north: endpoint {
slave-mode;
@@ -444,7 +435,7 @@
};
};
- port@9 {
+ port@8 {
reg = <13>;
tpda_in_tpdm_pimem: endpoint {
slave-mode;
@@ -545,67 +536,6 @@
};
};
- funnel_lpass: funnel@6845000 {
- compatible = "arm,primecell";
- arm,primecell-periphid = <0x0003b908>;
-
- reg = <0x6845000 0x1000>;
- reg-names = "funnel-base";
-
- coresight-name = "coresight-funnel-lpass";
-
- clocks = <&clock_aop QDSS_CLK>;
- clock-names = "apb_pclk";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
- funnel_lpass_out_tpda: endpoint {
- remote-endpoint =
- <&tpda_in_funnel_lpass>;
- };
- };
-
- port@1 {
- reg = <0>;
- funnel_lpass_in_tpdm_lpass: endpoint {
- slave-mode;
- remote-endpoint =
- <&tpdm_lpass_out_funnel_lpass>;
- };
- };
-
- port@2 {
- reg = <1>;
- funnel_lpass_in_audio_etm0: endpoint {
- slave-mode;
- remote-endpoint =
- <&audio_etm0_out_funnel_lpass>;
- };
- };
- };
- };
-
- tpdm_lpass: tpdm@6844000 {
- compatible = "arm,primecell";
- reg = <0x6844000 0x1000>;
- reg-names = "tpdm-base";
-
- coresight-name = "coresight-tpdm-lpass";
-
- clocks = <&clock_aop QDSS_CLK>;
- clock-names = "apb_pclk";
-
- port {
- tpdm_lpass_out_funnel_lpass: endpoint {
- remote-endpoint = <&funnel_lpass_in_tpdm_lpass>;
- };
- };
- };
-
tpdm_center: tpdm@6c28000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b968>;
@@ -1652,19 +1582,6 @@
};
};
- audio_etm0 {
- compatible = "qcom,coresight-remote-etm";
-
- coresight-name = "coresight-audio-etm0";
- qcom,inst-id = <5>;
-
- port {
- audio_etm0_out_funnel_lpass: endpoint {
- remote-endpoint = <&funnel_lpass_in_audio_etm0>;
- };
- };
- };
-
funnel_apss_merg: funnel@7810000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
new file mode 100644
index 0000000..32a8580
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
new file mode 100644
index 0000000..6a87d3a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..970209ca
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
new file mode 100644
index 0000000..87ac190
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..48a6066
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
@@ -0,0 +1,35 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
new file mode 100644
index 0000000..e64d13b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..8715ddc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
new file mode 100644
index 0000000..0beaddb3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
new file mode 100644
index 0000000..6ea92ee
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
@@ -0,0 +1,11 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index d13aa15..7718bca 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -73,6 +73,7 @@
/* base addr, size */
qcom,gpu-qdss-stm = <0x161c0000 0x40000>;
+ #cooling-cells = <2>;
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
<&clock_gpucc GPU_CC_CXO_CLK>,
@@ -170,7 +171,7 @@
reg = <0>;
qcom,gpu-freq = <430000000>;
qcom,bus-freq = <11>;
- qcom,bus-min = <10>;
+ qcom,bus-min = <8>;
qcom,bus-max = <11>;
};
@@ -178,9 +179,9 @@
qcom,gpu-pwrlevel@1 {
reg = <1>;
qcom,gpu-freq = <355000000>;
- qcom,bus-freq = <9>;
- qcom,bus-min = <8>;
- qcom,bus-max = <10>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <5>;
+ qcom,bus-max = <9>;
};
/* LOW SVS */
@@ -198,7 +199,7 @@
qcom,gpu-freq = <180000000>;
qcom,bus-freq = <4>;
qcom,bus-min = <3>;
- qcom,bus-max = <5>;
+ qcom,bus-max = <4>;
};
/* XO */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 4f40678..320a1f2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -12,6 +12,31 @@
#include "sdm670-pmic-overlay.dtsi"
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm660l_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm660_l1>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm660l_l4>;
+ vccq2-supply = <&pm660_l8>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm660_l1>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
&qupv3_se9_2uart {
status = "disabled";
};
@@ -35,3 +60,81 @@
&qupv3_se6_4uart {
status = "disabled";
};
+
+&sdhc_1 {
+ vdd-supply = <&pm660l_l4>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ vdd-io-supply = <&pm660_l8>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm660l_l5>;
+ qcom,vdd-voltage-level = <2960000 2960000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pm660l_l2>;
+ qcom,vdd-io-voltage-level = <1800000 2960000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ status = "ok";
+};
+
+&vendor {
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "fg-gen3-batterydata-itech-3000mah.dtsi"
+ #include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+ #include "fg-gen3-batterydata-demo-6000mah.dtsi"
+ };
+};
+
+&pm660_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&tlmm 91 0>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&tlmm 92 0>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index 73df253..2a2b6d8 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1196,6 +1196,20 @@
};
};
+ sdc1_rclk_on: sdc1_rclk_on {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ sdc1_rclk_off: sdc1_rclk_off {
+ config {
+ pins = "sdc1_rclk";
+ bias-pull-down; /* pull down */
+ };
+ };
+
sdc2_clk_on: sdc2_clk_on {
config {
pins = "sdc2_clk";
@@ -1437,5 +1451,27 @@
};
};
};
+
+ /* Pinctrl setting for CAMERA GPIO key */
+ key_cam_snapshot {
+ key_cam_snapshot_default: key_cam_snapshot_default {
+ pins = "gpio91";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ key_cam_focus {
+ key_cam_focus_default: key_cam_focus_default {
+ pins = "gpio92";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index cd8bfba..75922b0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -15,6 +15,7 @@
compatible = "qcom,qpnp-smb2";
#address-cells = <1>;
#size-cells = <1>;
+ #cooling-cells = <2>;
qcom,pmic-revid = <&pm660_revid>;
@@ -365,3 +366,7 @@
vbus-supply = <&smb2_vbus>;
vconn-supply = <&smb2_vconn>;
};
+
+&usb0 {
+ extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 1f76288..23792b1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -96,6 +96,14 @@
regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
};
+
+ mx_cdev: mx-cdev-lvl {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pm660l_s1_level>;
+ regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_OFF>;
+ #cooling-cells = <2>;
+ };
};
/* pm660l S2 - VDD_GFX supply */
@@ -137,6 +145,13 @@
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
qcom,min-dropout-voltage-level = <(-1)>;
};
+
+ cx_cdev: regulator-cdev {
+ compatible = "qcom,rpmh-reg-cdev";
+ mboxes = <&qmp_aop 0>;
+ qcom,reg-resource-name = "cx";
+ #cooling-cells = <2>;
+ };
};
rpmh-regulator-ldoa1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index ca9d8c7..4ba16e4 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -49,6 +49,7 @@
/delete-node/ rpmh-regulator-ldoa28;
/delete-node/ rpmh-regulator-bobb1;
/delete-node/ rpmh-regulator-gfxlvl;
+ /delete-node/ thermal-zones;
};
#include "sdm670-stub-regulator.dtsi"
@@ -127,6 +128,8 @@
qcom,clk-rates = <400000 20000000 25000000 50000000>;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ /delete-property/qcom,devfreq,freq-table;
+
status = "ok";
};
@@ -146,6 +149,8 @@
qcom,clk-rates = <400000 20000000 25000000 50000000>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50";
+ /delete-property/qcom,devfreq,freq-table;
+
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
new file mode 100644
index 0000000..e4993d6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -0,0 +1,1507 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+&clock_cpucc {
+ lmh_dcvs0: qcom,limits-dcvs@0 {
+ compatible = "qcom,msm-hw-limits";
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,affinity = <0>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ lmh_dcvs1: qcom,limits-dcvs@1 {
+ compatible = "qcom,msm-hw-limits";
+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,affinity = <1>;
+ #thermal-sensor-cells = <0>;
+ };
+};
+
+&soc {
+ qmi-tmd-devices {
+ compatible = "qcom,qmi_cooling_devices";
+
+ modem {
+ qcom,instance-id = <0x0>;
+
+ modem_pa: modem_pa {
+ qcom,qmi-dev-name = "pa";
+ #cooling-cells = <2>;
+ };
+
+ modem_proc: modem_proc {
+ qcom,qmi-dev-name = "modem";
+ #cooling-cells = <2>;
+ };
+
+ modem_current: modem_current {
+ qcom,qmi-dev-name = "modem_current";
+ #cooling-cells = <2>;
+ };
+
+ modem_vdd: modem_vdd {
+ qcom,qmi-dev-name = "cpuv_restriction_cold";
+ #cooling-cells = <2>;
+ };
+ };
+
+ adsp {
+ qcom,instance-id = <0x1>;
+
+ adsp_vdd: adsp_vdd {
+ qcom,qmi-dev-name = "cpuv_restriction_cold";
+ #cooling-cells = <2>;
+ };
+ };
+
+ cdsp {
+ qcom,instance-id = <0x43>;
+
+ cdsp_vdd: cdsp_vdd {
+ qcom,qmi-dev-name = "cpuv_restriction_cold";
+ #cooling-cells = <2>;
+ };
+ };
+ };
+};
+
+&thermal_zones {
+ aoss0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 0>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu2-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu3-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu4-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu5-silver-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-gold-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-gold-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 11>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 12>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ aoss1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 0>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-dsp-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 1>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ ddr-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 2>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ wlan-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 3>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ compute-hvx-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mmss-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-core-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu-virt-max-step {
+ polling-delay-passive = <10>;
+ polling-delay = <100>;
+ thermal-governor = "step_wise";
+ trips {
+ gpu_trip0: gpu-trip0 {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ gpu_cdev0 {
+ trip = <&gpu_trip0>;
+ cooling-device =
+ <&msm_gpu THERMAL_NO_LIMIT
+ THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ hexa-silv-max-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ trips {
+ silver-trip {
+ temperature = <120000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ dual-gold-max-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ trips {
+ gold-trip {
+ temperature = <120000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+
+ pop-mem-step {
+ polling-delay-passive = <10>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 2>;
+ thermal-governor = "step_wise";
+ trips {
+ pop_trip: pop-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ pop_cdev6 {
+ trip = <&pop_trip>;
+ cooling-device =
+ <&CPU6 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ pop_cdev7 {
+ trip = <&pop_trip>;
+ cooling-device =
+ <&CPU7 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ };
+ };
+
+ aoss0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 0>;
+ tracks-low;
+ trips {
+ aoss0_trip: aoss0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu0-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 1>;
+ tracks-low;
+ trips {
+ cpu0_trip: cpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu1-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 2>;
+ tracks-low;
+ trips {
+ cpu1_trip: cpu1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu2-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 3>;
+ tracks-low;
+ trips {
+ cpu2_trip: cpu2-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu3-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 4>;
+ tracks-low;
+ trips {
+ cpu3_trip: cpu3-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu4-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 5>;
+ tracks-low;
+ trips {
+ cpu4_trip: cpu4-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu4_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu5-silver-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 6>;
+ tracks-low;
+ trips {
+ cpu5_trip: cpu5-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpu5_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ kryo-l3-0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 7>;
+ tracks-low;
+ trips {
+ l3_0_trip: l3-0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ kryo-l3-1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 8>;
+ tracks-low;
+ trips {
+ l3_1_trip: l3-1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu0-gold-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 9>;
+ tracks-low;
+ trips {
+ cpug0_trip: cpug0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ cpu1-gold-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 10>;
+ tracks-low;
+ trips {
+ cpug1_trip: cpug1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ gpu0-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 11>;
+ tracks-low;
+ trips {
+ gpu0_trip_l: gpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ gpu1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 12>;
+ tracks-low;
+ trips {
+ gpu1_trip_l: gpu1-trip_l {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ aoss1-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 0>;
+ tracks-low;
+ trips {
+ aoss1_trip: aoss1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ mdm-dsp-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 1>;
+ tracks-low;
+ trips {
+ dsp_trip: dsp-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ ddr-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 2>;
+ tracks-low;
+ trips {
+ ddr_trip: ddr-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ wlan-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 3>;
+ tracks-low;
+ trips {
+ wlan_trip: wlan-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ compute-hvx-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 4>;
+ tracks-low;
+ trips {
+ hvx_trip: hvx-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ camera-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 5>;
+ tracks-low;
+ trips {
+ camera_trip: camera-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ mmss-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 6>;
+ tracks-low;
+ trips {
+ mmss_trip: mmss-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ mdm-core-lowf {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 7>;
+ tracks-low;
+ trips {
+ mdm_trip: mdm-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&CPU0 4 4>;
+ };
+ cpu6_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&CPU6 9 9>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 1 1>;
+ };
+ cx_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
+ modem_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&modem_vdd 0 0>;
+ };
+ adsp_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&adsp_vdd 0 0>;
+ };
+ cdsp_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&cdsp_vdd 0 0>;
+ };
+ };
+ };
+
+ lmh-dcvs-01 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&lmh_dcvs1>;
+
+ trips {
+ active-config {
+ temperature = <95000>;
+ hysteresis = <30000>;
+ type = "passive";
+ };
+ };
+ };
+
+ lmh-dcvs-00 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&lmh_dcvs0>;
+
+ trips {
+ active-config {
+ temperature = <95000>;
+ hysteresis = <30000>;
+ type = "passive";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index bd35cf2..6a69e29 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -17,10 +17,19 @@
/delete-node/ ssusb@a800000;
/delete-node/ qusb@88e3000;
/delete-node/ ssphy@88eb000;
+ /delete-node/ usb_audio_qmi_dev;
+ usb_audio_qmi_dev {
+ compatible = "qcom,usb-audio-qmi-dev";
+ iommus = <&apps_smmu 0x180f 0x0>;
+ qcom,usb-audio-stream-id = <0xf>;
+ qcom,usb-audio-intr-num = <2>;
+ };
};
&usb0 {
- extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+ /delete-property/ iommus;
+ /delete-property/ qcom,smmu-s1-bypass;
+ extcon = <0>, <0>, <0> /* <&eud> */;
};
&qusb_phy0 {
@@ -30,6 +39,6 @@
};
&usb_qmp_dp_phy {
- vdd-supply = <&pm660_l1>;
- core-supply = <&pm660l_l1>;
+ vdd-supply = <&pm660l_l1>; /* 0.88v */
+ core-supply = <&pm660_l1>; /* 1.2v */
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
new file mode 100644
index 0000000..190b32f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
new file mode 100644
index 0000000..45ff83f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
new file mode 100644
index 0000000..226c2ae
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
new file mode 100644
index 0000000..8928f80
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..78d1dfa
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
new file mode 100644
index 0000000..5628e92
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..c1891a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
@@ -0,0 +1,35 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
new file mode 100644
index 0000000..c059113
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..c54e299
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
new file mode 100644
index 0000000..d09b5e5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
new file mode 100644
index 0000000..d8c4102
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
@@ -0,0 +1,32 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
new file mode 100644
index 0000000..b9bb3ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0102001a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..95df620
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
new file mode 100644
index 0000000..5e33308
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
+ compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..226a46b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,msm-id = <336 0x0>;
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
new file mode 100644
index 0000000..ca99736
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
+ compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+ <0x0001001b 0x0002001a 0x0 0x0>,
+ <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
new file mode 100644
index 0000000..a74f9d8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-vidc.dtsi
@@ -0,0 +1,214 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/clock/qcom,videocc-sdm845.h>
+
+&soc {
+ msm_vidc0: qcom,vidc0 {
+ compatible = "qcom,msm-vidc", "qcom,sdm670-vidc";
+ status = "ok";
+ sku-index = <0>;
+ reg = <0xaa00000 0x200000>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* Supply */
+ venus-supply = <&venus_gdsc>;
+ venus-core0-supply = <&vcodec0_gdsc>;
+ venus-core1-supply = <&vcodec1_gdsc>;
+
+ /* Clocks */
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "core0_clk", "core0_bus_clk",
+ "core1_clk", "core1_bus_clk";
+ clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC1_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC1_AXI_CLK>;
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "core0_clk", "core0_bus_clk",
+ "core1_clk", "core1_bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
+ qcom,allowed-clock-rates = <100000000 200000000 320000000
+ 380000000 444000000 533000000>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "msm-vidc-ddr";
+ qcom,bus-range-kbps = <1000 3388000>;
+ };
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&apps_smmu 0x10a0 0x8>,
+ <&apps_smmu 0x10b0 0x0>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x6f800000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus =
+ <&apps_smmu 0x10a1 0x8>,
+ <&apps_smmu 0x10a5 0x8>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus =
+ <&apps_smmu 0x10a3 0x8>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus =
+ <&apps_smmu 0x10a4 0x8>,
+ <&apps_smmu 0x10b4 0x0>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+
+ msm_vidc1: qcom,vidc1 {
+ compatible = "qcom,msm-vidc", "qcom,sdm670-vidc";
+ status = "ok";
+ sku-index = <1>;
+ reg = <0xaa00000 0x200000>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* Supply */
+ venus-supply = <&venus_gdsc>;
+ venus-core0-supply = <&vcodec0_gdsc>;
+
+ /* Clocks */
+ clock-names = "core_clk", "iface_clk", "bus_clk",
+ "core0_clk", "core0_bus_clk";
+ clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>,
+ <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+ <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>;
+ qcom,proxy-clock-names = "core_clk", "iface_clk",
+ "bus_clk", "core0_clk", "core0_bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0>;
+ qcom,allowed-clock-rates = <100000000 200000000 320000000
+ 364800000>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "msm-vidc-ddr";
+ qcom,bus-range-kbps = <1000 2128000>;
+ };
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1000 1000>;
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&apps_smmu 0x10a0 0x8>,
+ <&apps_smmu 0x10b0 0x0>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x6f800000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus =
+ <&apps_smmu 0x10a1 0x8>,
+ <&apps_smmu 0x10a5 0x8>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus =
+ <&apps_smmu 0x10a3 0x8>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus =
+ <&apps_smmu 0x10a4 0x8>,
+ <&apps_smmu 0x10b4 0x0>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 692d75f..c8bb003 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -53,6 +53,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_0>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_0: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -86,6 +89,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_100>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_100: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -114,6 +120,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_200>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_200: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -142,6 +151,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_300>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_300: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -170,6 +182,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_400>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_400: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -198,6 +213,9 @@
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_500>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
L2_500: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x20000>;
@@ -226,6 +244,9 @@
cache-size = <0x10000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_600>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
L2_600: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x40000>;
@@ -254,6 +275,9 @@
cache-size = <0x10000>;
cpu-release-addr = <0x0 0x90000000>;
next-level-cache = <&L2_700>;
+ sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
L2_700: l2-cache {
compatible = "arm,arch-cache";
cache-size = <0x40000>;
@@ -311,6 +335,129 @@
};
};
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 300000 14
+ 403200 18
+ 480000 21
+ 576000 25
+ 652800 27
+ 748800 31
+ 825600 40
+ 902400 43
+ 979200 46
+ 1056000 50
+ 1132800 53
+ 1228800 57
+ 1324800 84
+ 1420800 90
+ 1516800 96
+ 1612800 114
+ 1689600 135
+ 1766400 141
+ >;
+ idle-cost-data = <
+ 12 10 8 6
+ >;
+ };
+ CPU_COST_1: core-cost1 {
+ busy-cost-data = <
+ 300000 256
+ 403200 271
+ 480000 282
+ 576000 296
+ 652800 307
+ 748800 321
+ 825600 332
+ 902400 369
+ 979200 382
+ 1056000 395
+ 1132800 408
+ 1209600 421
+ 1286400 434
+ 1363200 448
+ 1459200 567
+ 1536000 586
+ 1612800 604
+ 1689600 622
+ 1766400 641
+ 1843200 659
+ 1920000 678
+ 1996800 696
+ 2092800 876
+ 2169600 900
+ 2246400 924
+ 2323200 948
+ 2400000 1170
+ >;
+ idle-cost-data = <
+ 100 80 60 40
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 300000 5
+ 403200 7
+ 480000 7
+ 576000 7
+ 652800 8
+ 748800 8
+ 825600 9
+ 902400 9
+ 979200 9
+ 1056000 10
+ 1132800 10
+ 1228800 10
+ 1324800 13
+ 1420800 14
+ 1516800 15
+ 1612800 16
+ 1689600 19
+ 1766400 19
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 300000 25
+ 403200 27
+ 480000 28
+ 576000 29
+ 652800 30
+ 748800 32
+ 825600 33
+ 902400 36
+ 979200 38
+ 1056000 39
+ 1132800 40
+ 1209600 42
+ 1286400 43
+ 1363200 44
+ 1459200 56
+ 1536000 58
+ 1612800 60
+ 1689600 62
+ 1766400 64
+ 1843200 65
+ 1920000 67
+ 1996800 69
+ 2092800 87
+ 2169600 90
+ 2246400 92
+ 2323200 94
+ 2400000 117
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
+
psci {
compatible = "arm,psci-1.0";
method = "smc";
@@ -439,6 +586,12 @@
size = <0 0x5c00000>;
};
+ dump_mem: mem_dump_region {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x2400000>;
+ };
+
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
@@ -458,6 +611,9 @@
#include "sdm670-qupv3.dtsi"
#include "sdm670-coresight.dtsi"
+
+#include "sdm670-vidc.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -490,301 +646,7 @@
qcom,pipe-attr-ee;
};
- thermal_zones: thermal-zones {
- aoss0-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "user_space";
- thermal-sensors = <&tsens0 0>;
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu0-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "user_space";
- thermal-sensors = <&tsens0 1>;
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu1-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "user_space";
- thermal-sensors = <&tsens0 2>;
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu2-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "user_space";
- thermal-sensors = <&tsens0 3>;
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu3-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 4>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu4-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 5>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu5-silver-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 6>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- kryo-l3-0-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 7>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- kryo-l3-1-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 8>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu0-gold-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 9>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- cpu1-gold-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 10>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- gpu0-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens0 11>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- gpu1-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-governor = "user_space";
- thermal-sensors = <&tsens0 12>;
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- aoss1-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 0>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- mdm-dsp-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 1>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- ddr-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 2>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- wlan-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 3>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- compute-hvx-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 4>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- camera-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 5>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- mmss-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 6>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
-
- mdm-core-usr {
- polling-delay-passive = <0>;
- polling-delay = <0>;
- thermal-sensors = <&tsens1 7>;
- thermal-governor = "user_space";
- trips {
- active-config0 {
- temperature = <125000>;
- hysteresis = <1000>;
- type = "passive";
- };
- };
- };
- };
+ thermal_zones: thermal-zones {};
tsens0: tsens@c222000 {
compatible = "qcom,tsens24xx";
@@ -881,53 +743,88 @@
};
clock_rpmh: qcom,rpmhclk {
- compatible = "qcom,dummycc";
- clock-output-names = "rpmh_clocks";
+ compatible = "qcom,rpmh-clk-sdm670";
#clock-cells = <1>;
+ mboxes = <&apps_rsc 0>;
+ mbox-names = "apps";
};
clock_gcc: qcom,gcc@100000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gcc_clocks";
+ compatible = "qcom,gcc-sdm670", "syscon";
+ reg = <0x100000 0x1f0000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm660l_s3_level>;
+ vdd_cx_ao-supply = <&pm660l_s3_level_ao>;
#clock-cells = <1>;
#reset-cells = <1>;
};
clock_videocc: qcom,videocc@ab00000 {
- compatible = "qcom,dummycc";
- clock-output-names = "videocc_clocks";
+ compatible = "qcom,video_cc-sdm670", "syscon";
+ reg = <0xab00000 0x10000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm660l_s3_level>;
#clock-cells = <1>;
#reset-cells = <1>;
};
clock_camcc: qcom,camcc@ad00000 {
- compatible = "qcom,dummycc";
- clock-output-names = "camcc_clocks";
+ compatible = "qcom,cam_cc-sdm670", "syscon";
+ reg = <0xad00000 0x10000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm660l_s3_level>;
+ vdd_mx-supply = <&pm660l_s1_level>;
#clock-cells = <1>;
#reset-cells = <1>;
};
clock_dispcc: qcom,dispcc@af00000 {
- compatible = "qcom,dummycc";
- clock-output-names = "dispcc_clocks";
+ compatible = "qcom,dispcc-sdm670", "syscon";
+ reg = <0xaf00000 0x10000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm660l_s3_level>;
#clock-cells = <1>;
#reset-cells = <1>;
};
clock_gpucc: qcom,gpucc@5090000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gpucc_clocks";
+ compatible = "qcom,gpucc-sdm670", "syscon";
+ reg = <0x5090000 0x9000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm660l_s3_level>;
+ vdd_mx-supply = <&pm660l_s1_level>;
#clock-cells = <1>;
#reset-cells = <1>;
};
clock_gfx: qcom,gfxcc@5090000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gfxcc_clocks";
+ compatible = "qcom,gfxcc-sdm670";
+ reg = <0x5090000 0x9000>;
+ reg-names = "cc_base";
+ vdd_gfx-supply = <&pm660l_s2_level>;
#clock-cells = <1>;
#reset-cells = <1>;
};
+ cpucc_debug: syscon@17970018 {
+ compatible = "syscon";
+ reg = <0x17970018 0x4>;
+ };
+
+ clock_debug: qcom,cc-debug {
+ compatible = "qcom,debugcc-sdm845";
+ qcom,cc-count = <5>;
+ qcom,gcc = <&clock_gcc>;
+ qcom,videocc = <&clock_videocc>;
+ qcom,camcc = <&clock_camcc>;
+ qcom,dispcc = <&clock_dispcc>;
+ qcom,gpucc = <&clock_gpucc>;
+ qcom,cpucc = <&cpucc_debug>;
+ clock-names = "xo_clk_src";
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ #clock-cells = <1>;
+ };
+
clock_cpucc: qcom,cpucc {
compatible = "qcom,dummycc";
clock-output-names = "cpucc_clocks";
@@ -953,6 +850,16 @@
qcom,apps-ch-pipes = <0x780000>;
qcom,ea-pc = <0x290>;
status = "disabled";
+ qcom,iommu-s1-bypass;
+
+ iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+ compatible = "qcom,iommu-slim-ctrl-cb";
+ iommus = <&apps_smmu 0x1826 0x0>,
+ <&apps_smmu 0x182d 0x0>,
+ <&apps_smmu 0x182e 0x1>,
+ <&apps_smmu 0x1830 0x1>;
+ };
+
};
slim_qca: slim@62e40000 {
@@ -964,6 +871,13 @@
interrupts = <0 291 0>, <0 292 0>;
interrupt-names = "slimbus_irq", "slimbus_bam_irq";
status = "disabled";
+ qcom,iommu-s1-bypass;
+
+ iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+ compatible = "qcom,iommu-slim-ctrl-cb";
+ iommus = <&apps_smmu 0x1833 0x0>;
+ };
+
};
wdog: qcom,wdt@17980000{
@@ -1160,6 +1074,61 @@
};
};
+ mem_dump {
+ compatible = "qcom,mem-dump";
+ memory-region = <&dump_mem>;
+
+ rpmh_dump {
+ qcom,dump-size = <0x2000000>;
+ qcom,dump-id = <0xec>;
+ };
+
+ rpm_sw_dump {
+ qcom,dump-size = <0x28000>;
+ qcom,dump-id = <0xea>;
+ };
+
+ pmic_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xe4>;
+ };
+
+ tmc_etf_dump {
+ qcom,dump-size = <0x10000>;
+ qcom,dump-id = <0xf0>;
+ };
+
+ tmc_etf_swao_dump {
+ qcom,dump-size = <0x8400>;
+ qcom,dump-id = <0xf1>;
+ };
+
+ tmc_etr_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x100>;
+ };
+
+ tmc_etf_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x101>;
+ };
+
+ tmc_etf_swao_reg_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0x102>;
+ };
+
+ misc_data_dump {
+ qcom,dump-size = <0x1000>;
+ qcom,dump-id = <0xe8>;
+ };
+
+ power_regs_data_dump {
+ qcom,dump-size = <0x100000>;
+ qcom,dump-id = <0xed>;
+ };
+ };
+
kryo3xx-erp {
compatible = "arm,arm64-kryo3xx-cpu-erp";
interrupts = <1 6 4>,
@@ -1422,6 +1391,15 @@
interrupts = <0 17 0>;
};
+ eud: qcom,msm-eud@88e0000 {
+ compatible = "qcom,msm-eud";
+ interrupt-names = "eud_irq";
+ interrupts = <GIC_SPI 492 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x88e0000 0x2000>;
+ reg-names = "eud_base";
+ status = "disabled";
+ };
+
qcom,llcc@1100000 {
compatible = "qcom,llcc-core", "syscon", "simple-mfd";
reg = <0x1100000 0x250000>;
@@ -1574,6 +1552,44 @@
<0 0>,
<0 0>;
+ qcom,msm-bus,name = "ufshc_mem";
+ qcom,msm-bus,num-cases = <12>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ /*
+ * During HS G3 UFS runs at nominal voltage corner, vote
+ * higher bandwidth to push other buses in the data path
+ * to run at nominal to achieve max throughput.
+ * 4GBps pushes BIMC to run at nominal.
+ * 200MBps pushes CNOC to run at nominal.
+ * Vote for half of this bandwidth for HS G3 1-lane.
+ * For max bandwidth, vote high enough to push the buses
+ * to run in turbo voltage corner.
+ */
+ <123 512 0 0>, <1 757 0 0>, /* No vote */
+ <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */
+ <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */
+ <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */
+ <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */
+ <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */
+ <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */
+ <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */
+ <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */
+ <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */
+ <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */
+ <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */
+
+ qcom,bus-vector-names = "MIN",
+ "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
+ "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
+ "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
+ "MAX";
+
+ /* PM QoS */
+ qcom,pm-qos-cpu-groups = <0x3f 0xC0>;
+ qcom,pm-qos-cpu-group-latency-us = <70 70>;
+ qcom,pm-qos-default-cpu = <0>;
+
resets = <&clock_gcc GCC_UFS_PHY_BCR>;
reset-names = "core_reset";
@@ -1612,6 +1628,13 @@
status = "ok";
};
+ qcom,rmtfs_sharedmem@0 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0 0x200000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
qcom,rmnet-ipa {
compatible = "qcom,rmnet-ipa3";
qcom,rmnet-ipa-ssr;
@@ -1817,6 +1840,7 @@
qcom,ssctl-instance-id = <0x12>;
qcom,override-acc;
qcom,qdsp6v65-1-0;
+ qcom,mss_pdc_offset = <8>;
status = "ok";
memory-region = <&pil_modem_mem>;
qcom,mem-protect-id = <0xF>;
@@ -1905,6 +1929,12 @@
qcom,bus-width = <8>;
qcom,large-address-bus;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 192000000 384000000>;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+
clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>,
<&clock_gcc GCC_SDCC1_APPS_CLK>;
clock-names = "iface_clk", "core_clk";
@@ -1926,6 +1956,12 @@
qcom,bus-width = <4>;
qcom,large-address-bus;
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 201500000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50",
+ "SDR104";
+
+ qcom,devfreq,freq-table = <50000000 201500000>;
clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
<&clock_gcc GCC_SDCC2_APPS_CLK>;
clock-names = "iface_clk", "core_clk";
@@ -2015,6 +2051,225 @@
dma-coherent;
};
};
+
+ qcom,icnss@18800000 {
+ status = "disabled";
+ compatible = "qcom,icnss";
+ reg = <0x18800000 0x800000>;
+ interrupts = <0 414 0 /* CE0 */ >,
+ <0 415 0 /* CE1 */ >,
+ <0 416 0 /* CE2 */ >,
+ <0 417 0 /* CE3 */ >,
+ <0 418 0 /* CE4 */ >,
+ <0 419 0 /* CE5 */ >,
+ <0 420 0 /* CE6 */ >,
+ <0 421 0 /* CE7 */ >,
+ <0 422 0 /* CE8 */ >,
+ <0 423 0 /* CE9 */ >,
+ <0 424 0 /* CE10 */ >,
+ <0 425 0 /* CE11 */ >;
+ qcom,wlan-msa-memory = <0x100000>;
+ qcom,smmu-s1-bypass;
+ };
+
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "performance";
+ qcom,src-dst-ports =
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 1144 /* 150 MHz */ >,
+ < 2288 /* 300 MHz */ >,
+ < 3555 /* 466 MHz */ >,
+ < 4577 /* 600 MHz */ >,
+ < 6149 /* 806 MHz */ >,
+ < 7118 /* 933 MHz */ >;
+ };
+
+ bwmon: qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon4";
+ reg = <0x1436400 0x300>, <0x1436300 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 581 4>;
+ qcom,mport = <0>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ llccbw: qcom,llccbw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports =
+ <MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ llcc_bwmon: qcom,llcc-bwmon {
+ compatible = "qcom,bimc-bwmon5";
+ reg = <0x0114a000 0x1000>;
+ reg-names = "base";
+ interrupts = <GIC_SPI 580 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&llccbw>;
+ qcom,count-unit = <0x200000>;
+ qcom,byte-mid-mask = <0xe000>;
+ qcom,byte-mid-match = <0xe000>;
+ };
+
+ memlat_cpu0: qcom,memlat-cpu0 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ memlat_cpu4: qcom,memlat-cpu4 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ status = "ok";
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq_memlat_0: qcom,cpu0-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&memlat_cpu0>;
+ qcom,cachemiss-ev = <0x24>;
+ qcom,core-dev-table =
+ < 748800 1144 >,
+ < 998400 1720 >,
+ < 1209600 2086 >,
+ < 1497600 2929 >,
+ < 1728000 3879 >;
+ };
+
+ devfreq_memlat_4: qcom,cpu4-memlat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&memlat_cpu4>;
+ qcom,cachemiss-ev = <0x24>;
+ qcom,core-dev-table =
+ < 787200 1144 >,
+ < 1113600 2086 >,
+ < 1344000 3879 >,
+ < 1900800 5931 >,
+ < 2438400 6881 >;
+ };
+
+ l3_cpu0: qcom,l3-cpu0 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>;
+ governor = "performance";
+ };
+
+ l3_cpu4: qcom,l3-cpu4 {
+ compatible = "devfreq-simple-dev";
+ clock-names = "devfreq_clk";
+ clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>;
+ governor = "performance";
+ };
+
+ devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&l3_cpu0>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 748800 566400000 >,
+ < 998400 787200000 >,
+ < 1209660 940800000 >,
+ < 1497600 1190400000 >,
+ < 1612800 1382400000 >,
+ < 1728000 1440000000 >;
+ };
+
+ devfreq_l3lat_4: qcom,cpu4-l3lat-mon {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&l3_cpu4>;
+ qcom,cachemiss-ev = <0x17>;
+ qcom,core-dev-table =
+ < 1113600 566400000 >,
+ < 1344000 787200000 >,
+ < 1728000 940800000 >,
+ < 1900800 1190400000 >,
+ < 2438400 1440000000 >;
+ };
+
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1720 /* 451 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 5161 /* 1353 MHz */ >,
+ < 5931 /* 1555 MHz */ >,
+ < 6881 /* 1804 MHz */ >;
+ };
+
+ devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 748800 1144 >,
+ < 1209600 1720 >,
+ < 1612000 2086 >,
+ < 1728000 2929 >;
+ cpu-to-dev-map-4 =
+ < 1113600 1144 >,
+ < 1344000 2086 >,
+ < 1728000 2929 >,
+ < 1900800 3879 >,
+ < 2438400 6881 >;
+ };
+ };
};
#include "sdm670-pinctrl.dtsi"
@@ -2114,3 +2369,4 @@
#include "sdm670-audio.dtsi"
#include "sdm670-usb.dtsi"
#include "sdm670-gpu.dtsi"
+#include "sdm670-thermal.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
index 9bd1d54..cb11a9e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
@@ -175,7 +175,7 @@
compatible = "qcom,wcd-spi-v2";
qcom,master-bus-num = <0>;
qcom,chip-select = <0>;
- qcom,max-frequency = <9600000>;
+ qcom,max-frequency = <24000000>;
qcom,mem-base-addr = <0x100000>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 5fbb1db..cf7ccae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -645,7 +645,10 @@
qcom,qport = <2>;
qcom,connections = <&slv_qns_a2noc_snoc>;
qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
qcom,prio = <2>;
+ qcom,defer-init-qos;
+ qcom,node-qos-bcms = <7035 0 1>;
};
mas_xm_pcie3_1: mas-xm-pcie3-1 {
@@ -900,7 +903,7 @@
qcom,bus-dev = <&fab_mem_noc>;
qcom,bcms = <&bcm_sh3>;
qcom,ap-owned;
- qcom,prio = <6>;
+ qcom,prio = <7>;
};
mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index dddf1fb..fe19658 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -110,6 +110,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -146,6 +147,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 3cfcddb..568213b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -522,6 +522,58 @@
};
};
+ port@5 {
+ reg = <6>;
+ funnel_in2_in_funnel_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_gfx_out_funnel_in2>;
+ };
+ };
+ };
+ };
+
+ funnel_gfx: funnel@0x6943000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6943000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-gfx";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_gfx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_funnel_gfx>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_in2_in_gfx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_out_funnel_in2>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_in2_in_gfx_cx: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&gfx_cx_out_funnel_in2>;
+ };
+ };
};
};
@@ -1883,6 +1935,22 @@
clock-names = "apb_pclk";
};
+ ipcb_tgu: tgu@6b0c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b999>;
+ reg = <0x06B0C000 0x1000>;
+ reg-names = "tgu-base";
+ tgu-steps = <3>;
+ tgu-conditions = <4>;
+ tgu-regs = <4>;
+ tgu-timer-counters = <8>;
+
+ coresight-name = "coresight-tgu-ipcb";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+ };
+
turing_etm0 {
compatible = "qcom,coresight-remote-etm";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index c02a0a6..f800b4e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -122,6 +122,36 @@
cache-slice-names = "gpu", "gpuhtw";
cache-slices = <&llcc 12>, <&llcc 11>;
+ qcom,gpu-coresights {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-coresight";
+
+ qcom,gpu-coresight@0 {
+ reg = <0>;
+ coresight-name = "coresight-gfx";
+ coresight-atid = <50>;
+ port {
+ gfx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_gfx>;
+ };
+ };
+ };
+
+ qcom,gpu-coresight@1 {
+ reg = <1>;
+ coresight-name = "coresight-gfx-cx";
+ coresight-atid = <51>;
+ port {
+ gfx_cx_out_funnel_in2: endpoint {
+ remote-endpoint =
+ <&funnel_in2_in_gfx_cx>;
+ };
+ };
+ };
+ };
+
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
index ad15615..e435cdd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
@@ -13,3 +13,28 @@
#include "sdm845-cdp.dtsi"
#include "sdm845-interposer-pm660.dtsi"
#include "sdm845-interposer-sdm670-audio.dtsi"
+
+&soc {
+ /delete-node/ ssusb@a800000;
+ /delete-node/ qusb@88e3000;
+ /delete-node/ ssphy@88eb000;
+};
+
+&usb0 {
+ extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
+
+&qusb_phy0 {
+ vdd-supply = <&pm660l_l1>;
+ vdda18-supply = <&pm660_l10>;
+ vdda33-supply = <&pm660l_l7>;
+};
+
+&usb_qmp_dp_phy {
+ vdd-supply = <&pm660l_l1>; /* 0.88v */
+ core-supply = <&pm660_l1>; /* 1.2v */
+};
+
+&pcie0 {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
index c709770..4b24b0d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
@@ -16,4 +16,30 @@
&qupv3_se10_i2c {
/delete-node/ qcom,smb1355@8;
+ /delete-node/ qcom,smb1355@c;
+};
+
+&soc {
+ /delete-node/ ssusb@a800000;
+ /delete-node/ qusb@88e3000;
+ /delete-node/ ssphy@88eb000;
+};
+
+&usb0 {
+ extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
+
+&qusb_phy0 {
+ vdd-supply = <&pm660l_l1>;
+ vdda18-supply = <&pm660_l10>;
+ vdda33-supply = <&pm660l_l7>;
+};
+
+&usb_qmp_dp_phy {
+ vdd-supply = <&pm660l_l1>; /* 0.88v */
+ core-supply = <&pm660_l1>; /* 1.2v */
+};
+
+&pcie0 {
+ status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 3d58dc1..3756197 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -198,6 +198,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -234,6 +235,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
@@ -291,7 +293,11 @@
qcom,battery-data = <&mtp_batterydata>;
};
-&smb1355_charger {
+&smb1355_charger_0 {
+ status = "ok";
+};
+
+&smb1355_charger_1 {
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
index 000d65e7..2ac313d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
@@ -32,6 +32,9 @@
smb2_vconn: qcom,smb2-vconn {
regulator-name = "smb2-vconn";
};
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
+ };
};
&usb0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6122eee..02f30fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -88,7 +88,11 @@
qcom,fg-bmd-en-delay-ms = <300>;
};
-&smb1355_charger {
+&smb1355_charger_0 {
+ status = "ok";
+};
+
+&smb1355_charger_1 {
status = "ok";
};
@@ -111,6 +115,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -147,6 +152,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index 6ea92ee..7bc4d89 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -9,3 +9,35 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+
+&pmi8998_pdphy {
+ vbus-supply = <&smb2_vbus>;
+};
+
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l20>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index f50df47..d22c28a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -1389,12 +1389,24 @@
compatible = "qcom,rpmh-vrm-regulator";
mboxes = <&apps_rsc 0>;
qcom,resource-name = "bobb1";
+ qcom,send-defaults;
+
pmi8998_bob: regulator-bob {
regulator-name = "pmi8998_bob";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_PASS>;
+ };
+
+ pmi8998_bob_ao: regulator-bob-ao {
+ regulator-name = "pmi8998_bob_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,init-voltage = <3312000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_AUTO>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index e7fd8a0..99004bf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -33,6 +33,7 @@
vdd-hba-supply = <&ufs_phy_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
@@ -157,6 +158,7 @@
vdd-hba-supply = <&ufs_card_gdsc>;
vdd-hba-fixed-regulator;
vcc-supply = <&pm8998_l21>;
+ vcc-voltage-level = <2950000 2960000>;
vccq2-supply = <&pm8998_s4>;
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index db3d23c..03b40b3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -430,10 +430,11 @@
<0xaf02000 0x1a0>,
<0x780000 0x621c>,
<0x88ea030 0x10>,
+ <0x88e8000 0x20>,
<0x0aee1000 0x034>;
reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
"dp_mmss_cc", "qfprom_physical", "dp_pll",
- "hdcp_physical";
+ "usb3_dp_com", "hdcp_physical";
interrupt-parent = <&mdss_mdp>;
interrupts = <12 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 0618f92..6051106 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -130,6 +130,9 @@
qcom,sde-has-idle-pc;
qcom,sde-max-bw-low-kbps = <9600000>;
qcom,sde-max-bw-high-kbps = <9600000>;
+ qcom,sde-min-core-ib-kbps = <2400000>;
+ qcom,sde-min-llcc-ib-kbps = <800000>;
+ qcom,sde-min-dram-ib-kbps = <800000>;
qcom,sde-dram-channels = <2>;
qcom,sde-num-nrt-paths = <0>;
qcom,sde-dspp-ad-version = <0x00040000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..5b3e964
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel CDP";
+ compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..0d6c5e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel MTP";
+ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..764c145
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel QRD";
+ compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+ qcom,msm-id = <321 0x20000>;
+ qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+ /delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+ qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+ qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 98ab8d4..0b55736 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -477,6 +477,10 @@
};
};
+&pil_modem {
+ qcom,mss_pdc_offset = <9>;
+};
+
/* VDD_APC0 */
&pm8998_s13 {
regulator-min-microvolt = <568000>;
@@ -843,6 +847,25 @@
qcom,count-unit = <0x10000>;
};
+&cpubw {
+ qcom,bw-tbl =
+ < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */
+ < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */
+ < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */
+ < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */
+ < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */
+ < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */
+ < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */
+};
+
+&devfreq_cpufreq {
+ mincpubw-cpufreq {
+ cpu-to-dev-map-4 =
+ < 1881600 MHZ_TO_MBPS(200, 4) >,
+ < 2400000 MHZ_TO_MBPS(681, 4) >;
+ };
+};
+
&clock_gcc {
compatible = "qcom,gcc-sdm845-v2", "syscon";
};
@@ -885,15 +908,16 @@
&mdss_mdp {
clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+ qcom,sde-min-core-ib-kbps = <4800000>;
};
&energy_costs {
CPU_COST_0: core-cost0 {
busy-cost-data = <
- 300000 11
+ 300000 12
403200 17
480000 21
- 576000 26
+ 576000 27
652800 31
748800 37
825600 42
@@ -901,13 +925,13 @@
979200 52
1056000 57
1132800 62
- 1228800 69
+ 1228800 70
1324800 78
1420800 89
1516800 103
1612800 122
- 1689600 140
- 1766400 159
+ 1689600 141
+ 1766400 160
>;
idle-cost-data = <
22 18 14 12
@@ -915,37 +939,37 @@
};
CPU_COST_1: core-cost1 {
busy-cost-data = <
- 300000 130
- 403200 480
- 480000 730
- 576000 1030
- 652800 1260
- 748800 1530
- 825600 1740
- 902400 1930
- 979200 2110
- 1056000 2290
- 1132800 2460
- 1209600 2630
- 1286400 2800
- 1363200 2980
- 1459200 3240
- 1536000 3490
- 1612800 3780
- 1689600 4120
- 1766400 4530
- 1843200 5020
- 1920000 5590
- 1996800 6230
+ 300000 189
+ 403200 523
+ 480000 763
+ 576000 1052
+ 652800 1273
+ 748800 1536
+ 825600 1736
+ 902400 1926
+ 979200 2108
+ 1056000 2284
+ 1132800 2456
+ 1209600 2628
+ 1286400 2804
+ 1363200 2992
+ 1459200 3255
+ 1536000 3499
+ 1612800 3786
+ 1689600 4128
+ 1766400 4535
+ 1843200 5019
+ 1920000 5583
+ 1996800 6226
2092800 7120
- 2169600 7870
- 2246400 8620
- 2323200 9330
+ 2169600 7876
+ 2246400 8628
+ 2323200 9344
2400000 10030
- 2476800 10830
- 2553600 12080
- 2630400 14580
- 2707200 19960
+ 2476800 10806
+ 2553600 12045
+ 2649600 15686
+ 2745600 25586
>;
idle-cost-data = <
100 80 60 40
@@ -1007,8 +1031,8 @@
2400000 135
2476800 140
2553600 145
- 2630400 150
- 2707200 155
+ 2649600 150
+ 2745600 155
>;
idle-cost-data = <
4 3 2 1
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index d72c91c..b4c1fb3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -547,7 +547,6 @@
wlan_fw_region: wlan_fw_region@8cb00000 {
compatible = "shared-dma-pool";
- no-map;
reg = <0 0x8cb00000 0 0x100000>;
};
@@ -828,12 +827,12 @@
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
qcom,active-only;
qcom,bw-tbl =
- < 2288 /* 150 MHz */ >,
- < 4577 /* 300 MHz */ >,
- < 6500 /* 426 MHz */ >,
- < 8132 /* 533 MHz */ >,
- < 9155 /* 600 MHz */ >,
- < 10681 /* 700 MHz */ >;
+ < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */
+ < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */
+ < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */
+ < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */
+ < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */
+ < MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */
};
bwmon: qcom,cpu-bwmon {
@@ -853,16 +852,16 @@
<MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
llcc_bwmon: qcom,llcc-bwmon {
@@ -883,16 +882,16 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
memlat_cpu4: qcom,memlat-cpu4 {
@@ -902,16 +901,16 @@
qcom,active-only;
status = "ok";
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
@@ -930,11 +929,11 @@
qcom,target-dev = <&memlat_cpu0>;
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
- < 300000 762 >,
- < 748800 1720 >,
- < 1132800 2086 >,
- < 1440000 2929 >,
- < 1593600 3879 >;
+ < 300000 MHZ_TO_MBPS( 200, 4) >,
+ < 748800 MHZ_TO_MBPS( 451, 4) >,
+ < 1132800 MHZ_TO_MBPS( 547, 4) >,
+ < 1440000 MHZ_TO_MBPS( 768, 4) >,
+ < 1593600 MHZ_TO_MBPS(1017, 4) >;
};
devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -943,14 +942,14 @@
qcom,target-dev = <&memlat_cpu4>;
qcom,cachemiss-ev = <0x2A>;
qcom,core-dev-table =
- < 300000 762 >,
- < 499200 1720 >,
- < 806400 2086 >,
- < 1036800 2929 >,
- < 1190400 3879 >,
- < 1574400 4943 >,
- < 1728000 5931 >,
- < 1958400 6881 >;
+ < 300000 MHZ_TO_MBPS( 200, 4) >,
+ < 499200 MHZ_TO_MBPS( 451, 4) >,
+ < 806400 MHZ_TO_MBPS( 547, 4) >,
+ < 1036800 MHZ_TO_MBPS( 768, 4) >,
+ < 1190400 MHZ_TO_MBPS(1017, 4) >,
+ < 1574400 MHZ_TO_MBPS(1296, 4) >,
+ < 1728000 MHZ_TO_MBPS(1555, 4) >,
+ < 1958400 MHZ_TO_MBPS(1804, 4) >;
};
l3_cpu0: qcom,l3-cpu0 {
@@ -1008,26 +1007,26 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 4943 /* 1296 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
- devfreq-cpufreq {
+ devfreq_cpufreq: devfreq-cpufreq {
mincpubw-cpufreq {
target-dev = <&mincpubw>;
cpu-to-dev-map-0 =
- < 1708800 762 >;
+ < 1708800 MHZ_TO_MBPS(200, 4) >;
cpu-to-dev-map-4 =
- < 1881600 762 >,
- < 2208000 2597 >;
+ < 1881600 MHZ_TO_MBPS(200, 4) >,
+ < 2208000 MHZ_TO_MBPS(681, 4) >;
};
};
@@ -1742,6 +1741,7 @@
qcom,ssctl-instance-id = <0x12>;
qcom,override-acc;
qcom,qdsp6v65-1-0;
+ qcom,mss_pdc_offset = <8>;
status = "ok";
memory-region = <&pil_modem_mem>;
qcom,mem-protect-id = <0xF>;
@@ -2540,6 +2540,18 @@
qcom,fragmented-data;
};
+ qcom,qsee_ipc_irq_bridge {
+ compatible = "qcom,qsee-ipc-irq-bridge";
+
+ qcom,qsee-ipq-irq-spss {
+ qcom,rx-irq-clr = <0x1888008 0x4>;
+ qcom,rx-irq-clr-mask = <0x1>;
+ qcom,dev-name = "qsee_ipc_irq_spss";
+ interrupts = <0 349 4>;
+ label = "spss";
+ };
+ };
+
qcom,spcom {
compatible = "qcom,spcom";
@@ -3009,7 +3021,6 @@
<0 424 0 /* CE10 */ >,
<0 425 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x100000>;
- qcom,wlan-msa-fixed-region = <&wlan_fw_region>;
vdd-0.8-cx-mx-supply = <&pm8998_l5>;
vdd-1.8-xo-supply = <&pm8998_l7>;
@@ -3041,6 +3052,11 @@
#cooling-cells = <2>;
};
+ modem_skin: modem_skin {
+ qcom,qmi-dev-name = "modem_skin";
+ #cooling-cells = <2>;
+ };
+
modem_vdd: modem_vdd {
qcom,qmi-dev-name = "cpuv_restriction_cold";
#cooling-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi
index 6b7ebbd..bde4d1e 100644
--- a/arch/arm64/boot/dts/qcom/smb1355.dtsi
+++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi
@@ -13,30 +13,75 @@
#include <dt-bindings/interrupt-controller/irq.h>
&qupv3_se10_i2c {
- smb1355: qcom,smb1355@8 {
+ smb1355_0: qcom,smb1355@8 {
compatible = "qcom,i2c-pmic";
reg = <0x8>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&spmi_bus>;
interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
- interrupt_names = "smb1355";
+ interrupt_names = "smb1355_0";
interrupt-controller;
#interrupt-cells = <3>;
qcom,periph-map = <0x10 0x12 0x13 0x16>;
- smb1355_revid: qcom,revid@100 {
+ smb1355_revid_0: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
- smb1355_charger: qcom,smb1355-charger@1000 {
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
compatible = "qcom,smb1355";
- qcom,pmic-revid = <&smb1355_revid>;
+ qcom,pmic-revid = <&smb1355_revid_0>;
reg = <0x1000 0x700>;
#address-cells = <1>;
#size-cells = <1>;
- interrupt-parent = <&smb1355>;
+ interrupt-parent = <&smb1355_0>;
+ status = "disabled";
+
+ io-channels = <&pmi8998_rradc 2>,
+ <&pmi8998_rradc 12>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max";
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "chg-state-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog-bark";
+ };
+ };
+ };
+
+ smb1355_1: qcom,smb1355@c {
+ compatible = "qcom,i2c-pmic";
+ reg = <0xc>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt_names = "smb1355_1";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ qcom,periph-map = <0x10 0x12 0x13 0x16>;
+
+ smb1355_revid_1: qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ compatible = "qcom,smb1355";
+ qcom,pmic-revid = <&smb1355_revid_1>;
+ reg = <0x1000 0x700>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&smb1355_1>;
status = "disabled";
io-channels = <&pmi8998_rradc 2>,
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 07e7ee9..dc09f04 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -321,10 +321,12 @@
CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
CONFIG_QTI_VIRTUAL_SENSOR=y
CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -390,6 +392,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -454,9 +457,14 @@
CONFIG_MSM_11AD=m
CONFIG_SEEMP_CORE=y
CONFIG_QCOM_GENI_SE=y
+CONFIG_MSM_GCC_SDM845=y
+CONFIG_MSM_VIDEOCC_SDM845=y
+CONFIG_MSM_CAMCC_SDM845=y
+CONFIG_MSM_DISPCC_SDM845=y
CONFIG_CLOCK_QPNP_DIV=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index cda924c..79bb308 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -29,6 +29,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -234,6 +235,7 @@
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
CONFIG_DMA_CMA=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
@@ -330,6 +332,8 @@
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
CONFIG_QTI_VIRTUAL_SENSOR=y
CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -385,6 +389,7 @@
CONFIG_USB_PD_POLICY=y
CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -457,9 +462,14 @@
CONFIG_MSM_11AD=m
CONFIG_SEEMP_CORE=y
CONFIG_QCOM_GENI_SE=y
+CONFIG_MSM_GCC_SDM845=y
+CONFIG_MSM_VIDEOCC_SDM845=y
+CONFIG_MSM_CAMCC_SDM845=y
+CONFIG_MSM_DISPCC_SDM845=y
CONFIG_CLOCK_QPNP_DIV=y
CONFIG_MSM_CLK_RPMH=y
CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index d2d2bf0..a04d0f4 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -528,6 +528,7 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 4b347e6..7655c91 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -237,6 +237,7 @@
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
CONFIG_DMA_CMA=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
@@ -550,6 +551,7 @@
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
CONFIG_MSM_REMOTEQDSS=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -610,6 +612,7 @@
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_PANIC_ON_SCHED_BUG=y
@@ -650,6 +653,7 @@
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index ab0e5b2..110f750 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -14,14 +14,16 @@
struct dma_iommu_mapping {
/* iommu specific data */
struct iommu_domain *domain;
+ bool init;
+ struct kref kref;
+ const struct dma_map_ops *ops;
+ /* Protects bitmap */
+ spinlock_t lock;
void *bitmap;
size_t bits;
dma_addr_t base;
- spinlock_t lock;
- struct kref kref;
-
struct dma_fast_smmu_mapping *fast;
};
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index afa23b0..1fb0230 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -114,10 +114,10 @@
/*
* This is the base location for PIE (ET_DYN with INTERP) loads. On
- * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
* space open for things that want to use the area for 32-bit pointers.
*/
-#define ELF_ET_DYN_BASE 0x100000000UL
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 394c61d..1d5890f 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -157,9 +157,11 @@
void fpsimd_flush_thread(void)
{
+ preempt_disable();
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
fpsimd_flush_task_state(current);
set_thread_flag(TIF_FOREIGN_FPSTATE);
+ preempt_enable();
}
/*
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 7f90b7e..5229b33 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1906,23 +1906,42 @@
* IO address ranges, which is required to perform memory allocation and
* mapping with IOMMU aware functions.
*
- * The client device need to be attached to the mapping with
- * arm_iommu_attach_device function.
+ * Clients may use iommu_domain_set_attr() to set additional flags prior
+ * to calling arm_iommu_attach_device() to complete initialization.
*/
struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
{
unsigned int bits = size >> PAGE_SHIFT;
- unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
struct dma_iommu_mapping *mapping;
- int err = -ENOMEM;
- if (!bitmap_size)
+ if (!bits)
return ERR_PTR(-EINVAL);
mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
if (!mapping)
- goto err;
+ return ERR_PTR(-ENOMEM);
+
+ mapping->base = base;
+ mapping->bits = bits;
+
+ mapping->domain = iommu_domain_alloc(bus);
+ if (!mapping->domain)
+ goto err_domain_alloc;
+
+ mapping->init = false;
+ return mapping;
+
+err_domain_alloc:
+ kfree(mapping);
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(arm_iommu_create_mapping);
+
+static int
+bitmap_iommu_init_mapping(struct device *dev, struct dma_iommu_mapping *mapping)
+{
+ unsigned int bitmap_size = BITS_TO_LONGS(mapping->bits) * sizeof(long);
mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL | __GFP_NOWARN |
__GFP_NORETRY);
@@ -1930,67 +1949,124 @@
mapping->bitmap = vzalloc(bitmap_size);
if (!mapping->bitmap)
- goto err2;
+ return -ENOMEM;
- mapping->base = base;
- mapping->bits = bits;
spin_lock_init(&mapping->lock);
-
- mapping->domain = iommu_domain_alloc(bus);
- if (!mapping->domain)
- goto err3;
-
- kref_init(&mapping->kref);
- return mapping;
-err3:
- kvfree(mapping->bitmap);
-err2:
- kfree(mapping);
-err:
- return ERR_PTR(err);
+ mapping->ops = &iommu_ops;
+ return 0;
}
-EXPORT_SYMBOL(arm_iommu_create_mapping);
-static void release_iommu_mapping(struct kref *kref)
+static void bitmap_iommu_release_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ kfree(mapping->bitmap);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+}
+
+static void bypass_iommu_release_mapping(struct kref *kref)
{
struct dma_iommu_mapping *mapping =
container_of(kref, struct dma_iommu_mapping, kref);
iommu_domain_free(mapping->domain);
- kvfree(mapping->bitmap);
kfree(mapping);
}
+static int upstream_iommu_init_mapping(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ struct iommu_domain *domain = mapping->domain;
+ struct iommu_group *group = dev->iommu_group;
+ dma_addr_t base = mapping->base;
+ u64 size = mapping->bits << PAGE_SHIFT;
+
+ if (iommu_get_dma_cookie(domain))
+ return -EINVAL;
+
+ /* Need to attach to get geometry */
+ if (iommu_attach_group(domain, group))
+ goto out_put_cookie;
+
+ if (iommu_dma_init_domain(domain, base, size, dev))
+ goto out_detach_group;
+
+ mapping->ops = &iommu_dma_ops;
+ iommu_detach_group(domain, group);
+ return 0;
+
+out_detach_group:
+ iommu_detach_group(domain, group);
+out_put_cookie:
+ iommu_put_dma_cookie(domain);
+ return -EINVAL;
+}
+
+static void upstream_iommu_release_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ iommu_put_dma_cookie(mapping->domain);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+}
+
+/*
+ * arm_iommu_release_mapping
+ * @mapping: allocted via arm_iommu_create_mapping()
+ *
+ * Frees all resources associated with the iommu mapping.
+ * The device associated with this mapping must be in the 'detached' state
+ */
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
- if (mapping)
- kref_put(&mapping->kref, release_iommu_mapping);
+ int s1_bypass = 0, is_fast = 0, is_upstream = 0;
+ void (*release)(struct kref *kref);
+
+ if (!mapping)
+ return;
+
+ if (!mapping->init) {
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
+ return;
+ }
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ iommu_domain_get_attr(mapping->domain,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
+ &is_upstream);
+
+ if (s1_bypass)
+ release = bypass_iommu_release_mapping;
+ else if (is_fast)
+ release = fast_smmu_release_mapping;
+ else if (is_upstream)
+ release = upstream_iommu_release_mapping;
+ else
+ release = bitmap_iommu_release_mapping;
+
+ kref_put(&mapping->kref, release);
}
EXPORT_SYMBOL(arm_iommu_release_mapping);
-/**
- * arm_iommu_attach_device
- * @dev: valid struct device pointer
- * @mapping: io address space mapping structure (returned from
- * arm_iommu_create_mapping)
- *
- * Attaches specified io address space mapping to the provided device,
- * this replaces the dma operations (dma_map_ops pointer) with the
- * IOMMU aware version. Only one device in an iommu_group may use this
- * function.
- */
-int arm_iommu_attach_device(struct device *dev,
+static int arm_iommu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
- int err;
- int s1_bypass = 0, is_fast = 0;
+ int err = -EINVAL;
+ int s1_bypass = 0, is_fast = 0, is_upstream = 0;
struct iommu_group *group;
dma_addr_t iova_end;
group = dev->iommu_group;
if (!group) {
dev_err(dev, "No iommu associated with device\n");
- return -ENODEV;
+ return -EINVAL;
}
if (iommu_get_domain_for_dev(dev)) {
@@ -1998,6 +2074,11 @@
return -EINVAL;
}
+ if (mapping->init) {
+ kref_get(&mapping->kref);
+ return 0;
+ }
+
iova_end = mapping->base + (mapping->bits << PAGE_SHIFT) - 1;
if (iova_end > dma_get_mask(dev)) {
dev_err(dev, "dma mask %llx too small for requested iova range %pad to %pad\n",
@@ -2005,21 +2086,59 @@
return -EINVAL;
}
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
+ &s1_bypass);
iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
- if (is_fast)
- return fast_smmu_attach_device(dev, mapping);
+ iommu_domain_get_attr(mapping->domain,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
+ &is_upstream);
- err = iommu_attach_group(mapping->domain, group);
+ if (s1_bypass) {
+ mapping->ops = &swiotlb_dma_ops;
+ err = 0;
+ } else if (is_fast) {
+ err = fast_smmu_init_mapping(dev, mapping);
+ } else if (is_upstream) {
+ err = upstream_iommu_init_mapping(dev, mapping);
+ } else {
+ err = bitmap_iommu_init_mapping(dev, mapping);
+ }
+ if (!err) {
+ kref_init(&mapping->kref);
+ mapping->init = true;
+ }
+ return err;
+}
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ * arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version.
+ *
+ * Clients are expected to call arm_iommu_attach_device() prior to sharing
+ * the dma_iommu_mapping structure with another device. This ensures
+ * initialization is complete.
+ */
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ int err;
+
+ err = arm_iommu_init_mapping(dev, mapping);
if (err)
return err;
- iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
- &s1_bypass);
+ err = iommu_attach_group(mapping->domain, dev->iommu_group);
+ if (err)
+ return err;
- kref_get(&mapping->kref);
dev->archdata.mapping = mapping;
- if (!s1_bypass)
- set_dma_ops(dev, &iommu_ops);
+ set_dma_ops(dev, mapping->ops);
pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
return 0;
@@ -2036,8 +2155,7 @@
void arm_iommu_detach_device(struct device *dev)
{
struct dma_iommu_mapping *mapping;
- int is_fast, s1_bypass = 0;
- struct iommu_group *group;
+ int s1_bypass = 0;
mapping = to_dma_iommu_mapping(dev);
if (!mapping) {
@@ -2045,26 +2163,22 @@
return;
}
- iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
- if (is_fast) {
- fast_smmu_detach_device(dev, mapping);
+ if (!dev->iommu_group) {
+ dev_err(dev, "No iommu associated with device\n");
return;
}
iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
&s1_bypass);
+ /*
+ * ION defers dma_unmap calls. Ensure they have all completed prior to
+ * setting dma_ops to NULL.
+ */
if (msm_dma_unmap_all_for_dev(dev))
dev_warn(dev, "IOMMU detach with outstanding mappings\n");
- group = dev->iommu_group;
- if (!group) {
- dev_err(dev, "No iommu associated with device\n");
- return;
- }
-
- iommu_detach_group(mapping->domain, group);
- kref_put(&mapping->kref, release_iommu_mapping);
+ iommu_detach_group(mapping->domain, dev->iommu_group);
dev->archdata.mapping = NULL;
if (!s1_bypass)
set_dma_ops(dev, NULL);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 7f9501a..792dac8 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -384,8 +384,11 @@
* signal first. We do not need to release the mmap_sem because it
* would already be released in __lock_page_or_retry in mm/filemap.c.
*/
- if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+ if (!user_mode(regs))
+ goto no_context;
return 0;
+ }
/*
* Major/minor page fault accounting is only done on the initial
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 1910223..cea2bb1 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -147,23 +147,12 @@
* Find irq with highest priority
*/
# open coded PTR_LA t1, cpu_mask_nr_tbl
-#if (_MIPS_SZPTR == 32)
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
# open coded la t1, cpu_mask_nr_tbl
lui t1, %hi(cpu_mask_nr_tbl)
addiu t1, %lo(cpu_mask_nr_tbl)
-
-#endif
-#if (_MIPS_SZPTR == 64)
- # open coded dla t1, cpu_mask_nr_tbl
- .set push
- .set noat
- lui t1, %highest(cpu_mask_nr_tbl)
- lui AT, %hi(cpu_mask_nr_tbl)
- daddiu t1, t1, %higher(cpu_mask_nr_tbl)
- daddiu AT, AT, %lo(cpu_mask_nr_tbl)
- dsll t1, 32
- daddu t1, t1, AT
- .set pop
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
#endif
1: lw t2,(t1)
nop
@@ -214,23 +203,12 @@
* Find irq with highest priority
*/
# open coded PTR_LA t1,asic_mask_nr_tbl
-#if (_MIPS_SZPTR == 32)
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
# open coded la t1, asic_mask_nr_tbl
lui t1, %hi(asic_mask_nr_tbl)
addiu t1, %lo(asic_mask_nr_tbl)
-
-#endif
-#if (_MIPS_SZPTR == 64)
- # open coded dla t1, asic_mask_nr_tbl
- .set push
- .set noat
- lui t1, %highest(asic_mask_nr_tbl)
- lui AT, %hi(asic_mask_nr_tbl)
- daddiu t1, t1, %higher(asic_mask_nr_tbl)
- daddiu AT, AT, %lo(asic_mask_nr_tbl)
- dsll t1, 32
- daddu t1, t1, AT
- .set pop
+#else
+#error GCC `-msym32' option required for 64-bit DECstation builds
#endif
2: lw t2,(t1)
nop
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index c721ea2..df757c9 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -604,13 +604,12 @@
if (parisc_requires_coherency())
flush_tlb_range(vma, start, end);
- if ((end - start) >= parisc_cache_flush_threshold) {
+ if ((end - start) >= parisc_cache_flush_threshold
+ || vma->vm_mm->context != mfsp(3)) {
flush_cache_all();
return;
}
- BUG_ON(vma->vm_mm->context != mfsp(3));
-
flush_user_dcache_range_asm(start, end);
if (vma->vm_flags & VM_EXEC)
flush_user_icache_range_asm(start, end);
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 0012f03..fe208b7 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -75,9 +75,27 @@
struct task_struct *tsk)
{
/* Mark this context has been used on the new CPU */
- if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next)))
+ if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) {
cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
+ /*
+ * This full barrier orders the store to the cpumask above vs
+ * a subsequent operation which allows this CPU to begin loading
+ * translations for next.
+ *
+ * When using the radix MMU that operation is the load of the
+ * MMU context id, which is then moved to SPRN_PID.
+ *
+ * For the hash MMU it is either the first load from slb_cache
+ * in switch_slb(), and/or the store of paca->mm_ctx_id in
+ * copy_mm_to_paca().
+ *
+ * On the read side the barrier is in pte_xchg(), which orders
+ * the store to the PTE vs the load of mm_cpumask.
+ */
+ smp_mb();
+ }
+
/* 32-bit keeps track of the current PGDIR in the thread struct */
#ifdef CONFIG_PPC32
tsk->thread.pgdir = next->pgd;
diff --git a/arch/powerpc/include/asm/pgtable-be-types.h b/arch/powerpc/include/asm/pgtable-be-types.h
index 49c0a5a..68e087e 100644
--- a/arch/powerpc/include/asm/pgtable-be-types.h
+++ b/arch/powerpc/include/asm/pgtable-be-types.h
@@ -87,6 +87,7 @@
unsigned long *p = (unsigned long *)ptep;
__be64 prev;
+ /* See comment in switch_mm_irqs_off() */
prev = (__force __be64)__cmpxchg_u64(p, (__force unsigned long)pte_raw(old),
(__force unsigned long)pte_raw(new));
diff --git a/arch/powerpc/include/asm/pgtable-types.h b/arch/powerpc/include/asm/pgtable-types.h
index e7f4f3e..41e9d0a 100644
--- a/arch/powerpc/include/asm/pgtable-types.h
+++ b/arch/powerpc/include/asm/pgtable-types.h
@@ -62,6 +62,7 @@
{
unsigned long *p = (unsigned long *)ptep;
+ /* See comment in switch_mm_irqs_off() */
return pte_val(old) == __cmpxchg_u64(p, pte_val(old), pte_val(new));
}
#endif
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 3c05c31..028a22b 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -146,6 +146,19 @@
/* Clear bit 0 which we wouldn't clear otherwise */
local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
+ if (happened & PACA_IRQ_HARD_DIS) {
+ /*
+ * We may have missed a decrementer interrupt if hard disabled.
+ * Check the decrementer register in case we had a rollover
+ * while hard disabled.
+ */
+ if (!(happened & PACA_IRQ_DEC)) {
+ if (decrementer_check_overflow()) {
+ local_paca->irq_happened |= PACA_IRQ_DEC;
+ happened |= PACA_IRQ_DEC;
+ }
+ }
+ }
/*
* Force the delivery of pending soft-disabled interrupts on PS3.
@@ -171,7 +184,7 @@
* in case we also had a rollover while hard disabled
*/
local_paca->irq_happened &= ~PACA_IRQ_DEC;
- if ((happened & PACA_IRQ_DEC) || decrementer_check_overflow())
+ if (happened & PACA_IRQ_DEC)
return 0x900;
/* Finally check if an external interrupt happened */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index b249c2f..1c141d5 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -359,7 +359,8 @@
cpumsr = msr_check_and_set(MSR_FP|MSR_VEC|MSR_VSX);
- if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) {
+ if (current->thread.regs &&
+ (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP))) {
check_if_tm_restore_required(current);
/*
* If a thread has already been reclaimed then the
@@ -383,7 +384,7 @@
{
if (tsk->thread.regs) {
preempt_disable();
- if (tsk->thread.regs->msr & MSR_VSX) {
+ if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
BUG_ON(tsk != current);
giveup_vsx(tsk);
}
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5c8f12f..dcbb914 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -127,12 +127,19 @@
* If task is not current, it will have been flushed already to
* it's thread_struct during __switch_to().
*
- * A reclaim flushes ALL the state.
+ * A reclaim flushes ALL the state or if not in TM save TM SPRs
+ * in the appropriate thread structures from live.
*/
- if (tsk == current && MSR_TM_SUSPENDED(mfmsr()))
- tm_reclaim_current(TM_CAUSE_SIGNAL);
+ if (tsk != current)
+ return;
+ if (MSR_TM_SUSPENDED(mfmsr())) {
+ tm_reclaim_current(TM_CAUSE_SIGNAL);
+ } else {
+ tm_enable();
+ tm_save_sprs(&(tsk->thread));
+ }
}
#else
static inline void flush_tmregs_to_thread(struct task_struct *tsk) { }
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kvm/sthyi.c
index 05c98bb..2f04ad1 100644
--- a/arch/s390/kvm/sthyi.c
+++ b/arch/s390/kvm/sthyi.c
@@ -394,7 +394,7 @@
"srl %[cc],28\n"
: [cc] "=d" (cc)
: [code] "d" (code), [addr] "a" (addr)
- : "memory", "cc");
+ : "3", "memory", "cc");
return cc;
}
@@ -422,7 +422,7 @@
VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
trace_kvm_s390_handle_sthyi(vcpu, code, addr);
- if (reg1 == reg2 || reg1 & 1 || reg2 & 1 || addr & ~PAGE_MASK)
+ if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
if (code & 0xffff) {
@@ -430,6 +430,9 @@
goto out;
}
+ if (addr & ~PAGE_MASK)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
/*
* If the page has not yet been faulted in, we want to do that
* now and not after all the expensive calculations.
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index bee281f..e8dee62 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -1252,7 +1252,8 @@
insn_count = bpf_jit_insn(jit, fp, i);
if (insn_count < 0)
return -1;
- jit->addrs[i + 1] = jit->prg; /* Next instruction address */
+ /* Next instruction address */
+ jit->addrs[i + insn_count] = jit->prg;
}
bpf_jit_epilogue(jit);
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h
index 349dd23..0cdeb2b 100644
--- a/arch/sparc/include/asm/mmu_context_64.h
+++ b/arch/sparc/include/asm/mmu_context_64.h
@@ -25,9 +25,11 @@
void __tsb_context_switch(unsigned long pgd_pa,
struct tsb_config *tsb_base,
struct tsb_config *tsb_huge,
- unsigned long tsb_descr_pa);
+ unsigned long tsb_descr_pa,
+ unsigned long secondary_ctx);
-static inline void tsb_context_switch(struct mm_struct *mm)
+static inline void tsb_context_switch_ctx(struct mm_struct *mm,
+ unsigned long ctx)
{
__tsb_context_switch(__pa(mm->pgd),
&mm->context.tsb_block[0],
@@ -38,9 +40,12 @@
#else
NULL
#endif
- , __pa(&mm->context.tsb_descr[0]));
+ , __pa(&mm->context.tsb_descr[0]),
+ ctx);
}
+#define tsb_context_switch(X) tsb_context_switch_ctx(X, 0)
+
void tsb_grow(struct mm_struct *mm,
unsigned long tsb_index,
unsigned long mm_rss);
@@ -110,8 +115,7 @@
* cpu0 to update it's TSB because at that point the cpu_vm_mask
* only had cpu1 set in it.
*/
- load_secondary_context(mm);
- tsb_context_switch(mm);
+ tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
/* Any time a processor runs a context on an address space
* for the first time, we must flush that context out of the
diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h
index ec9c04d..ff05992 100644
--- a/arch/sparc/include/asm/trap_block.h
+++ b/arch/sparc/include/asm/trap_block.h
@@ -54,6 +54,7 @@
void init_cur_cpu_trap(struct thread_info *);
void setup_tba(void);
extern int ncpus_probed;
+extern u64 cpu_mondo_counter[NR_CPUS];
unsigned long real_hard_smp_processor_id(void);
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index 06981cc..d04111a 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -1240,8 +1240,6 @@
* ATU group, but ATU hcalls won't be available.
*/
hv_atu = false;
- pr_err(PFX "Could not register hvapi ATU err=%d\n",
- err);
} else {
pr_info(PFX "Registered hvapi ATU major[%lu] minor[%lu]\n",
vatu_major, vatu_minor);
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index d5807d2..2deb89e 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -621,22 +621,48 @@
}
}
-/* Multi-cpu list version. */
+#define CPU_MONDO_COUNTER(cpuid) (cpu_mondo_counter[cpuid])
+#define MONDO_USEC_WAIT_MIN 2
+#define MONDO_USEC_WAIT_MAX 100
+#define MONDO_RETRY_LIMIT 500000
+
+/* Multi-cpu list version.
+ *
+ * Deliver xcalls to 'cnt' number of cpus in 'cpu_list'.
+ * Sometimes not all cpus receive the mondo, requiring us to re-send
+ * the mondo until all cpus have received, or cpus are truly stuck
+ * unable to receive mondo, and we timeout.
+ * Occasionally a target cpu strand is borrowed briefly by hypervisor to
+ * perform guest service, such as PCIe error handling. Consider the
+ * service time, 1 second overall wait is reasonable for 1 cpu.
+ * Here two in-between mondo check wait time are defined: 2 usec for
+ * single cpu quick turn around and up to 100usec for large cpu count.
+ * Deliver mondo to large number of cpus could take longer, we adjusts
+ * the retry count as long as target cpus are making forward progress.
+ */
static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt)
{
- int retries, this_cpu, prev_sent, i, saw_cpu_error;
+ int this_cpu, tot_cpus, prev_sent, i, rem;
+ int usec_wait, retries, tot_retries;
+ u16 first_cpu = 0xffff;
+ unsigned long xc_rcvd = 0;
unsigned long status;
+ int ecpuerror_id = 0;
+ int enocpu_id = 0;
u16 *cpu_list;
+ u16 cpu;
this_cpu = smp_processor_id();
-
cpu_list = __va(tb->cpu_list_pa);
-
- saw_cpu_error = 0;
- retries = 0;
+ usec_wait = cnt * MONDO_USEC_WAIT_MIN;
+ if (usec_wait > MONDO_USEC_WAIT_MAX)
+ usec_wait = MONDO_USEC_WAIT_MAX;
+ retries = tot_retries = 0;
+ tot_cpus = cnt;
prev_sent = 0;
+
do {
- int forward_progress, n_sent;
+ int n_sent, mondo_delivered, target_cpu_busy;
status = sun4v_cpu_mondo_send(cnt,
tb->cpu_list_pa,
@@ -644,94 +670,113 @@
/* HV_EOK means all cpus received the xcall, we're done. */
if (likely(status == HV_EOK))
- break;
+ goto xcall_done;
+
+ /* If not these non-fatal errors, panic */
+ if (unlikely((status != HV_EWOULDBLOCK) &&
+ (status != HV_ECPUERROR) &&
+ (status != HV_ENOCPU)))
+ goto fatal_errors;
/* First, see if we made any forward progress.
*
+ * Go through the cpu_list, count the target cpus that have
+ * received our mondo (n_sent), and those that did not (rem).
+ * Re-pack cpu_list with the cpus remain to be retried in the
+ * front - this simplifies tracking the truly stalled cpus.
+ *
* The hypervisor indicates successful sends by setting
* cpu list entries to the value 0xffff.
+ *
+ * EWOULDBLOCK means some target cpus did not receive the
+ * mondo and retry usually helps.
+ *
+ * ECPUERROR means at least one target cpu is in error state,
+ * it's usually safe to skip the faulty cpu and retry.
+ *
+ * ENOCPU means one of the target cpu doesn't belong to the
+ * domain, perhaps offlined which is unexpected, but not
+ * fatal and it's okay to skip the offlined cpu.
*/
+ rem = 0;
n_sent = 0;
for (i = 0; i < cnt; i++) {
- if (likely(cpu_list[i] == 0xffff))
+ cpu = cpu_list[i];
+ if (likely(cpu == 0xffff)) {
n_sent++;
+ } else if ((status == HV_ECPUERROR) &&
+ (sun4v_cpu_state(cpu) == HV_CPU_STATE_ERROR)) {
+ ecpuerror_id = cpu + 1;
+ } else if (status == HV_ENOCPU && !cpu_online(cpu)) {
+ enocpu_id = cpu + 1;
+ } else {
+ cpu_list[rem++] = cpu;
+ }
}
- forward_progress = 0;
- if (n_sent > prev_sent)
- forward_progress = 1;
+ /* No cpu remained, we're done. */
+ if (rem == 0)
+ break;
+ /* Otherwise, update the cpu count for retry. */
+ cnt = rem;
+
+ /* Record the overall number of mondos received by the
+ * first of the remaining cpus.
+ */
+ if (first_cpu != cpu_list[0]) {
+ first_cpu = cpu_list[0];
+ xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+ }
+
+ /* Was any mondo delivered successfully? */
+ mondo_delivered = (n_sent > prev_sent);
prev_sent = n_sent;
- /* If we get a HV_ECPUERROR, then one or more of the cpus
- * in the list are in error state. Use the cpu_state()
- * hypervisor call to find out which cpus are in error state.
+ /* or, was any target cpu busy processing other mondos? */
+ target_cpu_busy = (xc_rcvd < CPU_MONDO_COUNTER(first_cpu));
+ xc_rcvd = CPU_MONDO_COUNTER(first_cpu);
+
+ /* Retry count is for no progress. If we're making progress,
+ * reset the retry count.
*/
- if (unlikely(status == HV_ECPUERROR)) {
- for (i = 0; i < cnt; i++) {
- long err;
- u16 cpu;
-
- cpu = cpu_list[i];
- if (cpu == 0xffff)
- continue;
-
- err = sun4v_cpu_state(cpu);
- if (err == HV_CPU_STATE_ERROR) {
- saw_cpu_error = (cpu + 1);
- cpu_list[i] = 0xffff;
- }
- }
- } else if (unlikely(status != HV_EWOULDBLOCK))
- goto fatal_mondo_error;
-
- /* Don't bother rewriting the CPU list, just leave the
- * 0xffff and non-0xffff entries in there and the
- * hypervisor will do the right thing.
- *
- * Only advance timeout state if we didn't make any
- * forward progress.
- */
- if (unlikely(!forward_progress)) {
- if (unlikely(++retries > 10000))
- goto fatal_mondo_timeout;
-
- /* Delay a little bit to let other cpus catch up
- * on their cpu mondo queue work.
- */
- udelay(2 * cnt);
+ if (likely(mondo_delivered || target_cpu_busy)) {
+ tot_retries += retries;
+ retries = 0;
+ } else if (unlikely(retries > MONDO_RETRY_LIMIT)) {
+ goto fatal_mondo_timeout;
}
+
+ /* Delay a little bit to let other cpus catch up on
+ * their cpu mondo queue work.
+ */
+ if (!mondo_delivered)
+ udelay(usec_wait);
+
+ retries++;
} while (1);
- if (unlikely(saw_cpu_error))
- goto fatal_mondo_cpu_error;
-
+xcall_done:
+ if (unlikely(ecpuerror_id > 0)) {
+ pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) was in error state\n",
+ this_cpu, ecpuerror_id - 1);
+ } else if (unlikely(enocpu_id > 0)) {
+ pr_crit("CPU[%d]: SUN4V mondo cpu error, target cpu(%d) does not belong to the domain\n",
+ this_cpu, enocpu_id - 1);
+ }
return;
-fatal_mondo_cpu_error:
- printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus "
- "(including %d) were in error state\n",
- this_cpu, saw_cpu_error - 1);
- return;
+fatal_errors:
+ /* fatal errors include bad alignment, etc */
+ pr_crit("CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) mondo_block_pa(%lx)\n",
+ this_cpu, tot_cpus, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
+ panic("Unexpected SUN4V mondo error %lu\n", status);
fatal_mondo_timeout:
- printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward "
- " progress after %d retries.\n",
- this_cpu, retries);
- goto dump_cpu_list_and_out;
-
-fatal_mondo_error:
- printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n",
- this_cpu, status);
- printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) "
- "mondo_block_pa(%lx)\n",
- this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa);
-
-dump_cpu_list_and_out:
- printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu);
- for (i = 0; i < cnt; i++)
- printk("%u ", cpu_list[i]);
- printk("]\n");
+ /* some cpus being non-responsive to the cpu mondo */
+ pr_crit("CPU[%d]: SUN4V mondo timeout, cpu(%d) made no forward progress after %d retries. Total target cpus(%d).\n",
+ this_cpu, first_cpu, (tot_retries + retries), tot_cpus);
+ panic("SUN4V mondo timeout panic\n");
}
static void (*xcall_deliver_impl)(struct trap_per_cpu *, int);
diff --git a/arch/sparc/kernel/sun4v_ivec.S b/arch/sparc/kernel/sun4v_ivec.S
index 559bc5e..3463199 100644
--- a/arch/sparc/kernel/sun4v_ivec.S
+++ b/arch/sparc/kernel/sun4v_ivec.S
@@ -26,6 +26,21 @@
ldxa [%g0] ASI_SCRATCHPAD, %g4
sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4
+ /* Get smp_processor_id() into %g3 */
+ sethi %hi(trap_block), %g5
+ or %g5, %lo(trap_block), %g5
+ sub %g4, %g5, %g3
+ srlx %g3, TRAP_BLOCK_SZ_SHIFT, %g3
+
+ /* Increment cpu_mondo_counter[smp_processor_id()] */
+ sethi %hi(cpu_mondo_counter), %g5
+ or %g5, %lo(cpu_mondo_counter), %g5
+ sllx %g3, 3, %g3
+ add %g5, %g3, %g5
+ ldx [%g5], %g3
+ add %g3, 1, %g3
+ stx %g3, [%g5]
+
/* Get CPU mondo queue base phys address into %g7. */
ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index d44fb80..32dafb92 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2732,6 +2732,7 @@
}
}
+u64 cpu_mondo_counter[NR_CPUS] = {0};
struct trap_per_cpu trap_block[NR_CPUS];
EXPORT_SYMBOL(trap_block);
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index 395ec18..7d961f6 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -375,6 +375,7 @@
* %o1: TSB base config pointer
* %o2: TSB huge config pointer, or NULL if none
* %o3: Hypervisor TSB descriptor physical address
+ * %o4: Secondary context to load, if non-zero
*
* We have to run this whole thing with interrupts
* disabled so that the current cpu doesn't change
@@ -387,6 +388,17 @@
rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
+ brz,pn %o4, 1f
+ mov SECONDARY_CONTEXT, %o5
+
+661: stxa %o4, [%o5] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %o4, [%o5] ASI_MMU
+ .previous
+ flush %g6
+
+1:
TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
stx %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S
index 54f9870..5a8cb37 100644
--- a/arch/sparc/lib/U3memcpy.S
+++ b/arch/sparc/lib/U3memcpy.S
@@ -145,13 +145,13 @@
ENTRY(U3_retl_o2_and_7_plus_GS)
and %o2, 7, %o2
retl
- add %o2, GLOBAL_SPARE, %o2
+ add %o2, GLOBAL_SPARE, %o0
ENDPROC(U3_retl_o2_and_7_plus_GS)
ENTRY(U3_retl_o2_and_7_plus_GS_plus_8)
add GLOBAL_SPARE, 8, GLOBAL_SPARE
and %o2, 7, %o2
retl
- add %o2, GLOBAL_SPARE, %o2
+ add %o2, GLOBAL_SPARE, %o0
ENDPROC(U3_retl_o2_and_7_plus_GS_plus_8)
#endif
diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c
index 17bd2e1..df707a8 100644
--- a/arch/sparc/power/hibernate.c
+++ b/arch/sparc/power/hibernate.c
@@ -35,6 +35,5 @@
{
struct mm_struct *mm = current->active_mm;
- load_secondary_context(mm);
- tsb_context_switch(mm);
+ tsb_context_switch_ctx(mm, CTX_HWBITS(mm->context));
}
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index cc3bd58..9e240fc 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include "ctype.h"
+#include "string.h"
int memcmp(const void *s1, const void *s2, size_t len)
{
diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h
index 725e820..113588d 100644
--- a/arch/x86/boot/string.h
+++ b/arch/x86/boot/string.h
@@ -18,4 +18,13 @@
#define memset(d,c,l) __builtin_memset(d,c,l)
#define memcmp __builtin_memcmp
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern size_t strlen(const char *s);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strnlen(const char *s, size_t maxlen);
+extern unsigned int atou(const char *s);
+extern unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base);
+
#endif /* BOOT_STRING_H */
diff --git a/arch/x86/crypto/sha1_avx2_x86_64_asm.S b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
index 1cd792d..1eab79c 100644
--- a/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+++ b/arch/x86/crypto/sha1_avx2_x86_64_asm.S
@@ -117,11 +117,10 @@
.set T1, REG_T1
.endm
-#define K_BASE %r8
#define HASH_PTR %r9
+#define BLOCKS_CTR %r8
#define BUFFER_PTR %r10
#define BUFFER_PTR2 %r13
-#define BUFFER_END %r11
#define PRECALC_BUF %r14
#define WK_BUF %r15
@@ -205,14 +204,14 @@
* blended AVX2 and ALU instruction scheduling
* 1 vector iteration per 8 rounds
*/
- vmovdqu ((i * 2) + PRECALC_OFFSET)(BUFFER_PTR), W_TMP
+ vmovdqu (i * 2)(BUFFER_PTR), W_TMP
.elseif ((i & 7) == 1)
- vinsertf128 $1, (((i-1) * 2)+PRECALC_OFFSET)(BUFFER_PTR2),\
+ vinsertf128 $1, ((i-1) * 2)(BUFFER_PTR2),\
WY_TMP, WY_TMP
.elseif ((i & 7) == 2)
vpshufb YMM_SHUFB_BSWAP, WY_TMP, WY
.elseif ((i & 7) == 4)
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
.elseif ((i & 7) == 7)
vmovdqu WY_TMP, PRECALC_WK(i&~7)
@@ -255,7 +254,7 @@
vpxor WY, WY_TMP, WY_TMP
.elseif ((i & 7) == 7)
vpxor WY_TMP2, WY_TMP, WY
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
vmovdqu WY_TMP, PRECALC_WK(i&~7)
PRECALC_ROTATE_WY
@@ -291,7 +290,7 @@
vpsrld $30, WY, WY
vpor WY, WY_TMP, WY
.elseif ((i & 7) == 7)
- vpaddd K_XMM(K_BASE), WY, WY_TMP
+ vpaddd K_XMM + K_XMM_AR(%rip), WY, WY_TMP
vmovdqu WY_TMP, PRECALC_WK(i&~7)
PRECALC_ROTATE_WY
@@ -446,6 +445,16 @@
.endm
+/* Add constant only if (%2 > %3) condition met (uses RTA as temp)
+ * %1 + %2 >= %3 ? %4 : 0
+ */
+.macro ADD_IF_GE a, b, c, d
+ mov \a, RTA
+ add $\d, RTA
+ cmp $\c, \b
+ cmovge RTA, \a
+.endm
+
/*
* macro implements 80 rounds of SHA-1, for multiple blocks with s/w pipelining
*/
@@ -463,13 +472,16 @@
lea (2*4*80+32)(%rsp), WK_BUF
# Precalc WK for first 2 blocks
- PRECALC_OFFSET = 0
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 2, 64
.set i, 0
.rept 160
PRECALC i
.set i, i + 1
.endr
- PRECALC_OFFSET = 128
+
+ /* Go to next block if needed */
+ ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 3, 128
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
xchg WK_BUF, PRECALC_BUF
.align 32
@@ -479,8 +491,8 @@
* we use K_BASE value as a signal of a last block,
* it is set below by: cmovae BUFFER_PTR, K_BASE
*/
- cmp K_BASE, BUFFER_PTR
- jne _begin
+ test BLOCKS_CTR, BLOCKS_CTR
+ jnz _begin
.align 32
jmp _end
.align 32
@@ -512,10 +524,10 @@
.set j, j+2
.endr
- add $(2*64), BUFFER_PTR /* move to next odd-64-byte block */
- cmp BUFFER_END, BUFFER_PTR /* is current block the last one? */
- cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
-
+ /* Update Counter */
+ sub $1, BLOCKS_CTR
+ /* Move to the next block only if needed*/
+ ADD_IF_GE BUFFER_PTR, BLOCKS_CTR, 4, 128
/*
* rounds
* 60,62,64,66,68
@@ -532,8 +544,8 @@
UPDATE_HASH 12(HASH_PTR), D
UPDATE_HASH 16(HASH_PTR), E
- cmp K_BASE, BUFFER_PTR /* is current block the last one? */
- je _loop
+ test BLOCKS_CTR, BLOCKS_CTR
+ jz _loop
mov TB, B
@@ -575,10 +587,10 @@
.set j, j+2
.endr
- add $(2*64), BUFFER_PTR2 /* move to next even-64-byte block */
-
- cmp BUFFER_END, BUFFER_PTR2 /* is current block the last one */
- cmovae K_BASE, BUFFER_PTR /* signal the last iteration smartly */
+ /* update counter */
+ sub $1, BLOCKS_CTR
+ /* Move to the next block only if needed*/
+ ADD_IF_GE BUFFER_PTR2, BLOCKS_CTR, 4, 128
jmp _loop3
_loop3:
@@ -641,19 +653,12 @@
avx2_zeroupper
- lea K_XMM_AR(%rip), K_BASE
-
+ /* Setup initial values */
mov CTX, HASH_PTR
mov BUF, BUFFER_PTR
- lea 64(BUF), BUFFER_PTR2
- shl $6, CNT /* mul by 64 */
- add BUF, CNT
- add $64, CNT
- mov CNT, BUFFER_END
-
- cmp BUFFER_END, BUFFER_PTR2
- cmovae K_BASE, BUFFER_PTR2
+ mov BUF, BUFFER_PTR2
+ mov CNT, BLOCKS_CTR
xmm_mov BSWAP_SHUFB_CTL(%rip), YMM_SHUFB_BSWAP
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index f960a04..fc61739 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -201,7 +201,7 @@
static bool avx2_usable(void)
{
- if (false && avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
+ if (avx_usable() && boot_cpu_has(X86_FEATURE_AVX2)
&& boot_cpu_has(X86_FEATURE_BMI1)
&& boot_cpu_has(X86_FEATURE_BMI2))
return true;
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index ef766a3..e7b0e7f 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -1215,6 +1215,8 @@
* other IST entries.
*/
+ ASM_CLAC
+
/* Use %rdx as our temp variable throughout */
pushq %rdx
diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c
index 970c1de..4c1b7ea 100644
--- a/arch/x86/events/intel/rapl.c
+++ b/arch/x86/events/intel/rapl.c
@@ -161,7 +161,13 @@
static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
{
- return rapl_pmus->pmus[topology_logical_package_id(cpu)];
+ unsigned int pkgid = topology_logical_package_id(cpu);
+
+ /*
+ * The unsigned check also catches the '-1' return value for non
+ * existent mappings in the topology map.
+ */
+ return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL;
}
static inline u64 rapl_read_counter(struct perf_event *event)
@@ -402,6 +408,8 @@
/* must be done before validate_group */
pmu = cpu_to_rapl_pmu(event->cpu);
+ if (!pmu)
+ return -EINVAL;
event->cpu = pmu->cpu;
event->pmu_private = pmu;
event->hw.event_base = msr;
@@ -585,6 +593,19 @@
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
int target;
+ if (!pmu) {
+ pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+ if (!pmu)
+ return -ENOMEM;
+
+ raw_spin_lock_init(&pmu->lock);
+ INIT_LIST_HEAD(&pmu->active_list);
+ pmu->pmu = &rapl_pmus->pmu;
+ pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
+ rapl_hrtimer_init(pmu);
+
+ rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
+ }
/*
* Check if there is an online cpu in the package which collects rapl
* events already.
@@ -598,27 +619,6 @@
return 0;
}
-static int rapl_cpu_prepare(unsigned int cpu)
-{
- struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
-
- if (pmu)
- return 0;
-
- pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
- if (!pmu)
- return -ENOMEM;
-
- raw_spin_lock_init(&pmu->lock);
- INIT_LIST_HEAD(&pmu->active_list);
- pmu->pmu = &rapl_pmus->pmu;
- pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
- pmu->cpu = -1;
- rapl_hrtimer_init(pmu);
- rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
- return 0;
-}
-
static int rapl_check_hw_unit(bool apply_quirk)
{
u64 msr_rapl_power_unit_bits;
@@ -804,28 +804,21 @@
* Install callbacks. Core will call them for each online cpu.
*/
- ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "PERF_X86_RAPL_PREP",
- rapl_cpu_prepare, NULL);
- if (ret)
- goto out;
-
ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
"AP_PERF_X86_RAPL_ONLINE",
rapl_cpu_online, rapl_cpu_offline);
if (ret)
- goto out1;
+ goto out;
ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
if (ret)
- goto out2;
+ goto out1;
rapl_advertise();
return 0;
-out2:
- cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out1:
- cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP);
+ cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out:
pr_warn("Initialization failed (%d), disabled\n", ret);
cleanup_rapl_pmus();
@@ -836,7 +829,6 @@
static void __exit intel_rapl_exit(void)
{
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
- cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP);
perf_pmu_unregister(&rapl_pmus->pmu);
cleanup_rapl_pmus();
}
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index c152db2..b31761e 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -247,11 +247,11 @@
/*
* This is the base location for PIE (ET_DYN with INTERP) loads. On
- * 64-bit, this is raised to 4GB to leave the entire 32-bit address
+ * 64-bit, this is above 4GB to leave the entire 32-bit address
* space open for things that want to use the area for 32-bit pointers.
*/
#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
- 0x100000000UL)
+ (TASK_SIZE / 3 * 2))
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This could be done in user space,
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index d34bd37..6c50201 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -304,13 +304,13 @@
static inline void outs##bwl(int port, const void *addr, unsigned long count) \
{ \
asm volatile("rep; outs" #bwl \
- : "+S"(addr), "+c"(count) : "d"(port)); \
+ : "+S"(addr), "+c"(count) : "d"(port) : "memory"); \
} \
\
static inline void ins##bwl(int port, void *addr, unsigned long count) \
{ \
asm volatile("rep; ins" #bwl \
- : "+D"(addr), "+c"(count) : "d"(port)); \
+ : "+D"(addr), "+c"(count) : "d"(port) : "memory"); \
}
BUILDIO(b, b, char)
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 8e0a9fe..f9dd224 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -116,9 +116,7 @@
mm->context.execute_only_pkey = -1;
}
#endif
- init_new_context_ldt(tsk, mm);
-
- return 0;
+ return init_new_context_ldt(tsk, mm);
}
static inline void destroy_context(struct mm_struct *mm)
{
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 9cf697c..55ffd9d 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -152,6 +152,8 @@
if (hlist_unhashed(&n.link))
break;
+ rcu_irq_exit();
+
if (!n.halted) {
local_irq_enable();
schedule();
@@ -160,11 +162,11 @@
/*
* We cannot reschedule. So halt.
*/
- rcu_irq_exit();
native_safe_halt();
local_irq_disable();
- rcu_irq_enter();
}
+
+ rcu_irq_enter();
}
if (!n.halted)
finish_swait(&n.wq, &wait);
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 649d8f2..91af75e 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -456,7 +456,7 @@
entry->ecx &= kvm_cpuid_7_0_ecx_x86_features;
cpuid_mask(&entry->ecx, CPUID_7_ECX);
/* PKU is not yet implemented for shadow paging. */
- if (!tdp_enabled)
+ if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
entry->ecx &= ~F(PKU);
} else {
entry->ebx = 0;
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 4d2872f..a71d273 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -94,13 +94,11 @@
}
EXPORT_SYMBOL(__sync_fetch_and_or_4);
-#ifdef CONFIG_NET
/*
* Networking support
*/
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
-#endif /* CONFIG_NET */
/*
* Architecture-specific symbols
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
index 1a804a2..3c75c4e 100644
--- a/arch/xtensa/mm/cache.c
+++ b/arch/xtensa/mm/cache.c
@@ -103,6 +103,7 @@
clear_page_alias(kvaddr, paddr);
preempt_enable();
}
+EXPORT_SYMBOL(clear_user_highpage);
void copy_user_highpage(struct page *dst, struct page *src,
unsigned long vaddr, struct vm_area_struct *vma)
@@ -119,10 +120,7 @@
copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
preempt_enable();
}
-
-#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+EXPORT_SYMBOL(copy_user_highpage);
/*
* Any time the kernel writes to a user page cache page, or it is about to
@@ -176,7 +174,7 @@
/* There shouldn't be an entry in the cache for this page anymore. */
}
-
+EXPORT_SYMBOL(flush_dcache_page);
/*
* For now, flush the whole cache. FIXME??
@@ -188,6 +186,7 @@
__flush_invalidate_dcache_all();
__invalidate_icache_all();
}
+EXPORT_SYMBOL(local_flush_cache_range);
/*
* Remove any entry in the cache for this page.
@@ -207,8 +206,9 @@
__flush_invalidate_dcache_page_alias(virt, phys);
__invalidate_icache_page_alias(virt, phys);
}
+EXPORT_SYMBOL(local_flush_cache_page);
-#endif
+#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
void
update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
@@ -225,7 +225,7 @@
flush_tlb_page(vma, addr);
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
unsigned long phys = page_to_phys(page);
@@ -256,7 +256,7 @@
* flush_dcache_page() on the page.
*/
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
diff --git a/block/blk-mq-pci.c b/block/blk-mq-pci.c
index 966c216..ee9d3d9 100644
--- a/block/blk-mq-pci.c
+++ b/block/blk-mq-pci.c
@@ -36,12 +36,18 @@
for (queue = 0; queue < set->nr_hw_queues; queue++) {
mask = pci_irq_get_affinity(pdev, queue);
if (!mask)
- return -EINVAL;
+ goto fallback;
for_each_cpu(cpu, mask)
set->mq_map[cpu] = queue;
}
return 0;
+
+fallback:
+ WARN_ON_ONCE(set->nr_hw_queues > 1);
+ for_each_possible_cpu(cpu)
+ set->mq_map[cpu] = 0;
+ return 0;
}
EXPORT_SYMBOL_GPL(blk_mq_pci_map_queues);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 28556fc..45af0fe 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -86,8 +86,13 @@
}
sgl = sreq->tsg;
n = sg_nents(sgl);
- for_each_sg(sgl, sg, n, i)
- put_page(sg_page(sg));
+ for_each_sg(sgl, sg, n, i) {
+ struct page *page = sg_page(sg);
+
+ /* some SGs may not have a page mapped */
+ if (page && page_ref_count(page))
+ put_page(page);
+ }
kfree(sreq->tsg);
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index e53bef6..0375c60 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -1072,6 +1072,7 @@
if (list_empty(&ghes_sci))
unregister_acpi_hed_notifier(&ghes_notifier_sci);
mutex_unlock(&ghes_list_mutex);
+ synchronize_rcu();
break;
case ACPI_HEST_NOTIFY_NMI:
ghes_nmi_remove(ghes);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 79152db..5187469 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1728,7 +1728,7 @@
* functioning ECDT EC first in order to handle the events.
* https://bugzilla.kernel.org/show_bug.cgi?id=115021
*/
-int __init acpi_ec_ecdt_start(void)
+static int __init acpi_ec_ecdt_start(void)
{
acpi_handle handle;
@@ -1959,20 +1959,17 @@
int __init acpi_ec_init(void)
{
int result;
+ int ecdt_fail, dsdt_fail;
/* register workqueue for _Qxx evaluations */
result = acpi_ec_query_init();
if (result)
- goto err_exit;
- /* Now register the driver for the EC */
- result = acpi_bus_register_driver(&acpi_ec_driver);
- if (result)
- goto err_exit;
+ return result;
-err_exit:
- if (result)
- acpi_ec_query_exit();
- return result;
+ /* Drivers must be started after acpi_ec_query_init() */
+ ecdt_fail = acpi_ec_ecdt_start();
+ dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver);
+ return ecdt_fail && dsdt_fail ? -ENODEV : 0;
}
/* EC driver currently not unloadable */
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 219b90b..08b3ca0 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -185,7 +185,6 @@
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_ec_dsdt_probe(void);
-int acpi_ec_ecdt_start(void);
void acpi_ec_block_transactions(void);
void acpi_ec_unblock_transactions(void);
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 6d7ce6e..5e18ccf 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -45,6 +45,12 @@
struct resource *res = data;
struct resource_win win;
+ /*
+ * We might assign this to 'res' later, make sure all pointers are
+ * cleared before the resource is added to the global list
+ */
+ memset(&win, 0, sizeof(win));
+
res->flags = 0;
if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM))
return AE_OK;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index dd3786a..cf725d5 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2051,7 +2051,6 @@
acpi_gpe_apply_masked_gpes();
acpi_update_all_gpes();
- acpi_ec_ecdt_start();
acpi_scan_initialized = true;
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index 4d4cdc1..01de42c 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -44,6 +44,16 @@
Note that enabling this will break newer Android user-space.
+config ANDROID_BINDER_IPC_SELFTEST
+ bool "Android Binder IPC Driver Selftest"
+ depends on ANDROID_BINDER_IPC
+ ---help---
+ This feature allows binder selftest to run.
+
+ Binder selftest checks the allocation and free of binder buffers
+ exhaustively with combinations of various buffer sizes and
+ alignments.
+
endif # if ANDROID
endmenu
diff --git a/drivers/android/Makefile b/drivers/android/Makefile
index 4b7c726..a01254c 100644
--- a/drivers/android/Makefile
+++ b/drivers/android/Makefile
@@ -1,3 +1,4 @@
ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
+obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 88edacd..1ac8008 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2480,7 +2480,6 @@
(u64)node->ptr);
binder_node_unlock(node);
} else {
- int ret;
struct binder_ref_data dest_rdata;
binder_node_unlock(node);
@@ -3252,6 +3251,7 @@
err_dead_proc_or_thread:
return_error = BR_DEAD_REPLY;
return_error_line = __LINE__;
+ binder_dequeue_work(proc, tcomplete);
err_translate_failed:
err_bad_object_type:
err_bad_offset:
@@ -3521,11 +3521,13 @@
BUG_ON(buf_node->proc != proc);
w = binder_dequeue_work_head_ilocked(
&buf_node->async_todo);
- if (!w)
+ if (!w) {
buf_node->has_async_transaction = 0;
- else
+ } else {
binder_enqueue_work_ilocked(
- w, &thread->todo);
+ w, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ }
binder_node_inner_unlock(buf_node);
}
trace_binder_transaction_buffer_release(buffer);
@@ -3669,22 +3671,12 @@
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
- if (thread->looper &
- (BINDER_LOOPER_STATE_REGISTERED |
- BINDER_LOOPER_STATE_ENTERED))
- binder_enqueue_work(
- proc,
- &ref->death->work,
- &thread->todo);
- else {
- binder_inner_proc_lock(proc);
- binder_enqueue_work_ilocked(
- &ref->death->work,
- &proc->todo);
- binder_wakeup_proc_ilocked(
- proc);
- binder_inner_proc_unlock(proc);
- }
+
+ binder_inner_proc_lock(proc);
+ binder_enqueue_work_ilocked(
+ &ref->death->work, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ binder_inner_proc_unlock(proc);
}
} else {
if (ref->death == NULL) {
@@ -3801,12 +3793,6 @@
}
}
-static int binder_has_thread_work(struct binder_thread *thread)
-{
- return !binder_worklist_empty(thread->proc, &thread->todo) ||
- thread->looper_need_return;
-}
-
static int binder_put_node_cmd(struct binder_proc *proc,
struct binder_thread *thread,
void __user **ptrp,
@@ -4437,12 +4423,9 @@
binder_inner_proc_unlock(thread->proc);
- if (binder_has_work(thread, wait_for_proc_work))
- return POLLIN;
-
poll_wait(filp, &thread->wait, wait);
- if (binder_has_thread_work(thread))
+ if (binder_has_work(thread, wait_for_proc_work))
return POLLIN;
return 0;
@@ -4596,6 +4579,8 @@
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
+ binder_selftest_alloc(&proc->alloc);
+
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
@@ -5441,6 +5426,8 @@
count = binder_alloc_get_allocated_count(&proc->alloc);
seq_printf(m, " buffers: %d\n", count);
+ binder_alloc_print_pages(m, &proc->alloc);
+
count = 0;
binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry) {
@@ -5637,6 +5624,8 @@
struct binder_device *device;
struct hlist_node *tmp;
+ binder_alloc_shrinker_init();
+
atomic_set(&binder_transaction_log.cur, ~0U);
atomic_set(&binder_transaction_log_failed.cur, ~0U);
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index b90222a..e026894 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -27,9 +27,12 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/list_lru.h>
#include "binder_alloc.h"
#include "binder_trace.h"
+struct list_lru binder_alloc_lru;
+
static DEFINE_MUTEX(binder_alloc_mmap_lock);
enum {
@@ -48,14 +51,23 @@
pr_info(x); \
} while (0)
+static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer)
+{
+ return list_entry(buffer->entry.next, struct binder_buffer, entry);
+}
+
+static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer)
+{
+ return list_entry(buffer->entry.prev, struct binder_buffer, entry);
+}
+
static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
if (list_is_last(&buffer->entry, &alloc->buffers))
- return alloc->buffer +
- alloc->buffer_size - (void *)buffer->data;
- return (size_t)list_entry(buffer->entry.next,
- struct binder_buffer, entry) - (size_t)buffer->data;
+ return (u8 *)alloc->buffer +
+ alloc->buffer_size - (u8 *)buffer->data;
+ return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data;
}
static void binder_insert_free_buffer(struct binder_alloc *alloc,
@@ -105,9 +117,9 @@
buffer = rb_entry(parent, struct binder_buffer, rb_node);
BUG_ON(buffer->free);
- if (new_buffer < buffer)
+ if (new_buffer->data < buffer->data)
p = &parent->rb_left;
- else if (new_buffer > buffer)
+ else if (new_buffer->data > buffer->data)
p = &parent->rb_right;
else
BUG();
@@ -122,18 +134,17 @@
{
struct rb_node *n = alloc->allocated_buffers.rb_node;
struct binder_buffer *buffer;
- struct binder_buffer *kern_ptr;
+ void *kern_ptr;
- kern_ptr = (struct binder_buffer *)(user_ptr - alloc->user_buffer_offset
- - offsetof(struct binder_buffer, data));
+ kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset);
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(buffer->free);
- if (kern_ptr < buffer)
+ if (kern_ptr < buffer->data)
n = n->rb_left;
- else if (kern_ptr > buffer)
+ else if (kern_ptr > buffer->data)
n = n->rb_right;
else {
/*
@@ -180,8 +191,9 @@
{
void *page_addr;
unsigned long user_page_addr;
- struct page **page;
- struct mm_struct *mm;
+ struct binder_lru_page *page;
+ struct mm_struct *mm = NULL;
+ bool need_mm = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: %s pages %pK-%pK\n", alloc->pid,
@@ -192,9 +204,18 @@
trace_binder_update_page_range(alloc, allocate, start, end);
- if (vma)
- mm = NULL;
- else
+ if (allocate == 0)
+ goto free_range;
+
+ for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
+ if (!page->page_ptr) {
+ need_mm = true;
+ break;
+ }
+ }
+
+ if (!vma && need_mm)
mm = get_task_mm(alloc->tsk);
if (mm) {
@@ -207,10 +228,7 @@
}
}
- if (allocate == 0)
- goto free_range;
-
- if (vma == NULL) {
+ if (!vma && need_mm) {
pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
alloc->pid);
goto err_no_vma;
@@ -218,18 +236,40 @@
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
int ret;
+ bool on_lru;
+ size_t index;
- page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
+ index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ page = &alloc->pages[index];
- BUG_ON(*page);
- *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
- if (*page == NULL) {
+ if (page->page_ptr) {
+ trace_binder_alloc_lru_start(alloc, index);
+
+ on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
+ WARN_ON(!on_lru);
+
+ trace_binder_alloc_lru_end(alloc, index);
+ continue;
+ }
+
+ if (WARN_ON(!vma))
+ goto err_page_ptr_cleared;
+
+ trace_binder_alloc_page_start(alloc, index);
+ page->page_ptr = alloc_page(GFP_KERNEL |
+ __GFP_HIGHMEM |
+ __GFP_ZERO);
+ if (!page->page_ptr) {
pr_err("%d: binder_alloc_buf failed for page at %pK\n",
alloc->pid, page_addr);
goto err_alloc_page_failed;
}
+ page->alloc = alloc;
+ INIT_LIST_HEAD(&page->lru);
+
ret = map_kernel_range_noflush((unsigned long)page_addr,
- PAGE_SIZE, PAGE_KERNEL, page);
+ PAGE_SIZE, PAGE_KERNEL,
+ &page->page_ptr);
flush_cache_vmap((unsigned long)page_addr,
(unsigned long)page_addr + PAGE_SIZE);
if (ret != 1) {
@@ -239,12 +279,14 @@
}
user_page_addr =
(uintptr_t)page_addr + alloc->user_buffer_offset;
- ret = vm_insert_page(vma, user_page_addr, page[0]);
+ ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
if (ret) {
pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
alloc->pid, user_page_addr);
goto err_vm_insert_page_failed;
}
+
+ trace_binder_alloc_page_end(alloc, index);
/* vm_insert_page does not seem to increment the refcount */
}
if (mm) {
@@ -256,16 +298,27 @@
free_range:
for (page_addr = end - PAGE_SIZE; page_addr >= start;
page_addr -= PAGE_SIZE) {
- page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
- if (vma)
- zap_page_range(vma, (uintptr_t)page_addr +
- alloc->user_buffer_offset, PAGE_SIZE, NULL);
+ bool ret;
+ size_t index;
+
+ index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ page = &alloc->pages[index];
+
+ trace_binder_free_lru_start(alloc, index);
+
+ ret = list_lru_add(&binder_alloc_lru, &page->lru);
+ WARN_ON(!ret);
+
+ trace_binder_free_lru_end(alloc, index);
+ continue;
+
err_vm_insert_page_failed:
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
err_map_kernel_failed:
- __free_page(*page);
- *page = NULL;
+ __free_page(page->page_ptr);
+ page->page_ptr = NULL;
err_alloc_page_failed:
+err_page_ptr_cleared:
;
}
err_no_vma:
@@ -321,6 +374,9 @@
return ERR_PTR(-ENOSPC);
}
+ /* Pad 0-size buffers so they get assigned unique addresses */
+ size = max(size, sizeof(void *));
+
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
@@ -380,14 +436,9 @@
has_page_addr =
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK);
- if (n == NULL) {
- if (size + sizeof(struct binder_buffer) + 4 >= buffer_size)
- buffer_size = size; /* no room for other buffers */
- else
- buffer_size = size + sizeof(struct binder_buffer);
- }
+ WARN_ON(n && buffer_size != size);
end_page_addr =
- (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
if (end_page_addr > has_page_addr)
end_page_addr = has_page_addr;
ret = binder_update_page_range(alloc, 1,
@@ -395,17 +446,25 @@
if (ret)
return ERR_PTR(ret);
- rb_erase(best_fit, &alloc->free_buffers);
- buffer->free = 0;
- buffer->free_in_progress = 0;
- binder_insert_allocated_buffer_locked(alloc, buffer);
if (buffer_size != size) {
- struct binder_buffer *new_buffer = (void *)buffer->data + size;
+ struct binder_buffer *new_buffer;
+ new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!new_buffer) {
+ pr_err("%s: %d failed to alloc new buffer struct\n",
+ __func__, alloc->pid);
+ goto err_alloc_buf_struct_failed;
+ }
+ new_buffer->data = (u8 *)buffer->data + size;
list_add(&new_buffer->entry, &buffer->entry);
new_buffer->free = 1;
binder_insert_free_buffer(alloc, new_buffer);
}
+
+ rb_erase(best_fit, &alloc->free_buffers);
+ buffer->free = 0;
+ buffer->free_in_progress = 0;
+ binder_insert_allocated_buffer_locked(alloc, buffer);
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd got %pK\n",
alloc->pid, size, buffer);
@@ -420,6 +479,12 @@
alloc->pid, size, alloc->free_async_space);
}
return buffer;
+
+err_alloc_buf_struct_failed:
+ binder_update_page_range(alloc, 0,
+ (void *)PAGE_ALIGN((uintptr_t)buffer->data),
+ end_page_addr, NULL);
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -454,57 +519,59 @@
static void *buffer_start_page(struct binder_buffer *buffer)
{
- return (void *)((uintptr_t)buffer & PAGE_MASK);
+ return (void *)((uintptr_t)buffer->data & PAGE_MASK);
}
-static void *buffer_end_page(struct binder_buffer *buffer)
+static void *prev_buffer_end_page(struct binder_buffer *buffer)
{
- return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK);
+ return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK);
}
static void binder_delete_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
struct binder_buffer *prev, *next = NULL;
- int free_page_end = 1;
- int free_page_start = 1;
-
+ bool to_free = true;
BUG_ON(alloc->buffers.next == &buffer->entry);
- prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
+ prev = binder_buffer_prev(buffer);
BUG_ON(!prev->free);
- if (buffer_end_page(prev) == buffer_start_page(buffer)) {
- free_page_start = 0;
- if (buffer_end_page(prev) == buffer_end_page(buffer))
- free_page_end = 0;
+ if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) {
+ to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid, buffer, prev);
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid, buffer->data, prev->data);
}
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
- next = list_entry(buffer->entry.next,
- struct binder_buffer, entry);
- if (buffer_start_page(next) == buffer_end_page(buffer)) {
- free_page_end = 0;
- if (buffer_start_page(next) ==
- buffer_start_page(buffer))
- free_page_start = 0;
+ next = binder_buffer_next(buffer);
+ if (buffer_start_page(next) == buffer_start_page(buffer)) {
+ to_free = false;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid, buffer, prev);
+ "%d: merge free, buffer %pK share page with %pK\n",
+ alloc->pid,
+ buffer->data,
+ next->data);
}
}
- list_del(&buffer->entry);
- if (free_page_start || free_page_end) {
+
+ if (PAGE_ALIGNED(buffer->data)) {
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
- alloc->pid, buffer, free_page_start ? "" : " end",
- free_page_end ? "" : " start", prev, next);
- binder_update_page_range(alloc, 0, free_page_start ?
- buffer_start_page(buffer) : buffer_end_page(buffer),
- (free_page_end ? buffer_end_page(buffer) :
- buffer_start_page(buffer)) + PAGE_SIZE, NULL);
+ "%d: merge free, buffer start %pK is page aligned\n",
+ alloc->pid, buffer->data);
+ to_free = false;
}
+
+ if (to_free) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: merge free, buffer %pK do not share page with %pK or %pK\n",
+ alloc->pid, buffer->data,
+ prev->data, next->data);
+ binder_update_page_range(alloc, 0, buffer_start_page(buffer),
+ buffer_start_page(buffer) + PAGE_SIZE,
+ NULL);
+ }
+ list_del(&buffer->entry);
+ kfree(buffer);
}
static void binder_free_buf_locked(struct binder_alloc *alloc,
@@ -525,8 +592,8 @@
BUG_ON(buffer->free);
BUG_ON(size > buffer_size);
BUG_ON(buffer->transaction != NULL);
- BUG_ON((void *)buffer < alloc->buffer);
- BUG_ON((void *)buffer > alloc->buffer + alloc->buffer_size);
+ BUG_ON(buffer->data < alloc->buffer);
+ BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size);
if (buffer->async_transaction) {
alloc->free_async_space += size + sizeof(struct binder_buffer);
@@ -544,8 +611,7 @@
rb_erase(&buffer->rb_node, &alloc->allocated_buffers);
buffer->free = 1;
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
- struct binder_buffer *next = list_entry(buffer->entry.next,
- struct binder_buffer, entry);
+ struct binder_buffer *next = binder_buffer_next(buffer);
if (next->free) {
rb_erase(&next->rb_node, &alloc->free_buffers);
@@ -553,8 +619,7 @@
}
}
if (alloc->buffers.next != &buffer->entry) {
- struct binder_buffer *prev = list_entry(buffer->entry.prev,
- struct binder_buffer, entry);
+ struct binder_buffer *prev = binder_buffer_prev(buffer);
if (prev->free) {
binder_delete_free_buffer(alloc, buffer);
@@ -640,14 +705,14 @@
}
alloc->buffer_size = vma->vm_end - vma->vm_start;
- if (binder_update_page_range(alloc, 1, alloc->buffer,
- alloc->buffer + PAGE_SIZE, vma)) {
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
ret = -ENOMEM;
- failure_string = "alloc small buf";
- goto err_alloc_small_buf_failed;
+ failure_string = "alloc buffer struct";
+ goto err_alloc_buf_struct_failed;
}
- buffer = alloc->buffer;
- INIT_LIST_HEAD(&alloc->buffers);
+
+ buffer->data = alloc->buffer;
list_add(&buffer->entry, &alloc->buffers);
buffer->free = 1;
binder_insert_free_buffer(alloc, buffer);
@@ -658,7 +723,7 @@
return 0;
-err_alloc_small_buf_failed:
+err_alloc_buf_struct_failed:
kfree(alloc->pages);
alloc->pages = NULL;
err_alloc_pages_failed:
@@ -678,14 +743,13 @@
{
struct rb_node *n;
int buffers, page_count;
+ struct binder_buffer *buffer;
BUG_ON(alloc->vma);
buffers = 0;
mutex_lock(&alloc->mutex);
while ((n = rb_first(&alloc->allocated_buffers))) {
- struct binder_buffer *buffer;
-
buffer = rb_entry(n, struct binder_buffer, rb_node);
/* Transaction should already have been freed */
@@ -695,22 +759,36 @@
buffers++;
}
+ while (!list_empty(&alloc->buffers)) {
+ buffer = list_first_entry(&alloc->buffers,
+ struct binder_buffer, entry);
+ WARN_ON(!buffer->free);
+
+ list_del(&buffer->entry);
+ WARN_ON_ONCE(!list_empty(&alloc->buffers));
+ kfree(buffer);
+ }
+
page_count = 0;
if (alloc->pages) {
int i;
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
void *page_addr;
+ bool on_lru;
- if (!alloc->pages[i])
+ if (!alloc->pages[i].page_ptr)
continue;
+ on_lru = list_lru_del(&binder_alloc_lru,
+ &alloc->pages[i].lru);
page_addr = alloc->buffer + i * PAGE_SIZE;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%s: %d: page %d at %pK not freed\n",
- __func__, alloc->pid, i, page_addr);
+ "%s: %d: page %d at %pK %s\n",
+ __func__, alloc->pid, i, page_addr,
+ on_lru ? "on lru" : "active");
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
- __free_page(alloc->pages[i]);
+ __free_page(alloc->pages[i].page_ptr);
page_count++;
}
kfree(alloc->pages);
@@ -754,6 +832,34 @@
}
/**
+ * binder_alloc_print_pages() - print page usage
+ * @m: seq_file for output via seq_printf()
+ * @alloc: binder_alloc for this proc
+ */
+void binder_alloc_print_pages(struct seq_file *m,
+ struct binder_alloc *alloc)
+{
+ struct binder_lru_page *page;
+ int i;
+ int active = 0;
+ int lru = 0;
+ int free = 0;
+
+ mutex_lock(&alloc->mutex);
+ for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+ page = &alloc->pages[i];
+ if (!page->page_ptr)
+ free++;
+ else if (list_empty(&page->lru))
+ active++;
+ else
+ lru++;
+ }
+ mutex_unlock(&alloc->mutex);
+ seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
+}
+
+/**
* binder_alloc_get_allocated_count() - return count of buffers
* @alloc: binder_alloc for this proc
*
@@ -787,6 +893,108 @@
}
/**
+ * binder_alloc_free_page() - shrinker callback to free pages
+ * @item: item to free
+ * @lock: lock protecting the item
+ * @cb_arg: callback argument
+ *
+ * Called from list_lru_walk() in binder_shrink_scan() to free
+ * up pages when the system is under memory pressure.
+ */
+enum lru_status binder_alloc_free_page(struct list_head *item,
+ struct list_lru_one *lru,
+ spinlock_t *lock,
+ void *cb_arg)
+{
+ struct mm_struct *mm = NULL;
+ struct binder_lru_page *page = container_of(item,
+ struct binder_lru_page,
+ lru);
+ struct binder_alloc *alloc;
+ uintptr_t page_addr;
+ size_t index;
+ struct vm_area_struct *vma;
+
+ alloc = page->alloc;
+ if (!mutex_trylock(&alloc->mutex))
+ goto err_get_alloc_mutex_failed;
+
+ if (!page->page_ptr)
+ goto err_page_already_freed;
+
+ index = page - alloc->pages;
+ page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
+ vma = alloc->vma;
+ if (vma) {
+ mm = get_task_mm(alloc->tsk);
+ if (!mm)
+ goto err_get_task_mm_failed;
+ if (!down_write_trylock(&mm->mmap_sem))
+ goto err_down_write_mmap_sem_failed;
+ }
+
+ list_lru_isolate(lru, item);
+ spin_unlock(lock);
+
+ if (vma) {
+ trace_binder_unmap_user_start(alloc, index);
+
+ zap_page_range(vma,
+ page_addr +
+ alloc->user_buffer_offset,
+ PAGE_SIZE, NULL);
+
+ trace_binder_unmap_user_end(alloc, index);
+
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ }
+
+ trace_binder_unmap_kernel_start(alloc, index);
+
+ unmap_kernel_range(page_addr, PAGE_SIZE);
+ __free_page(page->page_ptr);
+ page->page_ptr = NULL;
+
+ trace_binder_unmap_kernel_end(alloc, index);
+
+ spin_lock(lock);
+ mutex_unlock(&alloc->mutex);
+ return LRU_REMOVED_RETRY;
+
+err_down_write_mmap_sem_failed:
+ mmput_async(mm);
+err_get_task_mm_failed:
+err_page_already_freed:
+ mutex_unlock(&alloc->mutex);
+err_get_alloc_mutex_failed:
+ return LRU_SKIP;
+}
+
+static unsigned long
+binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+ unsigned long ret = list_lru_count(&binder_alloc_lru);
+ return ret;
+}
+
+static unsigned long
+binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+{
+ unsigned long ret;
+
+ ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ NULL, sc->nr_to_scan);
+ return ret;
+}
+
+struct shrinker binder_shrinker = {
+ .count_objects = binder_shrink_count,
+ .scan_objects = binder_shrink_scan,
+ .seeks = DEFAULT_SEEKS,
+};
+
+/**
* binder_alloc_init() - called by binder_open() for per-proc initialization
* @alloc: binder_alloc for this proc
*
@@ -798,5 +1006,11 @@
alloc->tsk = current->group_leader;
alloc->pid = current->group_leader->pid;
mutex_init(&alloc->mutex);
+ INIT_LIST_HEAD(&alloc->buffers);
}
+void binder_alloc_shrinker_init(void)
+{
+ list_lru_init(&binder_alloc_lru);
+ register_shrinker(&binder_shrinker);
+}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 088e4ff..a3a3602 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -21,7 +21,9 @@
#include <linux/rtmutex.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/list_lru.h>
+extern struct list_lru binder_alloc_lru;
struct binder_transaction;
/**
@@ -57,7 +59,19 @@
size_t data_size;
size_t offsets_size;
size_t extra_buffers_size;
- uint8_t data[0];
+ void *data;
+};
+
+/**
+ * struct binder_lru_page - page object used for binder shrinker
+ * @page_ptr: pointer to physical page in mmap'd space
+ * @lru: entry in binder_alloc_lru
+ * @alloc: binder_alloc for a proc
+ */
+struct binder_lru_page {
+ struct list_head lru;
+ struct page *page_ptr;
+ struct binder_alloc *alloc;
};
/**
@@ -75,8 +89,7 @@
* @allocated_buffers: rb tree of allocated buffers sorted by address
* @free_async_space: VA space available for async buffers. This is
* initialized at mmap time to 1/2 the full VA space
- * @pages: array of physical page addresses for each
- * page of mmap'd space
+ * @pages: array of binder_lru_page
* @buffer_size: size of address space specified via mmap
* @pid: pid for associated binder_proc (invariant after init)
*
@@ -96,18 +109,27 @@
struct rb_root free_buffers;
struct rb_root allocated_buffers;
size_t free_async_space;
- struct page **pages;
+ struct binder_lru_page *pages;
size_t buffer_size;
uint32_t buffer_free;
int pid;
};
+#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
+void binder_selftest_alloc(struct binder_alloc *alloc);
+#else
+static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
+#endif
+enum lru_status binder_alloc_free_page(struct list_head *item,
+ struct list_lru_one *lru,
+ spinlock_t *lock, void *cb_arg);
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async);
extern void binder_alloc_init(struct binder_alloc *alloc);
+void binder_alloc_shrinker_init(void);
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
extern struct binder_buffer *
binder_alloc_prepare_to_free(struct binder_alloc *alloc,
@@ -120,6 +142,8 @@
extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
extern void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc);
+void binder_alloc_print_pages(struct seq_file *m,
+ struct binder_alloc *alloc);
/**
* binder_alloc_get_free_async_space() - get free space available for async
diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c
new file mode 100644
index 0000000..8bd7bce
--- /dev/null
+++ b/drivers/android/binder_alloc_selftest.c
@@ -0,0 +1,310 @@
+/* binder_alloc_selftest.c
+ *
+ * Android IPC Subsystem
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mm_types.h>
+#include <linux/err.h>
+#include "binder_alloc.h"
+
+#define BUFFER_NUM 5
+#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
+
+static bool binder_selftest_run = true;
+static int binder_selftest_failures;
+static DEFINE_MUTEX(binder_selftest_lock);
+
+/**
+ * enum buf_end_align_type - Page alignment of a buffer
+ * end with regard to the end of the previous buffer.
+ *
+ * In the pictures below, buf2 refers to the buffer we
+ * are aligning. buf1 refers to previous buffer by addr.
+ * Symbol [ means the start of a buffer, ] means the end
+ * of a buffer, and | means page boundaries.
+ */
+enum buf_end_align_type {
+ /**
+ * @SAME_PAGE_UNALIGNED: The end of this buffer is on
+ * the same page as the end of the previous buffer and
+ * is not page aligned. Examples:
+ * buf1 ][ buf2 ][ ...
+ * buf1 ]|[ buf2 ][ ...
+ */
+ SAME_PAGE_UNALIGNED = 0,
+ /**
+ * @SAME_PAGE_ALIGNED: When the end of the previous buffer
+ * is not page aligned, the end of this buffer is on the
+ * same page as the end of the previous buffer and is page
+ * aligned. When the previous buffer is page aligned, the
+ * end of this buffer is aligned to the next page boundary.
+ * Examples:
+ * buf1 ][ buf2 ]| ...
+ * buf1 ]|[ buf2 ]| ...
+ */
+ SAME_PAGE_ALIGNED,
+ /**
+ * @NEXT_PAGE_UNALIGNED: The end of this buffer is on
+ * the page next to the end of the previous buffer and
+ * is not page aligned. Examples:
+ * buf1 ][ buf2 | buf2 ][ ...
+ * buf1 ]|[ buf2 | buf2 ][ ...
+ */
+ NEXT_PAGE_UNALIGNED,
+ /**
+ * @NEXT_PAGE_ALIGNED: The end of this buffer is on
+ * the page next to the end of the previous buffer and
+ * is page aligned. Examples:
+ * buf1 ][ buf2 | buf2 ]| ...
+ * buf1 ]|[ buf2 | buf2 ]| ...
+ */
+ NEXT_PAGE_ALIGNED,
+ /**
+ * @NEXT_NEXT_UNALIGNED: The end of this buffer is on
+ * the page that follows the page after the end of the
+ * previous buffer and is not page aligned. Examples:
+ * buf1 ][ buf2 | buf2 | buf2 ][ ...
+ * buf1 ]|[ buf2 | buf2 | buf2 ][ ...
+ */
+ NEXT_NEXT_UNALIGNED,
+ LOOP_END,
+};
+
+static void pr_err_size_seq(size_t *sizes, int *seq)
+{
+ int i;
+
+ pr_err("alloc sizes: ");
+ for (i = 0; i < BUFFER_NUM; i++)
+ pr_cont("[%zu]", sizes[i]);
+ pr_cont("\n");
+ pr_err("free seq: ");
+ for (i = 0; i < BUFFER_NUM; i++)
+ pr_cont("[%d]", seq[i]);
+ pr_cont("\n");
+}
+
+static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ size_t size)
+{
+ void *page_addr, *end;
+ int page_index;
+
+ end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size);
+ page_addr = buffer->data;
+ for (; page_addr < end; page_addr += PAGE_SIZE) {
+ page_index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ if (!alloc->pages[page_index].page_ptr ||
+ !list_empty(&alloc->pages[page_index].lru)) {
+ pr_err("expect alloc but is %s at page index %d\n",
+ alloc->pages[page_index].page_ptr ?
+ "lru" : "free", page_index);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffers[],
+ size_t *sizes, int *seq)
+{
+ int i;
+
+ for (i = 0; i < BUFFER_NUM; i++) {
+ buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
+ if (IS_ERR(buffers[i]) ||
+ !check_buffer_pages_allocated(alloc, buffers[i],
+ sizes[i])) {
+ pr_err_size_seq(sizes, seq);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_free_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffers[],
+ size_t *sizes, int *seq, size_t end)
+{
+ int i;
+
+ for (i = 0; i < BUFFER_NUM; i++)
+ binder_alloc_free_buf(alloc, buffers[seq[i]]);
+
+ for (i = 0; i < end / PAGE_SIZE; i++) {
+ /**
+ * Error message on a free page can be false positive
+ * if binder shrinker ran during binder_alloc_free_buf
+ * calls above.
+ */
+ if (list_empty(&alloc->pages[i].lru)) {
+ pr_err_size_seq(sizes, seq);
+ pr_err("expect lru but is %s at page index %d\n",
+ alloc->pages[i].page_ptr ? "alloc" : "free", i);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_free_page(struct binder_alloc *alloc)
+{
+ int i;
+ unsigned long count;
+
+ while ((count = list_lru_count(&binder_alloc_lru))) {
+ list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ NULL, count);
+ }
+
+ for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
+ if (alloc->pages[i].page_ptr) {
+ pr_err("expect free but is %s at page index %d\n",
+ list_empty(&alloc->pages[i].lru) ?
+ "alloc" : "lru", i);
+ binder_selftest_failures++;
+ }
+ }
+}
+
+static void binder_selftest_alloc_free(struct binder_alloc *alloc,
+ size_t *sizes, int *seq, size_t end)
+{
+ struct binder_buffer *buffers[BUFFER_NUM];
+
+ binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
+ binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
+
+ /* Allocate from lru. */
+ binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
+ if (list_lru_count(&binder_alloc_lru))
+ pr_err("lru list should be empty but is not\n");
+
+ binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
+ binder_selftest_free_page(alloc);
+}
+
+static bool is_dup(int *seq, int index, int val)
+{
+ int i;
+
+ for (i = 0; i < index; i++) {
+ if (seq[i] == val)
+ return true;
+ }
+ return false;
+}
+
+/* Generate BUFFER_NUM factorial free orders. */
+static void binder_selftest_free_seq(struct binder_alloc *alloc,
+ size_t *sizes, int *seq,
+ int index, size_t end)
+{
+ int i;
+
+ if (index == BUFFER_NUM) {
+ binder_selftest_alloc_free(alloc, sizes, seq, end);
+ return;
+ }
+ for (i = 0; i < BUFFER_NUM; i++) {
+ if (is_dup(seq, index, i))
+ continue;
+ seq[index] = i;
+ binder_selftest_free_seq(alloc, sizes, seq, index + 1, end);
+ }
+}
+
+static void binder_selftest_alloc_size(struct binder_alloc *alloc,
+ size_t *end_offset)
+{
+ int i;
+ int seq[BUFFER_NUM] = {0};
+ size_t front_sizes[BUFFER_NUM];
+ size_t back_sizes[BUFFER_NUM];
+ size_t last_offset, offset = 0;
+
+ for (i = 0; i < BUFFER_NUM; i++) {
+ last_offset = offset;
+ offset = end_offset[i];
+ front_sizes[i] = offset - last_offset;
+ back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
+ }
+ /*
+ * Buffers share the first or last few pages.
+ * Only BUFFER_NUM - 1 buffer sizes are adjustable since
+ * we need one giant buffer before getting to the last page.
+ */
+ back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
+ binder_selftest_free_seq(alloc, front_sizes, seq, 0,
+ end_offset[BUFFER_NUM - 1]);
+ binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size);
+}
+
+static void binder_selftest_alloc_offset(struct binder_alloc *alloc,
+ size_t *end_offset, int index)
+{
+ int align;
+ size_t end, prev;
+
+ if (index == BUFFER_NUM) {
+ binder_selftest_alloc_size(alloc, end_offset);
+ return;
+ }
+ prev = index == 0 ? 0 : end_offset[index - 1];
+ end = prev;
+
+ BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
+
+ for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
+ if (align % 2)
+ end = ALIGN(end, PAGE_SIZE);
+ else
+ end += BUFFER_MIN_SIZE;
+ end_offset[index] = end;
+ binder_selftest_alloc_offset(alloc, end_offset, index + 1);
+ }
+}
+
+/**
+ * binder_selftest_alloc() - Test alloc and free of buffer pages.
+ * @alloc: Pointer to alloc struct.
+ *
+ * Allocate BUFFER_NUM buffers to cover all page alignment cases,
+ * then free them in all orders possible. Check that pages are
+ * correctly allocated, put onto lru when buffers are freed, and
+ * are freed when binder_alloc_free_page is called.
+ */
+void binder_selftest_alloc(struct binder_alloc *alloc)
+{
+ size_t end_offset[BUFFER_NUM];
+
+ if (!binder_selftest_run)
+ return;
+ mutex_lock(&binder_selftest_lock);
+ if (!binder_selftest_run || !alloc->vma)
+ goto done;
+ pr_info("STARTED\n");
+ binder_selftest_alloc_offset(alloc, end_offset, 0);
+ binder_selftest_run = false;
+ if (binder_selftest_failures > 0)
+ pr_info("%d tests FAILED\n", binder_selftest_failures);
+ else
+ pr_info("PASSED\n");
+
+done:
+ mutex_unlock(&binder_selftest_lock);
+}
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
index 7967db1..76e3b9c 100644
--- a/drivers/android/binder_trace.h
+++ b/drivers/android/binder_trace.h
@@ -291,6 +291,61 @@
__entry->offset, __entry->size)
);
+DECLARE_EVENT_CLASS(binder_lru_page_class,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index),
+ TP_STRUCT__entry(
+ __field(int, proc)
+ __field(size_t, page_index)
+ ),
+ TP_fast_assign(
+ __entry->proc = alloc->pid;
+ __entry->page_index = page_index;
+ ),
+ TP_printk("proc=%d page_index=%zu",
+ __entry->proc, __entry->page_index)
+);
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
+DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end,
+ TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
+ TP_ARGS(alloc, page_index));
+
TRACE_EVENT(binder_command,
TP_PROTO(uint32_t cmd),
TP_ARGS(cmd),
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 8e575fb..e3e10e8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2971,10 +2971,12 @@
static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{
if (!sata_pmp_attached(ap)) {
- if (likely(devno < ata_link_max_devices(&ap->link)))
+ if (likely(devno >= 0 &&
+ devno < ata_link_max_devices(&ap->link)))
return &ap->link.device[devno];
} else {
- if (likely(devno < ap->nr_pmp_links))
+ if (likely(devno >= 0 &&
+ devno < ap->nr_pmp_links))
return &ap->pmp_link[devno].device[0];
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 35ab4d5..ac43d6f 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1116,13 +1116,7 @@
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
- if ((dev->pm_domain) || (dev->type && dev->type->pm)
- || (dev->class && (dev->class->pm || dev->class->resume))
- || (dev->bus && (dev->bus->pm || dev->bus->resume)) ||
- (dev->driver && dev->driver->pm)) {
- device_pm_add(dev);
- }
-
+ device_pm_add(dev);
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 55687b8..e17ad53 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -208,6 +208,59 @@
#endif
+static ssize_t show_sched_load_boost(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t rc;
+ unsigned int boost;
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = cpu->dev.id;
+
+ boost = per_cpu(sched_load_boost, cpuid);
+ rc = snprintf(buf, PAGE_SIZE-2, "%d\n", boost);
+
+ return rc;
+}
+
+static ssize_t __ref store_sched_load_boost(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int boost;
+ struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = cpu->dev.id;
+
+ err = kstrtoint(strstrip((char *)buf), 0, &boost);
+ if (err)
+ return err;
+
+ /*
+ * -100 is low enough to cancel out CPU's load and make it near zro.
+ * 1000 is close to the maximum value that cpu_util_freq_{walt,pelt}
+ * can take without overflow.
+ */
+ if (boost < -100 || boost > 1000)
+ return -EINVAL;
+
+ per_cpu(sched_load_boost, cpuid) = boost;
+
+ return count;
+}
+
+static DEVICE_ATTR(sched_load_boost, 0644,
+ show_sched_load_boost,
+ store_sched_load_boost);
+
+static struct attribute *sched_cpu_attrs[] = {
+ &dev_attr_sched_load_boost.attr,
+ NULL
+};
+
+static struct attribute_group sched_cpu_attr_group = {
+ .attrs = sched_cpu_attrs,
+};
+
static const struct attribute_group *common_cpu_attr_groups[] = {
#ifdef CONFIG_KEXEC
&crash_note_cpu_attr_group,
@@ -215,6 +268,7 @@
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
+ &sched_cpu_attr_group,
NULL
};
@@ -225,6 +279,7 @@
#ifdef CONFIG_HOTPLUG_CPU
&cpu_isolated_attr_group,
#endif
+ &sched_cpu_attr_group,
NULL
};
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index c1e56c3..4f99101 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -162,12 +162,6 @@
pr_debug("PM: Moving %s:%s before %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert before devb. */
list_move_tail(&deva->power.entry, &devb->power.entry);
}
@@ -182,12 +176,6 @@
pr_debug("PM: Moving %s:%s after %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert after devb. */
list_move(&deva->power.entry, &devb->power.entry);
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 43a36d6..06f6668 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -182,11 +182,12 @@
return 0;
}
-static inline struct fwnode_handle *dev_fwnode(struct device *dev)
+struct fwnode_handle *dev_fwnode(struct device *dev)
{
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
&dev->of_node->fwnode : dev->fwnode;
}
+EXPORT_SYMBOL_GPL(dev_fwnode);
/**
* device_property_present - check if a property of a device is present
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index fc814a3..45fc564 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -32,3 +32,12 @@
config REGMAP_SWR
tristate
+
+config REGMAP_ALLOW_WRITE_DEBUGFS
+ depends on REGMAP && DEBUG_FS
+ bool "Allow REGMAP debugfs write"
+ default n
+ help
+ Say 'y' here to allow the regmap debugfs write. Regmap debugfs write
+ could be risky when accessing some essential hardwares, so it is not
+ recommended to enable this option on any production device.
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index b4c5224..1559070 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -269,8 +269,7 @@
count, ppos);
}
-#define REGMAP_ALLOW_WRITE_DEBUGFS
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous especially when we have clients such as
* PMICs, therefore don't provide any real compile time configuration option
@@ -340,7 +339,7 @@
new_count, ppos);
}
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
static ssize_t regmap_data_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -633,7 +632,7 @@
if (map->max_register || regmap_readable(map, 0)) {
umode_t registers_mode;
-#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
registers_mode = 0600;
#else
registers_mode = 0400;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c9441f9..98b767d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -929,6 +929,7 @@
return -ENOMEM;
for (i = 0; i < nbds_max; i++) {
+ struct request_queue *q;
struct gendisk *disk = alloc_disk(1 << part_shift);
if (!disk)
goto out;
@@ -954,12 +955,13 @@
* every gendisk to have its very own request_queue struct.
* These structs are big so we dynamically allocate them.
*/
- disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set);
- if (!disk->queue) {
+ q = blk_mq_init_queue(&nbd_dev[i].tag_set);
+ if (IS_ERR(q)) {
blk_mq_free_tag_set(&nbd_dev[i].tag_set);
put_disk(disk);
goto out;
}
+ disk->queue = q;
/*
* Tell the block layer that we are not a rotational device
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 3c3b8f6..10332c2 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -630,11 +630,12 @@
if (err)
goto out_put_disk;
- q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
+ q = blk_mq_init_queue(&vblk->tag_set);
if (IS_ERR(q)) {
err = -ENOMEM;
goto out_free_tags;
}
+ vblk->disk->queue = q;
q->queuedata = vblk;
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 9908597..f11d62d 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -2112,9 +2112,9 @@
/*
* Get the bios in the request so we can re-queue them.
*/
- if (req_op(shadow[i].request) == REQ_OP_FLUSH ||
- req_op(shadow[i].request) == REQ_OP_DISCARD ||
- req_op(shadow[i].request) == REQ_OP_SECURE_ERASE ||
+ if (req_op(shadow[j].request) == REQ_OP_FLUSH ||
+ req_op(shadow[j].request) == REQ_OP_DISCARD ||
+ req_op(shadow[j].request) == REQ_OP_SECURE_ERASE ||
shadow[j].request->cmd_flags & REQ_FUA) {
/*
* Flush operations don't contain bios, so
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 636c982..874639f 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -60,6 +60,7 @@
#define NUM_SESSIONS 9 /*8 compute, 1 cpz*/
#define M_FDLIST (16)
#define M_CRCLIST (64)
+#define SESSION_ID_INDEX (30)
#define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
@@ -282,6 +283,7 @@
struct fastrpc_session_ctx *secsctx;
uint32_t mode;
uint32_t profile;
+ int sessionid;
int tgid;
int cid;
int ssrcount;
@@ -860,7 +862,7 @@
}
ctx->retval = -1;
ctx->pid = current->pid;
- ctx->tgid = current->tgid;
+ ctx->tgid = fl->tgid;
init_completion(&ctx->work);
spin_lock(&fl->hlock);
@@ -1351,8 +1353,10 @@
VERIFY(err, 0 != channel_ctx->chan);
if (err)
goto bail;
- msg->pid = current->tgid;
+ msg->pid = fl->tgid;
msg->tid = current->pid;
+ if (fl->sessionid)
+ msg->tid |= (1 << SESSION_ID_INDEX);
if (kernel)
msg->pid = 0;
msg->invoke.header.ctx = ptr_to_uint64(ctx) | fl->pd;
@@ -1407,6 +1411,7 @@
if (fl->profile)
getnstimeofday(&invoket);
+
VERIFY(err, fl->sctx != NULL);
if (err)
goto bail;
@@ -1504,7 +1509,7 @@
goto bail;
if (init->flags == FASTRPC_INIT_ATTACH) {
remote_arg_t ra[1];
- int tgid = current->tgid;
+ int tgid = fl->tgid;
ra[0].buf.pv = (void *)&tgid;
ra[0].buf.len = sizeof(tgid);
@@ -1532,7 +1537,7 @@
int siglen;
} inbuf;
- inbuf.pgid = current->tgid;
+ inbuf.pgid = fl->tgid;
inbuf.namelen = strlen(current->comm) + 1;
inbuf.filelen = init->filelen;
fl->pd = 1;
@@ -1645,7 +1650,7 @@
uintptr_t vaddrout;
} routargs;
- inargs.pid = current->tgid;
+ inargs.pid = fl->tgid;
inargs.vaddrin = (uintptr_t)map->va;
inargs.flags = flags;
inargs.num = fl->apps->compat ? num * sizeof(page) : num;
@@ -1687,7 +1692,7 @@
ssize_t size;
} inargs;
- inargs.pid = current->tgid;
+ inargs.pid = fl->tgid;
inargs.size = map->size;
inargs.vaddrout = map->raddr;
ra[0].buf.pv = (void *)&inargs;
@@ -2226,6 +2231,7 @@
INIT_HLIST_HEAD(&fl->maps);
INIT_HLIST_HEAD(&fl->bufs);
INIT_HLIST_NODE(&fl->hn);
+ fl->sessionid = 0;
fl->tgid = current->tgid;
fl->apps = me;
fl->mode = FASTRPC_MODE_SERIAL;
@@ -2386,6 +2392,10 @@
case FASTRPC_MODE_PROFILE:
fl->profile = (uint32_t)ioctl_param;
break;
+ case FASTRPC_MODE_SESSION:
+ fl->sessionid = 1;
+ fl->tgid |= (1 << SESSION_ID_INDEX);
+ break;
default:
err = -ENOTTY;
break;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 9f964d2..2e8bfc2 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -52,6 +52,9 @@
/* Driver should operate in profile mode with the co-processor */
#define FASTRPC_MODE_PROFILE 2
+/* Set FastRPC session ID to 1 */
+#define FASTRPC_MODE_SESSION 4
+
/* INIT a new process or attach to guestos */
#define FASTRPC_INIT_ATTACH 0
#define FASTRPC_INIT_CREATE 1
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 3684b8d..5de7897 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.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
@@ -90,6 +90,18 @@
{
if (id < 0 || id >= NUM_REMOTE_DEV)
return -EINVAL;
+
+ if ((mode == DIAG_USB_MODE &&
+ driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) ||
+ (mode == DIAG_MEMORY_DEVICE_MODE &&
+ driver->logging_mode == DIAG_USB_MODE)) {
+ /*
+ * Don't close the MHI channels when usb is disconnected
+ * and a process is running in memory device mode.
+ */
+ return 0;
+ }
+
if (bridge_info[id].dev_ops && bridge_info[id].dev_ops->close)
bridge_info[id].dev_ops->close(bridge_info[id].ctxt);
return 0;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index d7e24fc..354c6a0 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -729,8 +729,9 @@
struct diagfwd_info *fwd_info_cmd = NULL;
char *process_name = NULL;
int err = 0;
+ char *root_str = NULL;
uint8_t local_diag_id = 0;
- uint8_t new_request = 0;
+ uint8_t new_request = 0, i = 0;
if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
return;
@@ -753,20 +754,31 @@
ctrl_pkt.diag_id = diag_id;
new_request = 1;
}
+ root_str = strnstr(process_name, DIAG_ID_ROOT_STRING,
+ strlen(process_name));
if (new_request) {
fwd_info_data->num_pd++;
fwd_info_cmd->num_pd++;
+ if (root_str) {
+ fwd_info_cmd->diagid_root = ctrl_pkt.diag_id;
+ fwd_info_data->diagid_root = ctrl_pkt.diag_id;
+ } else {
+ i = fwd_info_cmd->num_pd - 2;
+ if (i >= 0)
+ fwd_info_cmd->diagid_user[i] =
+ ctrl_pkt.diag_id;
+
+ i = fwd_info_data->num_pd - 2;
+ if (i >= 0)
+ fwd_info_data->diagid_user[i] =
+ ctrl_pkt.diag_id;
+ }
}
- if (strnstr(process_name, DIAG_ID_ROOT_STRING, strlen(process_name))) {
- fwd_info_cmd->diagid_root = diag_id;
- fwd_info_data->diagid_root = diag_id;
+ if (root_str)
driver->diag_id_sent[peripheral] = 0;
- } else {
- fwd_info_cmd->diagid_user[fwd_info_cmd->num_pd - 2] = diag_id;
- fwd_info_data->diagid_user[fwd_info_data->num_pd - 2] = diag_id;
- }
+
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
@@ -794,6 +806,10 @@
* to peripherals.
*/
driver->diag_id_sent[peripheral] = 1;
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
+ driver->diag_id_sent[peripheral], peripheral,
+ ctrl_pkt.diag_id, process_name);
diag_send_updates_peripheral(peripheral);
diagfwd_buffers_init(fwd_info_data);
}
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 13904fd..9f7f699 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1058,7 +1058,7 @@
return -ENODEV;
if (type == TYPE_CMD) {
- if (driver->feature[peripheral].untag_header)
+ if (driver->feature[peripheral].diag_id_support)
if (!fwd_info->diagid_root ||
(!driver->diag_id_sent[peripheral])) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index e7d3ee4..afb2c01 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -459,6 +459,37 @@
}
}
+static int clk_fabia_pll_latch_input(struct clk_alpha_pll *pll,
+ struct regmap *regmap)
+{
+ u32 regval;
+ int ret = 0;
+
+ /* Latch the PLL input */
+ ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+ FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
+ if (ret)
+ return ret;
+
+ /* Wait for 2 reference cycles before checking the ACK bit. */
+ udelay(1);
+ regmap_read(regmap, pll->offset + PLL_MODE, ®val);
+ if (!(regval & FABIA_PLL_ACK_LATCH)) {
+ WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
+ return -EINVAL;
+ }
+
+ /* Return the latch input to 0 */
+ ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+ FABIA_PLL_UPDATE, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for PLL output to stabilize */
+ udelay(100);
+ return ret;
+}
+
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct pll_config *config)
{
@@ -471,6 +502,7 @@
if (config->frac)
regmap_write(regmap, pll->offset + FABIA_FRAC_VAL,
config->frac);
+
if (config->config_ctl_val)
regmap_write(regmap, pll->offset + PLL_CONFIG_CTL,
config->config_ctl_val);
@@ -482,6 +514,14 @@
mask, val);
}
+ /*
+ * If the PLL has already been initialized, it would now be in a STANDBY
+ * state. Any new updates to the PLL frequency will require setting the
+ * PLL_UPDATE bit.
+ */
+ if (pll->inited)
+ clk_fabia_pll_latch_input(pll, regmap);
+
regmap_update_bits(regmap, pll->offset + PLL_MODE,
FABIA_PLL_HW_UPDATE_LOGIC_BYPASS,
FABIA_PLL_HW_UPDATE_LOGIC_BYPASS);
@@ -627,29 +667,8 @@
regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
regmap_write(pll->clkr.regmap, off + FABIA_FRAC_VAL, a);
- /* Latch the PLL input */
- ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
- FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
- if (ret)
- return ret;
-
- /* Wait for 2 reference cycles before checking the ACK bit. */
- udelay(1);
- regmap_read(pll->clkr.regmap, off + PLL_MODE, ®val);
- if (!(regval & FABIA_PLL_ACK_LATCH)) {
- WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
- return -EINVAL;
- }
-
- /* Return the latch input to 0 */
- ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
- FABIA_PLL_UPDATE, 0);
- if (ret)
- return ret;
-
- /* Wait for PLL output to stabilize */
- udelay(100);
- return 0;
+ ret = clk_fabia_pll_latch_input(pll, pll->clkr.regmap);
+ return ret;
}
static void clk_fabia_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
index ff229fb..e2bfe42 100644
--- a/drivers/clk/qcom/clk-aop-qmp.c
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -139,6 +139,12 @@
struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
mutex_lock(&clk_aop_lock);
+ /*
+ * Return early if the clock has been enabled already. This
+ * is to avoid issues with sending duplicate enable requests.
+ */
+ if (clk->enabled)
+ goto err;
if (clk->level)
rate = clk->level;
@@ -179,6 +185,9 @@
mutex_lock(&clk_aop_lock);
+ if (!clk->enabled)
+ goto err;
+
rate = clk->disable_state;
snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}",
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index d57bf5f..7a2969a 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -385,6 +385,20 @@
{ }
};
+static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm670[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(286670000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
.cmd_rcgr = 0x2088,
.mnd_width = 0,
@@ -1036,9 +1050,9 @@
disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
358000000;
disp_cc_mdss_dp_pixel1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
- 337500000;
+ 337500;
disp_cc_mdss_dp_pixel_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] =
- 337500000;
+ 337500;
disp_cc_mdss_mdp_clk_src.freq_tbl =
ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2;
disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
@@ -1068,6 +1082,9 @@
static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap)
{
disp_cc_sdm845_fixup_sdm845v2(regmap);
+
+ disp_cc_mdss_mdp_clk_src.freq_tbl =
+ ftbl_disp_cc_mdss_mdp_clk_src_sdm670;
}
static int disp_cc_sdm845_fixup(struct platform_device *pdev,
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index eb6c658..1cd6c9c 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -665,7 +665,6 @@
static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
{
- dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
dsi_pll_disable_pll_bias(rsc);
}
@@ -684,11 +683,20 @@
pr_debug("stop PLL (%d)\n", rsc->index);
+ /*
+ * To avoid any stray glitches while
+ * abruptly powering down the PLL
+ * make sure to gate the clock using
+ * the clock enable bit before powering
+ * down the PLL
+ */
+ dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0);
dsi_pll_disable_sub(rsc);
- if (rsc->slave)
+ if (rsc->slave) {
+ dsi_pll_disable_global_clk(rsc->slave);
dsi_pll_disable_sub(rsc->slave);
-
+ }
/* flush, ensure all register writes are done*/
wmb();
rsc->pll_on = false;
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 8c8b495..cdc092a 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -586,7 +586,7 @@
GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
GATE_BUS_TOP, 24, 0, 0),
GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
- GATE_BUS_TOP, 27, 0, 0),
+ GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
};
static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
@@ -956,20 +956,20 @@
GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0),
GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys",
- GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0),
GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2",
GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d",
GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d",
- GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0),
GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg",
GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0",
GATE_BUS_TOP, 5, 0, 0),
GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl",
- GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0),
GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl",
GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp",
@@ -983,20 +983,20 @@
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333",
- GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0),
GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
GATE_BUS_TOP, 16, 0, 0),
GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl",
GATE_BUS_TOP, 17, 0, 0),
GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1",
- GATE_BUS_TOP, 18, 0, 0),
+ GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0),
GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24",
GATE_BUS_TOP, 28, 0, 0),
GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m",
GATE_BUS_TOP, 29, 0, 0),
GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
- SRC_MASK_TOP2, 24, 0, 0),
+ SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0),
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
SRC_MASK_TOP7, 20, 0, 0),
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index 0ab4c21..fb11acd 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -779,6 +779,7 @@
if (ret)
goto failed_parse_params;
+ INIT_LIST_HEAD(&c->list);
INIT_LIST_HEAD(&c->child);
INIT_LIST_HEAD(&c->cpu);
c->parent = parent;
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 7868765..b54af97 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -1074,7 +1074,7 @@
req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
&crypt->icv_rev_aes);
if (unlikely(!req_ctx->hmac_virt))
- goto free_buf_src;
+ goto free_buf_dst;
if (!encrypt) {
scatterwalk_map_and_copy(req_ctx->hmac_virt,
req->src, cryptlen, authsize, 0);
@@ -1089,10 +1089,10 @@
BUG_ON(qmgr_stat_overflow(SEND_QID));
return -EINPROGRESS;
-free_buf_src:
- free_buf_chain(dev, req_ctx->src, crypt->src_buf);
free_buf_dst:
free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
+free_buf_src:
+ free_buf_chain(dev, req_ctx->src, crypt->src_buf);
crypt->ctl_flags = CTL_FLAG_UNUSED;
return -ENOMEM;
}
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index 4b89cbf..038e89c 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -397,21 +397,6 @@
if (rc)
goto out_mem;
- if (interrupt_mode) {
- drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
- if (!drv->ecc_irq) {
- rc = -ENODEV;
- goto out_dev;
- }
-
- rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
- IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
- if (rc) {
- dev_err(dev, "failed to request ecc irq\n");
- goto out_dev;
- }
- }
-
drv->llcc_banks = devm_kzalloc(&pdev->dev,
sizeof(u32) * drv->num_banks, GFP_KERNEL);
@@ -437,6 +422,21 @@
platform_set_drvdata(pdev, edev_ctl);
+ if (interrupt_mode) {
+ drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
+ if (!drv->ecc_irq) {
+ rc = -ENODEV;
+ goto out_dev;
+ }
+
+ rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
+ IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
+ if (rc) {
+ dev_err(dev, "failed to request ecc irq\n");
+ goto out_dev;
+ }
+ }
+
return 0;
out_dev:
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f2bb512..063d176 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -703,24 +703,23 @@
{
struct lineevent_state *le = p;
struct gpioevent_data ge;
- int ret;
+ int ret, level;
ge.timestamp = ktime_get_real_ns();
+ level = gpiod_get_value_cansleep(le->desc);
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
- int level = gpiod_get_value_cansleep(le->desc);
-
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) {
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) {
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else {
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index dc9511c..327bdf1 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -1301,6 +1301,7 @@
amdgpu_program_register_sequence(adev,
pitcairn_mgcg_cgcg_init,
(const u32)ARRAY_SIZE(pitcairn_mgcg_cgcg_init));
+ break;
case CHIP_VERDE:
amdgpu_program_register_sequence(adev,
verde_golden_registers,
@@ -1325,6 +1326,7 @@
amdgpu_program_register_sequence(adev,
oland_mgcg_cgcg_init,
(const u32)ARRAY_SIZE(oland_mgcg_cgcg_init));
+ break;
case CHIP_HAINAN:
amdgpu_program_register_sequence(adev,
hainan_golden_registers,
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 99011621..4e16dff 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1459,6 +1459,9 @@
if (config->funcs->atomic_check)
ret = config->funcs->atomic_check(state->dev, state);
+ if (ret)
+ return ret;
+
if (!state->allow_modeset) {
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
@@ -1469,7 +1472,7 @@
}
}
- return ret;
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_check_only);
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index ac5437e..6394109 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -358,20 +358,13 @@
*/
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
{
- u8 value;
+ u8 value = DP_SET_POWER_D0;
int err;
/* DP_SET_POWER register is only available on DPCD v1.1 and later */
if (link->revision < 0x11)
return 0;
- err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
- if (err < 0)
- return err;
-
- value &= ~DP_SET_POWER_MASK;
- value |= DP_SET_POWER_D0;
-
err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 465bacd..48e99ab 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -255,13 +255,13 @@
struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev;
+ if (dev->driver->gem_close_object)
+ dev->driver->gem_close_object(obj, file_priv);
+
if (drm_core_check_feature(dev, DRIVER_PRIME))
drm_gem_remove_prime_handles(obj, file_priv);
drm_vma_node_revoke(&obj->vma_node, file_priv);
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, file_priv);
-
drm_gem_object_handle_unreference_unlocked(obj);
return 0;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index afdd55d..1ac9a95 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -264,8 +264,8 @@
if (ret)
return ret;
- if (r->reloc_offset >= bo->obj->base.size - sizeof(*ptr)) {
- DRM_ERROR("relocation %u outside object", i);
+ if (r->reloc_offset > bo->obj->base.size - sizeof(*ptr)) {
+ DRM_ERROR("relocation %u outside object\n", i);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c
index 95a7277..89a7774 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -394,6 +394,7 @@
}
/* Program the max register to clamp values > 1.0. */
+ i = lut_size - 1;
I915_WRITE(PREC_PAL_GC_MAX(pipe, 0),
drm_color_lut_extract(lut[i].red, 16));
I915_WRITE(PREC_PAL_GC_MAX(pipe, 1),
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index c263115..67b6072 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -379,7 +379,7 @@
case DP_LINK_BW_5_4:
select = 2;
break;
- case DP_LINK_RATE_810:
+ case DP_LINK_BW_8_1:
select = 3;
break;
default:
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 94bd199..9327ddc 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -15,10 +15,14 @@
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#include <linux/delay.h>
+#include <drm/drm_dp_helper.h>
#include "dp_catalog.h"
#include "dp_reg.h"
+#define DP_GET_MSB(x) (x >> 8)
+#define DP_GET_LSB(x) (x & 0xff)
+
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
@@ -277,6 +281,174 @@
return dp_read(base + DP_HDCP_STATUS);
}
+static void dp_catalog_ctrl_setup_infoframe_sdp(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 header, data;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ header = dp_read(base + MMSS_DP_VSCEXT_0);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_0, header);
+
+ header = dp_read(base + MMSS_DP_VSCEXT_1);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_1, header);
+
+ header = dp_read(base + MMSS_DP_VSCEXT_1);
+ header |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_VSCEXT_1, header);
+
+ header = ctrl->hdr_data.version;
+ header |= ctrl->hdr_data.length << 8;
+ header |= ctrl->hdr_data.eotf << 16;
+ header |= (ctrl->hdr_data.descriptor_id << 24);
+ dp_write(base + MMSS_DP_VSCEXT_2, header);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[0]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_3, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[1]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_4, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[2]) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_5, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.white_point_x) |
+ (DP_GET_MSB(ctrl->hdr_data.white_point_x) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.white_point_y) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.white_point_y) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_6, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.max_luminance) |
+ (DP_GET_MSB(ctrl->hdr_data.max_luminance) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.min_luminance) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.min_luminance) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_7, data);
+
+ data = (DP_GET_LSB(ctrl->hdr_data.max_content_light_level) |
+ (DP_GET_MSB(ctrl->hdr_data.max_content_light_level) << 8) |
+ (DP_GET_LSB(ctrl->hdr_data.max_average_light_level) << 16) |
+ (DP_GET_MSB(ctrl->hdr_data.max_average_light_level) << 24));
+ dp_write(base + MMSS_DP_VSCEXT_8, data);
+
+ dp_write(base + MMSS_DP_VSCEXT_9, 0x00);
+}
+
+static void dp_catalog_ctrl_setup_vsc_sdp(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 value;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ value = dp_read(base + MMSS_DP_GENERIC0_0);
+ value |= ctrl->hdr_data.vsc_hdr_byte1;
+ dp_write(base + MMSS_DP_GENERIC0_0, value);
+
+ value = dp_read(base + MMSS_DP_GENERIC0_1);
+ value |= ctrl->hdr_data.vsc_hdr_byte2;
+ dp_write(base + MMSS_DP_GENERIC0_1, value);
+
+ value = dp_read(base + MMSS_DP_GENERIC0_1);
+ value |= ctrl->hdr_data.vsc_hdr_byte3;
+ dp_write(base + MMSS_DP_GENERIC0_1, value);
+
+ dp_write(base + MMSS_DP_GENERIC0_2, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_3, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_4, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_5, 0x00);
+
+ dp_write(base + MMSS_DP_GENERIC0_6, ctrl->hdr_data.pkt_payload);
+ dp_write(base + MMSS_DP_GENERIC0_7, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_8, 0x00);
+ dp_write(base + MMSS_DP_GENERIC0_9, 0x00);
+}
+
+static void dp_catalog_ctrl_config_hdr(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+ u32 cfg, cfg2;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+ base = catalog->io->ctrl_io.base;
+
+ cfg = dp_read(base + MMSS_DP_SDP_CFG);
+ /* VSCEXT_SDP_EN */
+ cfg |= BIT(16);
+
+ /* GEN0_SDP_EN */
+ cfg |= BIT(17);
+
+ dp_write(base + MMSS_DP_SDP_CFG, cfg);
+
+ cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+ /* Generic0 SDP Payload is 19 bytes which is > 16, so Bit16 is 1 */
+ cfg2 |= BIT(16);
+ dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+
+ dp_catalog_ctrl_setup_vsc_sdp(ctrl);
+ dp_catalog_ctrl_setup_infoframe_sdp(ctrl);
+
+ cfg = dp_read(base + DP_MISC1_MISC0);
+ /* Indicates presence of VSC */
+ cfg |= BIT(6) << 8;
+
+ dp_write(base + DP_MISC1_MISC0, cfg);
+
+ cfg = dp_read(base + DP_CONFIGURATION_CTRL);
+ /* Send VSC */
+ cfg |= BIT(7);
+
+ switch (ctrl->hdr_data.bpc) {
+ default:
+ case 10:
+ cfg |= BIT(9);
+ break;
+ case 8:
+ cfg |= BIT(8);
+ break;
+ }
+
+ dp_write(base + DP_CONFIGURATION_CTRL, cfg);
+
+ cfg = dp_read(base + DP_COMPRESSION_MODE_CTRL);
+
+ /* Trigger SDP values in registers */
+ cfg |= BIT(8);
+ dp_write(base + DP_COMPRESSION_MODE_CTRL, cfg);
+}
+
static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
{
struct dp_catalog_private *catalog;
@@ -381,7 +553,7 @@
static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl,
u32 cc, u32 tb)
{
- u32 misc_val = cc;
+ u32 misc_val;
struct dp_catalog_private *catalog;
void __iomem *base;
@@ -393,6 +565,8 @@
dp_catalog_get_priv(ctrl);
base = catalog->io->ctrl_io.base;
+ misc_val = dp_read(base + DP_MISC1_MISC0);
+ misc_val |= cc;
misc_val |= (tb << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */
@@ -408,7 +582,8 @@
u32 mvid, nvid;
u64 mvid_calc;
u32 const nvid_fixed = 0x8000;
- u32 const link_rate = 540000;
+ u32 const link_rate_hbr2 = 540000;
+ u32 const link_rate_hbr3 = 810000;
struct dp_catalog_private *catalog;
void __iomem *base_cc, *base_ctrl;
@@ -449,8 +624,11 @@
pr_debug("rate = %d\n", rate);
- if (link_rate == rate)
+ if (link_rate_hbr2 == rate)
nvid *= 2;
+
+ if (link_rate_hbr3 == rate)
+ nvid *= 3;
}
base_ctrl = catalog->io->ctrl_io.base;
@@ -493,6 +671,43 @@
pr_err("set link_train=%d failed\n", pattern);
}
+static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+
+ base = catalog->io->usb3_dp_com.base;
+
+ dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
+ dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02);
+ dp_write(base + USB3_DP_COM_SW_RESET, 0x01);
+ /* make sure usb3 com phy software reset is done */
+ wmb();
+
+ if (!flip) /* CC1 */
+ dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02);
+ else /* CC2 */
+ dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03);
+
+ dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00);
+ dp_write(base + USB3_DP_COM_SW_RESET, 0x00);
+ /* make sure the software reset is done */
+ wmb();
+
+ dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
+ dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+ /* make sure phy is brought out of reset */
+ wmb();
+
+}
+
static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl)
{
u32 sw_reset;
@@ -706,6 +921,82 @@
}
}
+static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl,
+ u32 pattern)
+{
+ struct dp_catalog_private *catalog;
+ u32 value = 0x0;
+ void __iomem *base = NULL;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp_catalog_get_priv(ctrl);
+
+ base = catalog->io->ctrl_io.base;
+
+ dp_write(base + DP_STATE_CTRL, 0x0);
+
+ switch (pattern) {
+ case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+ dp_write(base + DP_STATE_CTRL, 0x1);
+ break;
+ case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ value &= ~(1 << 16);
+ dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+ value |= 0xFC;
+ dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+ dp_write(base + DP_MAINLINK_LEVELS, 0x2);
+ dp_write(base + DP_STATE_CTRL, 0x10);
+ break;
+ case DP_TEST_PHY_PATTERN_PRBS7:
+ dp_write(base + DP_STATE_CTRL, 0x20);
+ break;
+ case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+ dp_write(base + DP_STATE_CTRL, 0x40);
+ /* 00111110000011111000001111100000 */
+ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
+ /* 00001111100000111110000011111000 */
+ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
+ /* 1111100000111110 */
+ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
+ break;
+ case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
+ value = BIT(16);
+ dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+ value |= 0xFC;
+ dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+ dp_write(base + DP_MAINLINK_LEVELS, 0x2);
+ dp_write(base + DP_STATE_CTRL, 0x10);
+ break;
+ default:
+ pr_debug("No valid test pattern requested: 0x%x\n", pattern);
+ return;
+ }
+
+ /* Make sure the test pattern is programmed in the hardware */
+ wmb();
+}
+
+static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
+{
+ struct dp_catalog_private *catalog;
+ void __iomem *base = NULL;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return 0;
+ }
+
+ dp_catalog_get_priv(ctrl);
+
+ base = catalog->io->ctrl_io.base;
+
+ return dp_read(base + DP_MAINLINK_READY);
+}
+
/* panel related catalog functions */
static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
{
@@ -937,6 +1228,7 @@
.config_msa = dp_catalog_ctrl_config_msa,
.set_pattern = dp_catalog_ctrl_set_pattern,
.reset = dp_catalog_ctrl_reset,
+ .usb_reset = dp_catalog_ctrl_usb_reset,
.mainlink_ready = dp_catalog_ctrl_mainlink_ready,
.enable_irq = dp_catalog_ctrl_enable_irq,
.hpd_config = dp_catalog_ctrl_hpd_config,
@@ -944,8 +1236,11 @@
.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg,
.update_vx_px = dp_catalog_ctrl_update_vx_px,
.get_interrupt = dp_catalog_ctrl_get_interrupt,
+ .config_hdr = dp_catalog_ctrl_config_hdr,
.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
.read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
+ .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern,
+ .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern,
};
struct dp_catalog_audio audio = {
.init = dp_catalog_audio_init,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 47c10bf..39c5c6d 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -34,6 +34,32 @@
#define DP_INTR_FRAME_END BIT(6)
#define DP_INTR_CRC_UPDATED BIT(9)
+#define HDR_PRIMARIES_COUNT 3
+
+struct dp_catalog_hdr_data {
+ u32 vsc_hdr_byte0;
+ u32 vsc_hdr_byte1;
+ u32 vsc_hdr_byte2;
+ u32 vsc_hdr_byte3;
+ u32 pkt_payload;
+
+ u32 bpc;
+
+ u32 version;
+ u32 length;
+ u32 eotf;
+ u32 descriptor_id;
+
+ u32 display_primaries_x[HDR_PRIMARIES_COUNT];
+ u32 display_primaries_y[HDR_PRIMARIES_COUNT];
+ u32 white_point_x;
+ u32 white_point_y;
+ u32 max_luminance;
+ u32 min_luminance;
+ u32 max_content_light_level;
+ u32 max_average_light_level;
+};
+
struct dp_catalog_aux {
u32 data;
u32 isr;
@@ -55,6 +81,7 @@
u32 valid_boundary;
u32 valid_boundary2;
u32 isr;
+ struct dp_catalog_hdr_data hdr_data;
void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state);
void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u32 config);
@@ -65,6 +92,7 @@
u32 stream_rate_khz, bool fixed_nvid);
void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern);
void (*reset)(struct dp_catalog_ctrl *ctrl);
+ void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip);
bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl);
void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable);
void (*hpd_config)(struct dp_catalog_ctrl *ctrl, bool enable);
@@ -74,8 +102,12 @@
void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level,
u8 p_level);
void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
+ void (*config_hdr)(struct dp_catalog_ctrl *ctrl);
void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
+ void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
+ u32 pattern);
+ u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl);
};
enum dp_catalog_audio_sdp_type {
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 51abcf5..dcdcc6f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -36,6 +36,11 @@
#define ST_SEND_VIDEO BIT(7)
#define ST_PUSH_IDLE BIT(8)
+#define MR_LINK_TRAINING1 0x8
+#define MR_LINK_SYMBOL_ERM 0x80
+#define MR_LINK_PRBS7 0x100
+#define MR_LINK_CUSTOM80 0x200
+
struct dp_vc_tu_mapping_table {
u32 vic;
u8 lanes;
@@ -63,7 +68,6 @@
struct completion idle_comp;
struct completion video_comp;
- struct completion irq_comp;
bool psm_enabled;
bool orientation;
@@ -155,7 +159,7 @@
config |= tbd << 8;
/* Num of Lanes */
- config |= ((ctrl->link->lane_count - 1) << 4);
+ config |= ((ctrl->link->link_params.lane_count - 1) << 4);
if (drm_dp_enhanced_frame_cap(dpcd))
config |= 0x40;
@@ -303,7 +307,7 @@
u64 brute_force_threshold = 10;
u64 diff_abs;
- ln_cnt = ctrl->link->lane_count;
+ ln_cnt = ctrl->link->link_params.lane_count;
bpp = pinfo->bpp;
lwidth = pinfo->h_active;
@@ -322,7 +326,8 @@
even_distribution = 0;
min_hblank = 0;
- lclk = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code) * DP_KHZ_TO_HZ;
+ lclk = drm_dp_bw_code_to_link_rate(
+ ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ;
pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
pclk, lwidth, h_blank);
@@ -761,9 +766,10 @@
struct dp_link *link = ctrl->link;
ctrl->catalog->update_vx_px(ctrl->catalog,
- link->v_level, link->p_level);
+ link->phy_params.v_level, link->phy_params.p_level);
- dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
+ dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
+ link->phy_params.p_level);
}
static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
@@ -816,7 +822,7 @@
dp_ctrl_update_vx_px(ctrl);
tries = 0;
- old_v_level = ctrl->link->v_level;
+ old_v_level = ctrl->link->phy_params.v_level;
while (1) {
drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
@@ -825,26 +831,26 @@
break;
if (drm_dp_clock_recovery_ok(link_status,
- ctrl->link->lane_count)) {
+ ctrl->link->link_params.lane_count)) {
break;
}
- if (ctrl->link->v_level == DP_LINK_VOLTAGE_MAX) {
+ if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) {
pr_err_ratelimited("max v_level reached\n");
ret = -EAGAIN;
break;
}
- if (old_v_level == ctrl->link->v_level) {
+ if (old_v_level == ctrl->link->phy_params.v_level) {
tries++;
if (tries >= maximum_retries) {
pr_err("max tries reached\n");
- ret = -EAGAIN;
+ ret = -ETIMEDOUT;
break;
}
} else {
tries = 0;
- old_v_level = ctrl->link->v_level;
+ old_v_level = ctrl->link->phy_params.v_level;
}
pr_debug("clock recovery not done, adjusting vx px\n");
@@ -859,41 +865,25 @@
static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
{
int ret = 0;
- u32 min_req_link_rate_khz;
- u32 new_proposed_link_bw_code;
- u32 new_proposed_link_rate_khz;
if (!ctrl)
return -EINVAL;
- min_req_link_rate_khz = ctrl->panel->get_min_req_link_rate(ctrl->panel);
-
- switch (ctrl->link->bw_code) {
- case DP_LINK_RATE_810:
- new_proposed_link_bw_code = DP_LINK_BW_5_4;
+ switch (ctrl->link->link_params.bw_code) {
+ case DP_LINK_BW_8_1:
+ ctrl->link->link_params.bw_code = DP_LINK_BW_5_4;
break;
case DP_LINK_BW_5_4:
- new_proposed_link_bw_code = DP_LINK_BW_2_7;
+ ctrl->link->link_params.bw_code = DP_LINK_BW_2_7;
break;
case DP_LINK_BW_2_7:
case DP_LINK_BW_1_62:
default:
- new_proposed_link_bw_code = DP_LINK_BW_1_62;
+ ctrl->link->link_params.bw_code = DP_LINK_BW_1_62;
break;
};
- new_proposed_link_rate_khz = drm_dp_bw_code_to_link_rate(
- new_proposed_link_bw_code);
-
- pr_debug("new proposed link rate=%d khz\n", new_proposed_link_rate_khz);
- pr_debug("min required link rate=%d khz\n", min_req_link_rate_khz);
-
- if (new_proposed_link_rate_khz >= min_req_link_rate_khz)
- ctrl->link->bw_code = new_proposed_link_bw_code;
- else
- pr_debug("can't go below min required link rate\n");
-
- pr_debug("new bw code=0x%x\n", ctrl->link->bw_code);
+ pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
return ret;
}
@@ -931,11 +921,12 @@
if (ret)
break;
- if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count))
+ if (drm_dp_channel_eq_ok(link_status,
+ ctrl->link->link_params.lane_count))
break;
if (tries > maximum_retries) {
- ret = -EAGAIN;
+ ret = -ETIMEDOUT;
break;
}
tries++;
@@ -953,13 +944,14 @@
u8 encoding = 0x1;
struct drm_dp_link link_info = {0};
- ctrl->link->p_level = 0;
- ctrl->link->v_level = 0;
+ ctrl->link->phy_params.p_level = 0;
+ ctrl->link->phy_params.v_level = 0;
dp_ctrl_config_ctrl(ctrl);
- link_info.num_lanes = ctrl->link->lane_count;
- link_info.rate = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code);
+ link_info.num_lanes = ctrl->link->link_params.lane_count;
+ link_info.rate = drm_dp_bw_code_to_link_rate(
+ ctrl->link->link_params.bw_code);
link_info.capabilities = ctrl->panel->link_info.capabilities;
drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
@@ -1002,7 +994,7 @@
drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);
- if (ctrl->link->phy_pattern_requested(ctrl->link))
+ if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
goto end;
if (!train)
@@ -1060,7 +1052,7 @@
ctrl->power->set_pixel_clk_parent(ctrl->power);
dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
- drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+ drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code));
dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
@@ -1093,7 +1085,7 @@
ctrl->orientation = flip;
catalog = ctrl->catalog;
- catalog->reset(ctrl->catalog);
+ catalog->usb_reset(ctrl->catalog, flip);
catalog->phy_reset(ctrl->catalog);
catalog->enable_irq(ctrl->catalog, true);
@@ -1119,12 +1111,6 @@
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
ctrl->catalog->enable_irq(ctrl->catalog, false);
- ctrl->catalog->reset(ctrl->catalog);
-
- /* Make sure DP is disabled before clk disable */
- wmb();
-
- dp_ctrl_disable_mainlink_clocks(ctrl);
pr_debug("Host deinitialized successfully\n");
}
@@ -1147,95 +1133,223 @@
return false;
}
-static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
+static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
{
int ret = 0;
+ ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
+ ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
+
+ ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+
do {
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN) {
+ /* try with lower link rate */
+ dp_ctrl_link_rate_down_shift(ctrl);
+
ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
+ }
ctrl->catalog->phy_lane_cfg(ctrl->catalog,
- ctrl->orientation, ctrl->link->lane_count);
+ ctrl->orientation, ctrl->link->link_params.lane_count);
- if (lt_needed) {
- /*
- * Diasable and re-enable the mainlink clock since the
- * link clock might have been adjusted as part of the
- * link maintenance.
- */
- if (!ctrl->link->phy_pattern_requested(
- ctrl->link))
- dp_ctrl_disable_mainlink_clocks(ctrl);
+ /*
+ * Disable and re-enable the mainlink clock since the
+ * link clock might have been adjusted as part of the
+ * link maintenance.
+ */
+ dp_ctrl_disable_mainlink_clocks(ctrl);
- ret = dp_ctrl_enable_mainlink_clocks(ctrl);
- if (ret)
- continue;
- }
+ ret = dp_ctrl_enable_mainlink_clocks(ctrl);
+ if (ret)
+ continue;
dp_ctrl_configure_source_params(ctrl);
ctrl->catalog->config_msa(ctrl->catalog,
- drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+ drm_dp_bw_code_to_link_rate(
+ ctrl->link->link_params.bw_code),
ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
reinit_completion(&ctrl->idle_comp);
- if (ctrl->psm_enabled) {
- ret = ctrl->link->send_psm_request(ctrl->link, false);
- if (ret) {
- pr_err("failed to exit low power mode, rc=%d\n",
- ret);
- continue;
- }
- }
-
- ret = dp_ctrl_setup_main_link(ctrl, lt_needed);
+ ret = dp_ctrl_setup_main_link(ctrl, true);
} while (ret == -EAGAIN);
return ret;
}
-static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
+static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
{
int ret = 0;
- u32 rate = ctrl->panel->link_info.rate;
+
+ if (!ctrl->link->phy_params.phy_test_pattern_sel) {
+ pr_debug("no test pattern selected by sink\n");
+ return;
+ }
+
+ pr_debug("start\n");
+
+ ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
+ /*
+ * The global reset will need DP link ralated clocks to be
+ * running. Add the global reset just before disabling the
+ * link clocks and core clocks.
+ */
+ ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
+ ctrl->dp_ctrl.off(&ctrl->dp_ctrl);
+
+ ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl);
+ if (ret)
+ pr_err("failed to enable DP controller\n");
+
+ pr_debug("end\n");
+}
+
+static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
+{
+ bool success = false;
+ u32 pattern_sent = 0x0;
+ u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
+
+ pr_debug("request: %s\n",
+ dp_link_get_phy_test_pattern(pattern_requested));
+
+ ctrl->catalog->update_vx_px(ctrl->catalog,
+ ctrl->link->phy_params.v_level,
+ ctrl->link->phy_params.p_level);
+ ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
+ ctrl->link->send_test_response(ctrl->link);
+
+ pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);
+
+ switch (pattern_sent) {
+ case MR_LINK_TRAINING1:
+ if (pattern_requested ==
+ DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING)
+ success = true;
+ break;
+ case MR_LINK_SYMBOL_ERM:
+ if ((pattern_requested ==
+ DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT)
+ || (pattern_requested ==
+ DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN))
+ success = true;
+ break;
+ case MR_LINK_PRBS7:
+ if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7)
+ success = true;
+ break;
+ case MR_LINK_CUSTOM80:
+ if (pattern_requested ==
+ DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN)
+ success = true;
+ break;
+ default:
+ success = false;
+ return;
+ }
+
+ pr_debug("%s: %s\n", success ? "success" : "failed",
+ dp_link_get_phy_test_pattern(pattern_requested));
+}
+
+static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
+{
+ struct dp_ctrl_private *ctrl;
+ u32 sink_request = 0x0;
+
+ if (!dp_ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+ sink_request = ctrl->link->sink_request;
+
+ if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
+ pr_info("PHY_TEST_PATTERN request\n");
+ dp_ctrl_process_phy_test_request(ctrl);
+ }
+
+ if (sink_request & DP_LINK_STATUS_UPDATED)
+ dp_ctrl_link_maintenance(ctrl);
+
+ if (sink_request & DP_TEST_LINK_TRAINING) {
+ ctrl->link->send_test_response(ctrl->link);
+ dp_ctrl_link_maintenance(ctrl);
+ }
+}
+
+static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
+{
+ struct dp_ctrl_private *ctrl;
+
+ if (!dp_ctrl) {
+ pr_err("invalid params\n");
+ return;
+ }
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+ ctrl->catalog->reset(ctrl->catalog);
+}
+
+static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
+{
+ int rc = 0;
+ struct dp_ctrl_private *ctrl;
+ u32 rate = 0;
u32 link_train_max_retries = 100;
+ u32 const phy_cts_pixel_clk_khz = 148500;
+
+ if (!dp_ctrl) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
atomic_set(&ctrl->aborted, 0);
+ rate = ctrl->panel->link_info.rate;
ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
ctrl->catalog->hpd_config(ctrl->catalog, true);
- ctrl->link->bw_code = drm_dp_link_rate_to_bw_code(rate);
- ctrl->link->lane_count = ctrl->panel->link_info.num_lanes;
- ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+ if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
+ pr_debug("using phy test link parameters\n");
+ if (!ctrl->panel->pinfo.pixel_clk_khz)
+ ctrl->pixel_rate = phy_cts_pixel_clk_khz;
+ } else {
+ ctrl->link->link_params.bw_code =
+ drm_dp_link_rate_to_bw_code(rate);
+ ctrl->link->link_params.lane_count =
+ ctrl->panel->link_info.num_lanes;
+ ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+ }
pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
- ctrl->link->bw_code, ctrl->link->lane_count,
- ctrl->pixel_rate);
+ ctrl->link->link_params.bw_code,
+ ctrl->link->link_params.lane_count, ctrl->pixel_rate);
ctrl->catalog->phy_lane_cfg(ctrl->catalog,
- ctrl->orientation, ctrl->link->lane_count);
+ ctrl->orientation, ctrl->link->link_params.lane_count);
- ret = dp_ctrl_enable_mainlink_clocks(ctrl);
- if (ret)
- goto exit;
+ rc = dp_ctrl_enable_mainlink_clocks(ctrl);
+ if (rc)
+ goto end;
reinit_completion(&ctrl->idle_comp);
dp_ctrl_configure_source_params(ctrl);
- if (ctrl->psm_enabled)
- ret = ctrl->link->send_psm_request(ctrl->link, false);
-
while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
ctrl->catalog->config_msa(ctrl->catalog,
- drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+ drm_dp_bw_code_to_link_rate(
+ ctrl->link->link_params.bw_code),
ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
- ret = dp_ctrl_setup_main_link(ctrl, true);
- if (!ret)
+ rc = dp_ctrl_setup_main_link(ctrl, true);
+ if (!rc)
break;
/* try with lower link rate */
@@ -1250,50 +1364,16 @@
dp_ctrl_enable_mainlink_clocks(ctrl);
}
+ if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
+ dp_ctrl_send_phy_test_pattern(ctrl);
+
pr_debug("End-\n");
-exit:
- return ret;
-}
-
-static void dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
-{
- ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
-
- /* Make sure DP mainlink and audio engines are disabled */
- wmb();
-
- complete_all(&ctrl->irq_comp);
- pr_debug("end\n");
-}
-
-static void dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
-{
- ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
- pr_debug("DP off done\n");
-}
-
-static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool hpd_irq)
-{
- int rc = 0;
- struct dp_ctrl_private *ctrl;
-
- if (!dp_ctrl) {
- rc = -EINVAL;
- goto end;
- }
-
- ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-
- if (hpd_irq)
- rc = dp_ctrl_on_irq(ctrl, false);
- else
- rc = dp_ctrl_on_hpd(ctrl);
end:
return rc;
}
-static void dp_ctrl_off(struct dp_ctrl *dp_ctrl, bool hpd_irq)
+static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
{
struct dp_ctrl_private *ctrl;
@@ -1302,10 +1382,15 @@
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
- if (hpd_irq)
- dp_ctrl_off_irq(ctrl);
- else
- dp_ctrl_off_hpd(ctrl);
+ ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
+ ctrl->catalog->reset(ctrl->catalog);
+
+ /* Make sure DP is disabled before clk disable */
+ wmb();
+
+ dp_ctrl_disable_mainlink_clocks(ctrl);
+
+ pr_debug("DP off done\n");
}
static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
@@ -1347,7 +1432,6 @@
init_completion(&ctrl->idle_comp);
init_completion(&ctrl->video_comp);
- init_completion(&ctrl->irq_comp);
/* in parameters */
ctrl->parser = in->parser;
@@ -1367,6 +1451,8 @@
dp_ctrl->push_idle = dp_ctrl_push_idle;
dp_ctrl->abort = dp_ctrl_abort;
dp_ctrl->isr = dp_ctrl_isr;
+ dp_ctrl->reset = dp_ctrl_reset;
+ dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request;
return dp_ctrl;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 2ecfa0d..69cf6b6 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -23,13 +23,16 @@
#include "dp_catalog.h"
struct dp_ctrl {
+
int (*init)(struct dp_ctrl *dp_ctrl, bool flip);
void (*deinit)(struct dp_ctrl *dp_ctrl);
- int (*on)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
- void (*off)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
+ int (*on)(struct dp_ctrl *dp_ctrl);
+ void (*off)(struct dp_ctrl *dp_ctrl);
+ void (*reset)(struct dp_ctrl *dp_ctrl);
void (*push_idle)(struct dp_ctrl *dp_ctrl);
void (*abort)(struct dp_ctrl *dp_ctrl);
void (*isr)(struct dp_ctrl *dp_ctrl);
+ void (*handle_sink_request)(struct dp_ctrl *dp_ctrl);
};
struct dp_ctrl_in {
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 82e34df..cc9e623 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -306,33 +306,34 @@
/* Link Information */
rc = snprintf(buf + len, max_size,
"\tdp_link:\n\t\ttest_requested = %d\n",
- debug->link->test_requested);
+ debug->link->sink_request);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
rc = snprintf(buf + len, max_size,
- "\t\tlane_count = %d\n", debug->link->lane_count);
+ "\t\tlane_count = %d\n", debug->link->link_params.lane_count);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
rc = snprintf(buf + len, max_size,
- "\t\tbw_code = %d\n", debug->link->bw_code);
+ "\t\tbw_code = %d\n", debug->link->link_params.bw_code);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
- lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
+ lclk = drm_dp_bw_code_to_link_rate(
+ debug->link->link_params.bw_code) * 1000;
rc = snprintf(buf + len, max_size,
"\t\tlclk = %lld\n", lclk);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
rc = snprintf(buf + len, max_size,
- "\t\tv_level = %d\n", debug->link->v_level);
+ "\t\tv_level = %d\n", debug->link->phy_params.v_level);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
rc = snprintf(buf + len, max_size,
- "\t\tp_level = %d\n", debug->link->p_level);
+ "\t\tp_level = %d\n", debug->link->phy_params.p_level);
if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
goto error;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 7e40cc6..3fa376b 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -422,6 +422,50 @@
.unbind = dp_display_unbind,
};
+static bool dp_display_is_ds_bridge(struct dp_panel *panel)
+{
+ return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+ DP_DWN_STRM_PORT_PRESENT);
+}
+
+static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
+{
+ return dp_display_is_ds_bridge(dp->panel) &&
+ (dp->link->sink_count.count == 0);
+}
+
+static int dp_display_send_hpd_notification(struct dp_display_private *dp,
+ bool hpd)
+{
+
+ if ((hpd && dp->dp_display.is_connected) ||
+ (!hpd && !dp->dp_display.is_connected)) {
+ pr_info("HPD already %s\n", (hpd ? "on" : "off"));
+ return 0;
+ }
+
+ dp->dp_display.is_connected = hpd;
+ reinit_completion(&dp->notification_comp);
+ drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+
+ if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
+ pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void dp_display_handle_test_edid(struct dp_display_private *dp)
+{
+ if (dp->link->sink_request & DP_TEST_LINK_EDID_READ) {
+ drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_EDID_CHECKSUM,
+ &dp->panel->edid_ctrl->edid->checksum, 1);
+ drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE,
+ &dp->link->test_response, 1);
+ }
+}
+
static int dp_display_process_hpd_high(struct dp_display_private *dp)
{
int rc = 0;
@@ -432,23 +476,28 @@
if (rc)
return rc;
+ dp->link->process_request(dp->link);
+
+ if (dp_display_is_sink_count_zero(dp)) {
+ pr_debug("no downstream devices connected\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
edid = dp->panel->edid_ctrl->edid;
dp->audio_supported = drm_detect_monitor_audio(edid);
+ dp_display_handle_test_edid(dp);
+
max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
dp->parser->max_pclk_khz);
- dp->dp_display.is_connected = true;
+ dp_display_send_hpd_notification(dp, true);
- drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
-
- reinit_completion(&dp->notification_comp);
- if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
- pr_warn("timeout\n");
-
+end:
return rc;
}
@@ -498,12 +547,7 @@
if (dp->audio_supported)
dp->audio->off(dp->audio);
- dp->dp_display.is_connected = false;
- drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
-
- reinit_completion(&dp->notification_comp);
- if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
- pr_warn("timeout\n");
+ dp_display_send_hpd_notification(dp, false);
}
static int dp_display_usbpd_configure_cb(struct device *dev)
@@ -543,7 +587,7 @@
}
dp->ctrl->push_idle(dp->ctrl);
- dp->ctrl->off(dp->ctrl, false);
+ dp->ctrl->off(dp->ctrl);
}
static int dp_display_usbpd_disconnect_cb(struct device *dev)
@@ -570,22 +614,34 @@
if (dp->audio_supported)
dp->audio->off(dp->audio);
- dp->dp_display.is_connected = false;
- drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+ rc = dp_display_send_hpd_notification(dp, false);
- reinit_completion(&dp->notification_comp);
- if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
- pr_warn("timeout\n");
-
- if (dp->power_on)
- dp_display_clean(dp);
- }
+ if ((rc < 0) && dp->power_on)
+ dp_display_clean(dp);
dp_display_host_deinit(dp);
end:
return rc;
}
+static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
+{
+ if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
+ dp_display_send_hpd_notification(dp, false);
+
+ if (dp_display_is_sink_count_zero(dp)) {
+ pr_debug("sink count is zero, nothing to do\n");
+ return 0;
+ }
+
+ return dp_display_process_hpd_high(dp);
+ }
+
+ dp->ctrl->handle_sink_request(dp->ctrl);
+
+ return 0;
+}
+
static int dp_display_usbpd_attention_cb(struct device *dev)
{
int rc = 0;
@@ -611,9 +667,12 @@
}
rc = dp->link->process_request(dp->link);
- dp->hpd_irq_on = false;
+ /* check for any test request issued by sink */
if (!rc)
- goto end;
+ dp_display_handle_hpd_irq(dp);
+
+ dp->hpd_irq_on = false;
+ goto end;
}
if (!dp->usbpd->hpd_high) {
@@ -757,7 +816,12 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
- rc = dp->ctrl->on(dp->ctrl, dp->hpd_irq_on);
+ if (dp->power_on) {
+ pr_debug("Link already setup, return\n");
+ return 0;
+ }
+
+ rc = dp->ctrl->on(dp->ctrl);
if (!rc)
dp->power_on = true;
error:
@@ -778,8 +842,8 @@
dp = container_of(dp_display, struct dp_display_private, dp_display);
if (dp->audio_supported) {
- dp->audio->bw_code = dp->link->bw_code;
- dp->audio->lane_count = dp->link->lane_count;
+ dp->audio->bw_code = dp->link->link_params.bw_code;
+ dp->audio->lane_count = dp->link->link_params.lane_count;
dp->audio->on(dp->audio);
}
@@ -840,7 +904,7 @@
if (!dp->power_on || !dp->core_initialized)
goto error;
- dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
+ dp->ctrl->off(dp->ctrl);
dp->power_on = false;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 48e6c8f..b62c1e9 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -17,8 +17,6 @@
#include "dp_link.h"
#include "dp_panel.h"
-#define DP_LINK_ENUM_STR(x) #x
-
enum dp_lane_count {
DP_LANE_COUNT_1 = 1,
DP_LANE_COUNT_2 = 2,
@@ -50,48 +48,15 @@
u32 test_requested;
u32 test_link_rate;
u32 test_lane_count;
- u32 phy_test_pattern_sel;
- u32 test_video_pattern;
- u32 test_bit_depth;
- u32 test_dyn_range;
- u32 test_h_total;
- u32 test_v_total;
- u32 test_h_start;
- u32 test_v_start;
- u32 test_hsync_pol;
- u32 test_hsync_width;
- u32 test_vsync_pol;
- u32 test_vsync_width;
- u32 test_h_width;
- u32 test_v_height;
- u32 test_rr_d;
- u32 test_rr_n;
- u32 test_audio_sampling_rate;
- u32 test_audio_channel_count;
- u32 test_audio_pattern_type;
- u32 test_audio_period_ch_1;
- u32 test_audio_period_ch_2;
- u32 test_audio_period_ch_3;
- u32 test_audio_period_ch_4;
- u32 test_audio_period_ch_5;
- u32 test_audio_period_ch_6;
- u32 test_audio_period_ch_7;
- u32 test_audio_period_ch_8;
- u32 response;
-};
-
-struct dp_link_sink_count {
- u32 count;
- bool cp_ready;
};
struct dp_link_private {
+ u32 prev_sink_count;
struct device *dev;
struct dp_aux *aux;
struct dp_link dp_link;
struct dp_link_request request;
- struct dp_link_sink_count sink_count;
u8 link_status[DP_LINK_STATUS_SIZE];
};
@@ -131,30 +96,6 @@
return bpp;
}
-static char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
-{
- switch (phy_test_pattern_sel) {
- case DP_TEST_PHY_PATTERN_NONE:
- return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
- case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
- return DP_LINK_ENUM_STR(
- DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
- case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
- return DP_LINK_ENUM_STR(
- DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
- case DP_TEST_PHY_PATTERN_PRBS7:
- return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
- case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
- return DP_LINK_ENUM_STR(
- DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
- case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
- return DP_LINK_ENUM_STR(
- DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN);
- default:
- return "unknown";
- }
-}
-
static char *dp_link_get_audio_test_pattern(u32 pattern)
{
switch (pattern) {
@@ -223,7 +164,7 @@
static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
{
int ret = 0;
- struct dp_link_request *req = &link->request;
+ struct dp_link_test_audio *req = &link->dp_link.test_audio;
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
if (ret == -EINVAL)
@@ -310,7 +251,7 @@
goto exit;
}
- link->request.test_audio_pattern_type = data;
+ link->dp_link.test_audio.test_audio_pattern_type = data;
pr_debug("audio pattern type = %s\n",
dp_link_get_audio_test_pattern(data));
exit:
@@ -356,8 +297,8 @@
goto exit;
}
- link->request.test_audio_sampling_rate = sampling_rate;
- link->request.test_audio_channel_count = channel_count;
+ link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;
+ link->dp_link.test_audio.test_audio_channel_count = channel_count;
pr_debug("sampling_rate = %s, channel_count = 0x%x\n",
dp_link_get_audio_sample_rate(sampling_rate), channel_count);
exit:
@@ -578,11 +519,11 @@
goto exit;
}
- link->request.test_video_pattern = data;
+ link->dp_link.test_video.test_video_pattern = data;
pr_debug("link video pattern = 0x%x (%s)\n",
- link->request.test_video_pattern,
+ link->dp_link.test_video.test_video_pattern,
dp_link_video_pattern_to_string(
- link->request.test_video_pattern));
+ link->dp_link.test_video.test_video_pattern));
/* Read the requested color bit depth and dynamic range (Byte 0x232) */
rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0,
@@ -601,11 +542,11 @@
ret = -EINVAL;
goto exit;
}
- link->request.test_dyn_range = dyn_range;
+ link->dp_link.test_video.test_dyn_range = dyn_range;
pr_debug("link dynamic range = 0x%x (%s)\n",
- link->request.test_dyn_range,
+ link->dp_link.test_video.test_dyn_range,
dp_link_dynamic_range_to_string(
- link->request.test_dyn_range));
+ link->dp_link.test_video.test_dyn_range));
/* Color bit depth */
data &= DP_TEST_BIT_DEPTH_MASK;
@@ -615,96 +556,104 @@
goto exit;
}
- link->request.test_bit_depth = data;
+ link->dp_link.test_video.test_bit_depth = data;
pr_debug("link bit depth = 0x%x (%s)\n",
- link->request.test_bit_depth,
- dp_link_bit_depth_to_string(link->request.test_bit_depth));
+ link->dp_link.test_video.test_bit_depth,
+ dp_link_bit_depth_to_string(
+ link->dp_link.test_video.test_bit_depth));
/* resolution timing params */
ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
- &link->request.test_h_total);
+ &link->dp_link.test_video.test_h_total);
if (ret) {
pr_err("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n");
goto exit;
}
- pr_debug("TEST_H_TOTAL = %d\n", link->request.test_h_total);
+ pr_debug("TEST_H_TOTAL = %d\n", link->dp_link.test_video.test_h_total);
ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
- &link->request.test_v_total);
+ &link->dp_link.test_video.test_v_total);
if (ret) {
pr_err("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n");
goto exit;
}
- pr_debug("TEST_V_TOTAL = %d\n", link->request.test_v_total);
+ pr_debug("TEST_V_TOTAL = %d\n", link->dp_link.test_video.test_v_total);
ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
- &link->request.test_h_start);
+ &link->dp_link.test_video.test_h_start);
if (ret) {
pr_err("failed to parse test_h_start (DP_TEST_H_START_HI)\n");
goto exit;
}
- pr_debug("TEST_H_START = %d\n", link->request.test_h_start);
+ pr_debug("TEST_H_START = %d\n", link->dp_link.test_video.test_h_start);
ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
- &link->request.test_v_start);
+ &link->dp_link.test_video.test_v_start);
if (ret) {
pr_err("failed to parse test_v_start (DP_TEST_V_START_HI)\n");
goto exit;
}
- pr_debug("TEST_V_START = %d\n", link->request.test_v_start);
+ pr_debug("TEST_V_START = %d\n", link->dp_link.test_video.test_v_start);
ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
- &link->request.test_hsync_pol,
- &link->request.test_hsync_width);
+ &link->dp_link.test_video.test_hsync_pol,
+ &link->dp_link.test_video.test_hsync_width);
if (ret) {
pr_err("failed to parse (DP_TEST_HSYNC_HI)\n");
goto exit;
}
- pr_debug("TEST_HSYNC_POL = %d\n", link->request.test_hsync_pol);
- pr_debug("TEST_HSYNC_WIDTH = %d\n", link->request.test_hsync_width);
+ pr_debug("TEST_HSYNC_POL = %d\n",
+ link->dp_link.test_video.test_hsync_pol);
+ pr_debug("TEST_HSYNC_WIDTH = %d\n",
+ link->dp_link.test_video.test_hsync_width);
ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
- &link->request.test_vsync_pol,
- &link->request.test_vsync_width);
+ &link->dp_link.test_video.test_vsync_pol,
+ &link->dp_link.test_video.test_vsync_width);
if (ret) {
pr_err("failed to parse (DP_TEST_VSYNC_HI)\n");
goto exit;
}
- pr_debug("TEST_VSYNC_POL = %d\n", link->request.test_vsync_pol);
- pr_debug("TEST_VSYNC_WIDTH = %d\n", link->request.test_vsync_width);
+ pr_debug("TEST_VSYNC_POL = %d\n",
+ link->dp_link.test_video.test_vsync_pol);
+ pr_debug("TEST_VSYNC_WIDTH = %d\n",
+ link->dp_link.test_video.test_vsync_width);
ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
- &link->request.test_h_width);
+ &link->dp_link.test_video.test_h_width);
if (ret) {
pr_err("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n");
goto exit;
}
- pr_debug("TEST_H_WIDTH = %d\n", link->request.test_h_width);
+ pr_debug("TEST_H_WIDTH = %d\n", link->dp_link.test_video.test_h_width);
ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
- &link->request.test_v_height);
+ &link->dp_link.test_video.test_v_height);
if (ret) {
pr_err("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n");
goto exit;
}
- pr_debug("TEST_V_HEIGHT = %d\n", link->request.test_v_height);
+ pr_debug("TEST_V_HEIGHT = %d\n",
+ link->dp_link.test_video.test_v_height);
ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
- &link->request.test_rr_d);
- link->request.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
+ &link->dp_link.test_video.test_rr_d);
+ link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
if (ret) {
pr_err("failed to parse test_rr_d (DP_TEST_MISC1)\n");
goto exit;
}
- pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", link->request.test_rr_d);
+ pr_debug("TEST_REFRESH_DENOMINATOR = %d\n",
+ link->dp_link.test_video.test_rr_d);
ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
- &link->request.test_rr_n);
+ &link->dp_link.test_video.test_rr_n);
if (ret) {
pr_err("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n");
goto exit;
}
- pr_debug("TEST_REFRESH_NUMERATOR = %d\n", link->request.test_rr_n);
+ pr_debug("TEST_REFRESH_NUMERATOR = %d\n",
+ link->dp_link.test_video.test_rr_n);
exit:
return ret;
}
@@ -720,7 +669,7 @@
return ((bw_code == DP_LINK_BW_1_62) ||
(bw_code == DP_LINK_BW_2_7) ||
(bw_code == DP_LINK_BW_5_4) ||
- (bw_code == DP_LINK_RATE_810));
+ (bw_code == DP_LINK_BW_8_1));
}
/**
@@ -832,7 +781,7 @@
data = bp;
- link->request.phy_test_pattern_sel = data;
+ link->dp_link.phy_params.phy_test_pattern_sel = data;
pr_debug("phy_test_pattern_sel = %s\n",
dp_link_get_phy_test_pattern(data));
@@ -891,6 +840,11 @@
dp_link_is_video_audio_test_requested(test_requested);
}
+static bool dp_link_is_test_edid_read(struct dp_link_private *link)
+{
+ return (link->request.test_requested == DP_TEST_LINK_EDID_READ);
+}
+
/**
* dp_sink_parse_test_request() - parses link request parameters from sink
* @link: Display Port Driver data
@@ -972,10 +926,15 @@
* Send a DP_TEST_ACK if all link parameters are valid, otherwise send
* a DP_TEST_NAK.
*/
- if (ret)
- link->request.response = DP_TEST_NAK;
- else
- link->request.response = DP_TEST_ACK;
+ if (ret) {
+ link->dp_link.test_response = DP_TEST_NAK;
+ } else {
+ if (!dp_link_is_test_edid_read(link))
+ link->dp_link.test_response = DP_TEST_ACK;
+ else
+ link->dp_link.test_response =
+ DP_TEST_EDID_CHECKSUM_WRITE;
+ }
return ret;
}
@@ -987,46 +946,49 @@
* (Byte 0x200), and whether all the sink devices connected have Content
* Protection enabled.
*/
-static void dp_link_parse_sink_count(struct dp_link_private *link)
+static int dp_link_parse_sink_count(struct dp_link *dp_link)
{
- u8 bp;
- u8 data;
int rlen;
int const param_len = 0x1;
+ struct dp_link_private *link = container_of(dp_link,
+ struct dp_link_private, dp_link);
rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT,
- &bp, param_len);
+ &link->dp_link.sink_count.count, param_len);
if (rlen < param_len) {
pr_err("failed to read sink count\n");
- return;
+ return -EINVAL;
}
- data = bp;
-
+ link->dp_link.sink_count.cp_ready =
+ link->dp_link.sink_count.count & DP_SINK_CP_READY;
/* BIT 7, BIT 5:0 */
- link->sink_count.count = (data & BIT(7)) << 6 | (data & 0x63);
- /* BIT 6*/
- link->sink_count.cp_ready = data & BIT(6);
+ link->dp_link.sink_count.count =
+ DP_GET_SINK_COUNT(link->dp_link.sink_count.count);
pr_debug("sink_count = 0x%x, cp_ready = 0x%x\n",
- link->sink_count.count, link->sink_count.cp_ready);
+ link->dp_link.sink_count.count,
+ link->dp_link.sink_count.cp_ready);
+ return 0;
}
static void dp_link_parse_sink_status_field(struct dp_link_private *link)
{
int len = 0;
- dp_link_parse_sink_count(link);
- dp_link_parse_request(link);
+ link->prev_sink_count = link->dp_link.sink_count.count;
+ dp_link_parse_sink_count(&link->dp_link);
+
len = drm_dp_dpcd_read_link_status(link->aux->drm_aux,
link->link_status);
if (len < DP_LINK_STATUS_SIZE)
pr_err("DP link status read failed\n");
+ dp_link_parse_request(link);
}
static bool dp_link_is_link_training_requested(struct dp_link_private *link)
{
- return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
+ return (link->request.test_requested == DP_TEST_LINK_TRAINING);
}
/**
@@ -1046,24 +1008,34 @@
return -EINVAL;
pr_debug("%s link rate = 0x%x, lane count = 0x%x\n",
- dp_link_get_test_name(DP_TEST_LINK_PHY_TEST_PATTERN),
+ dp_link_get_test_name(DP_TEST_LINK_TRAINING),
link->request.test_link_rate,
link->request.test_lane_count);
- link->dp_link.lane_count = link->request.test_lane_count;
- link->dp_link.bw_code = link->request.test_link_rate;
+ link->dp_link.link_params.lane_count = link->request.test_lane_count;
+ link->dp_link.link_params.bw_code = link->request.test_link_rate;
return 0;
}
-static bool dp_link_phy_pattern_requested(struct dp_link *dp_link)
+static void dp_link_send_test_response(struct dp_link *dp_link)
{
- struct dp_link_private *link = container_of(dp_link,
- struct dp_link_private, dp_link);
+ struct dp_link_private *link = NULL;
+ u32 const test_response_addr = 0x260;
+ u32 const response_len = 0x1;
- return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
+ if (!dp_link) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ link = container_of(dp_link, struct dp_link_private, dp_link);
+
+ drm_dp_dpcd_write(link->aux->drm_aux, test_response_addr,
+ &dp_link->test_response, response_len);
}
+
static int dp_link_parse_vx_px(struct dp_link_private *link)
{
u8 bp;
@@ -1127,10 +1099,11 @@
* vector.
*/
pr_debug("Current: v_level = 0x%x, p_level = 0x%x\n",
- link->dp_link.v_level, link->dp_link.p_level);
+ link->dp_link.phy_params.v_level,
+ link->dp_link.phy_params.p_level);
pr_debug("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0);
- link->dp_link.v_level = v0;
- link->dp_link.p_level = p0;
+ link->dp_link.phy_params.v_level = v0;
+ link->dp_link.phy_params.p_level = p0;
pr_debug("Success\n");
end:
@@ -1150,8 +1123,10 @@
{
u32 test_link_rate = 0, test_lane_count = 0;
- if (!dp_link_phy_pattern_requested(&link->dp_link))
+ if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {
+ pr_debug("no phy test\n");
return -EINVAL;
+ }
test_link_rate = link->request.test_link_rate;
test_lane_count = link->request.test_lane_count;
@@ -1165,8 +1140,15 @@
pr_debug("start\n");
- link->dp_link.lane_count = link->request.test_lane_count;
- link->dp_link.bw_code = link->request.test_link_rate;
+ pr_info("Current: bw_code = 0x%x, lane count = 0x%x\n",
+ link->dp_link.link_params.bw_code,
+ link->dp_link.link_params.lane_count);
+
+ pr_info("Requested: bw_code = 0x%x, lane count = 0x%x\n",
+ test_link_rate, test_lane_count);
+
+ link->dp_link.link_params.lane_count = link->request.test_lane_count;
+ link->dp_link.link_params.bw_code = link->request.test_link_rate;
dp_link_parse_vx_px(link);
@@ -1196,16 +1178,16 @@
if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
DP_LINK_STATUS_UPDATED) || /* link status updated */
(drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.lane_count) &&
+ link->dp_link.link_params.lane_count) &&
drm_dp_channel_eq_ok(link->link_status,
- link->dp_link.lane_count)))
+ link->dp_link.link_params.lane_count)))
return -EINVAL;
pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n",
drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.lane_count),
+ link->dp_link.link_params.lane_count),
drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.lane_count));
+ link->dp_link.link_params.lane_count));
return 0;
}
@@ -1216,6 +1198,9 @@
DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */
return true;
+ if (link->prev_sink_count != link->dp_link.sink_count.count)
+ return true;
+
return false;
}
@@ -1235,6 +1220,9 @@
if (!dp_link_is_ds_port_status_changed(link))
return -EINVAL;
+ /* reset prev_sink_count */
+ link->prev_sink_count = link->dp_link.sink_count.count;
+
return 0;
}
@@ -1267,10 +1255,11 @@
pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n",
dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN),
- link->request.test_bit_depth,
- dp_link_bit_depth_to_bpp(link->request.test_bit_depth),
+ link->dp_link.test_video.test_bit_depth,
+ dp_link_bit_depth_to_bpp(
+ link->dp_link.test_video.test_bit_depth),
dp_link_video_pattern_to_string(
- link->request.test_video_pattern));
+ link->dp_link.test_video.test_video_pattern));
return 0;
end:
@@ -1293,22 +1282,22 @@
pr_debug("sampling_rate=%s, channel_count=%d, pattern_type=%s\n",
dp_link_get_audio_sample_rate(
- link->request.test_audio_sampling_rate),
- link->request.test_audio_channel_count,
+ link->dp_link.test_audio.test_audio_sampling_rate),
+ link->dp_link.test_audio.test_audio_channel_count,
dp_link_get_audio_test_pattern(
- link->request.test_audio_pattern_type));
+ link->dp_link.test_audio.test_audio_pattern_type));
pr_debug("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n",
- link->request.test_audio_period_ch_1,
- link->request.test_audio_period_ch_2,
- link->request.test_audio_period_ch_3,
- link->request.test_audio_period_ch_4);
+ link->dp_link.test_audio.test_audio_period_ch_1,
+ link->dp_link.test_audio.test_audio_period_ch_2,
+ link->dp_link.test_audio.test_audio_period_ch_3,
+ link->dp_link.test_audio.test_audio_period_ch_4);
pr_debug("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n",
- link->request.test_audio_period_ch_5,
- link->request.test_audio_period_ch_6,
- link->request.test_audio_period_ch_7,
- link->request.test_audio_period_ch_8);
+ link->dp_link.test_audio.test_audio_period_ch_5,
+ link->dp_link.test_audio.test_audio_period_ch_6,
+ link->dp_link.test_audio.test_audio_period_ch_7,
+ link->dp_link.test_audio.test_audio_period_ch_8);
return 0;
}
@@ -1316,8 +1305,12 @@
static void dp_link_reset_data(struct dp_link_private *link)
{
link->request = (const struct dp_link_request){ 0 };
- link->request.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
- link->dp_link.test_requested = 0;
+ link->dp_link.test_video = (const struct dp_link_test_video){ 0 };
+ link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
+ link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 };
+ link->dp_link.phy_params.phy_test_pattern_sel = 0;
+ link->dp_link.sink_request = 0;
+ link->dp_link.test_response = 0;
}
/**
@@ -1346,39 +1339,44 @@
dp_link_parse_sink_status_field(link);
- ret = dp_link_process_link_training_request(link);
- if (!ret) {
- dp_link->test_requested |= DP_TEST_LINK_TRAINING;
- goto exit;
- }
-
- ret = dp_link_process_phy_test_pattern_request(link);
- if (!ret) {
- dp_link->test_requested |= DP_TEST_LINK_PHY_TEST_PATTERN;
- goto exit;
- }
-
- ret = dp_link_process_link_status_update(link);
- if (!ret) {
- dp_link->test_requested |= DP_LINK_STATUS_UPDATED;
+ if (dp_link_is_test_edid_read(link)) {
+ dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
goto exit;
}
ret = dp_link_process_ds_port_status_change(link);
if (!ret) {
- dp_link->test_requested |= DS_PORT_STATUS_CHANGED;
+ dp_link->sink_request |= DS_PORT_STATUS_CHANGED;
+ goto exit;
+ }
+
+ ret = dp_link_process_link_training_request(link);
+ if (!ret) {
+ dp_link->sink_request |= DP_TEST_LINK_TRAINING;
+ goto exit;
+ }
+
+ ret = dp_link_process_phy_test_pattern_request(link);
+ if (!ret) {
+ dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN;
+ goto exit;
+ }
+
+ ret = dp_link_process_link_status_update(link);
+ if (!ret) {
+ dp_link->sink_request |= DP_LINK_STATUS_UPDATED;
goto exit;
}
ret = dp_link_process_video_pattern_request(link);
if (!ret) {
- dp_link->test_requested |= DP_TEST_LINK_VIDEO_PATTERN;
+ dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN;
goto exit;
}
ret = dp_link_process_audio_pattern_request(link);
if (!ret) {
- dp_link->test_requested |= DP_TEST_LINK_AUDIO_PATTERN;
+ dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN;
goto exit;
}
@@ -1402,7 +1400,7 @@
/* unless a video pattern CTS test is ongoing, use CEA_VESA */
if (dp_link_is_video_pattern_requested(link))
- dr = link->request.test_dyn_range;
+ dr = link->dp_link.test_video.test_dyn_range;
else
dr = DP_DYNAMIC_RANGE_RGB_VESA;
@@ -1434,51 +1432,52 @@
link = container_of(dp_link, struct dp_link_private, dp_link);
/* use the max level across lanes */
- for (i = 0; i < dp_link->lane_count; i++) {
+ for (i = 0; i < dp_link->link_params.lane_count; i++) {
data = drm_dp_get_adjust_request_voltage(link_status, i);
pr_debug("lane=%d req_voltage_swing=%d\n", i, data);
if (max < data)
max = data;
}
- dp_link->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+ dp_link->phy_params.v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
/* use the max level across lanes */
max = 0;
- for (i = 0; i < dp_link->lane_count; i++) {
+ for (i = 0; i < dp_link->link_params.lane_count; i++) {
data = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
pr_debug("lane=%d req_pre_emphasis=%d\n", i, data);
if (max < data)
max = data;
}
- dp_link->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+ dp_link->phy_params.p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
/**
* Adjust the voltage swing and pre-emphasis level combination to within
* the allowable range.
*/
- if (dp_link->v_level > DP_LINK_VOLTAGE_MAX) {
+ if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) {
pr_debug("Requested vSwingLevel=%d, change to %d\n",
- dp_link->v_level, DP_LINK_VOLTAGE_MAX);
- dp_link->v_level = DP_LINK_VOLTAGE_MAX;
+ dp_link->phy_params.v_level, DP_LINK_VOLTAGE_MAX);
+ dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX;
}
- if (dp_link->p_level > DP_LINK_PRE_EMPHASIS_MAX) {
+ if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) {
pr_debug("Requested preEmphasisLevel=%d, change to %d\n",
- dp_link->p_level, DP_LINK_PRE_EMPHASIS_MAX);
- dp_link->p_level = DP_LINK_PRE_EMPHASIS_MAX;
+ dp_link->phy_params.p_level, DP_LINK_PRE_EMPHASIS_MAX);
+ dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX;
}
- if ((dp_link->p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1)
- && (dp_link->v_level == DP_LINK_VOLTAGE_LEVEL_2)) {
+ if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1)
+ && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) {
pr_debug("Requested preEmphasisLevel=%d, change to %d\n",
- dp_link->p_level, DP_LINK_PRE_EMPHASIS_LEVEL_1);
- dp_link->p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
+ dp_link->phy_params.p_level,
+ DP_LINK_PRE_EMPHASIS_LEVEL_1);
+ dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
}
pr_debug("adjusted: v_level=%d, p_level=%d\n",
- dp_link->v_level, dp_link->p_level);
+ dp_link->phy_params.v_level, dp_link->phy_params.p_level);
return 0;
}
@@ -1555,7 +1554,7 @@
dp_link->get_colorimetry_config = dp_link_get_colorimetry_config;
dp_link->adjust_levels = dp_link_adjust_levels;
dp_link->send_psm_request = dp_link_send_psm_request;
- dp_link->phy_pattern_requested = dp_link_phy_pattern_requested;
+ dp_link->send_test_response = dp_link_send_test_response;
return dp_link;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 419186f..9a5b75a 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -17,6 +17,10 @@
#include "dp_aux.h"
+#define DS_PORT_STATUS_CHANGED 0x200
+#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
+#define DP_LINK_ENUM_STR(x) #x
+
enum dp_link_voltage_level {
DP_LINK_VOLTAGE_LEVEL_0 = 0,
DP_LINK_VOLTAGE_LEVEL_1 = 1,
@@ -31,25 +35,96 @@
DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_2,
};
-#define DS_PORT_STATUS_CHANGED 0x200
-#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
+struct dp_link_sink_count {
+ u32 count;
+ bool cp_ready;
+};
-struct dp_link {
- u32 test_requested;
+struct dp_link_test_video {
+ u32 test_video_pattern;
+ u32 test_bit_depth;
+ u32 test_dyn_range;
+ u32 test_h_total;
+ u32 test_v_total;
+ u32 test_h_start;
+ u32 test_v_start;
+ u32 test_hsync_pol;
+ u32 test_hsync_width;
+ u32 test_vsync_pol;
+ u32 test_vsync_width;
+ u32 test_h_width;
+ u32 test_v_height;
+ u32 test_rr_d;
+ u32 test_rr_n;
+};
+struct dp_link_test_audio {
+ u32 test_audio_sampling_rate;
+ u32 test_audio_channel_count;
+ u32 test_audio_pattern_type;
+ u32 test_audio_period_ch_1;
+ u32 test_audio_period_ch_2;
+ u32 test_audio_period_ch_3;
+ u32 test_audio_period_ch_4;
+ u32 test_audio_period_ch_5;
+ u32 test_audio_period_ch_6;
+ u32 test_audio_period_ch_7;
+ u32 test_audio_period_ch_8;
+};
+
+struct dp_link_phy_params {
+ u32 phy_test_pattern_sel;
+ u8 v_level;
+ u8 p_level;
+};
+
+struct dp_link_params {
u32 lane_count;
u32 bw_code;
- u32 v_level;
- u32 p_level;
+};
+
+struct dp_link {
+ u32 sink_request;
+ u32 test_response;
+
+ struct dp_link_sink_count sink_count;
+ struct dp_link_test_video test_video;
+ struct dp_link_test_audio test_audio;
+ struct dp_link_phy_params phy_params;
+ struct dp_link_params link_params;
u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
int (*process_request)(struct dp_link *dp_link);
int (*get_colorimetry_config)(struct dp_link *dp_link);
int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status);
int (*send_psm_request)(struct dp_link *dp_link, bool req);
- bool (*phy_pattern_requested)(struct dp_link *dp_link);
+ void (*send_test_response)(struct dp_link *dp_link);
};
+static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
+{
+ switch (phy_test_pattern_sel) {
+ case DP_TEST_PHY_PATTERN_NONE:
+ return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
+ case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
+ case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
+ case DP_TEST_PHY_PATTERN_PRBS7:
+ return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
+ case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
+ case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
+ return DP_LINK_ENUM_STR(
+ DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN);
+ default:
+ return "unknown";
+ }
+}
+
/**
* dp_link_get() - get the functionalities of dp test module
*
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 2e21033..56b2d37 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -17,6 +17,7 @@
#include "dp_panel.h"
#define DP_PANEL_DEFAULT_BPP 24
+#define DP_MAX_DS_PORT_COUNT 1
enum {
DP_LINK_RATE_MULTIPLIER = 27000000,
@@ -27,7 +28,6 @@
struct dp_panel dp_panel;
struct dp_aux *aux;
struct dp_catalog_panel *catalog;
- bool lane_switch_supported;
bool aux_cfg_update_done;
};
@@ -36,7 +36,8 @@
int rlen, rc = 0;
struct dp_panel_private *panel;
struct drm_dp_link *link_info;
- u8 major = 0, minor = 0;
+ u8 *dpcd, major = 0, minor = 0;
+ u32 dfp_count = 0;
unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING;
if (!dp_panel) {
@@ -45,11 +46,13 @@
goto end;
}
+ dpcd = dp_panel->dpcd;
+
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
link_info = &dp_panel->link_info;
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
- dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
+ dpcd, (DP_RECEIVER_CAP_SIZE + 1));
if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
pr_err("dpcd read failed, rlen=%d\n", rlen);
rc = -EINVAL;
@@ -66,17 +69,33 @@
drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
pr_debug("link_rate=%d\n", link_info->rate);
- if (panel->lane_switch_supported)
- link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
- DP_MAX_LANE_COUNT_MASK;
- else
- link_info->num_lanes = 2;
+ link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
+ DP_MAX_LANE_COUNT_MASK;
pr_debug("lane_count=%d\n", link_info->num_lanes);
- if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
+ if (drm_dp_enhanced_frame_cap(dpcd))
link_info->capabilities |= caps;
+ dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] &
+ DP_DOWN_STREAM_PORT_COUNT;
+
+ if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)
+ && (dpcd[DP_DPCD_REV] > 0x10)) {
+ rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
+ DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports,
+ DP_MAX_DOWNSTREAM_PORTS);
+ if (rlen < DP_MAX_DOWNSTREAM_PORTS) {
+ pr_err("ds port status failed, rlen=%d\n", rlen);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+
+ if (dfp_count > DP_MAX_DS_PORT_COUNT)
+ pr_debug("DS port count %d greater that max (%d) supported\n",
+ dfp_count, DP_MAX_DS_PORT_COUNT);
+
end:
return rc;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index ab9a451..a94f4b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -18,7 +18,7 @@
#include "dp_aux.h"
#include "sde_edid_parser.h"
-#define DP_LINK_RATE_810 30 /* 8.10G = 270M * 30 */
+#define DP_MAX_DOWNSTREAM_PORTS 0x10
struct dp_panel_info {
u32 h_active;
@@ -40,8 +40,9 @@
struct dp_panel {
/* dpcd raw data */
u8 dpcd[DP_RECEIVER_CAP_SIZE];
- struct drm_dp_link link_info;
+ u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS];
+ struct drm_dp_link link_info;
struct sde_edid_ctrl *edid_ctrl;
struct drm_connector *connector;
struct dp_panel_info pinfo;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index c85c2a2..c8da99a 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -22,22 +22,15 @@
{
struct dp_io *io = &parser->io;
- if (&io->ctrl_io)
- msm_dss_iounmap(&io->ctrl_io);
- if (&io->phy_io)
- msm_dss_iounmap(&io->phy_io);
- if (&io->ln_tx0_io)
- msm_dss_iounmap(&io->ln_tx0_io);
- if (&io->ln_tx1_io)
- msm_dss_iounmap(&io->ln_tx0_io);
- if (&io->dp_pll_io)
- msm_dss_iounmap(&io->dp_pll_io);
- if (&io->dp_cc_io)
- msm_dss_iounmap(&io->dp_cc_io);
- if (&io->qfprom_io)
- msm_dss_iounmap(&io->qfprom_io);
- if (&io->hdcp_io)
- msm_dss_iounmap(&io->hdcp_io);
+ msm_dss_iounmap(&io->ctrl_io);
+ msm_dss_iounmap(&io->phy_io);
+ msm_dss_iounmap(&io->ln_tx0_io);
+ msm_dss_iounmap(&io->ln_tx0_io);
+ msm_dss_iounmap(&io->dp_pll_io);
+ msm_dss_iounmap(&io->dp_cc_io);
+ msm_dss_iounmap(&io->usb3_dp_com);
+ msm_dss_iounmap(&io->qfprom_io);
+ msm_dss_iounmap(&io->hdcp_io);
}
static int dp_parser_ctrl_res(struct dp_parser *parser)
@@ -84,6 +77,12 @@
goto err;
}
+ rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com");
+ if (rc) {
+ pr_err("unable to remap USB3 DP com resources\n");
+ goto err;
+ }
+
if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
pr_err("unable to remap dp MMSS_CC resources\n");
goto err;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index 7794da5..76a72a2 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -65,6 +65,7 @@
* @dp_cc_io: DP cc's mapped memory address
* @qfprom_io: qfprom's mapped memory address
* @dp_pll_io: DP PLL mapped memory address
+ * @usb3_dp_com: USB3 DP PHY combo mapped memory address
* @hdcp_io: hdcp's mapped memory address
*/
struct dp_io {
@@ -75,6 +76,7 @@
struct dss_io_data dp_cc_io;
struct dss_io_data qfprom_io;
struct dss_io_data dp_pll_io;
+ struct dss_io_data usb3_dp_com;
struct dss_io_data hdcp_io;
};
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 30377a0..5aaad24 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -79,6 +79,8 @@
#define MMSS_DP_PSR_CRC_RG (0x00000554)
#define MMSS_DP_PSR_CRC_B (0x00000558)
+#define DP_COMPRESSION_MODE_CTRL (0x00000580)
+
#define MMSS_DP_AUDIO_CFG (0x00000600)
#define MMSS_DP_AUDIO_STATUS (0x00000604)
#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608)
@@ -141,6 +143,17 @@
#define MMSS_DP_GENERIC1_8 (0x00000748)
#define MMSS_DP_GENERIC1_9 (0x0000074C)
+#define MMSS_DP_VSCEXT_0 (0x000006D0)
+#define MMSS_DP_VSCEXT_1 (0x000006D4)
+#define MMSS_DP_VSCEXT_2 (0x000006D8)
+#define MMSS_DP_VSCEXT_3 (0x000006DC)
+#define MMSS_DP_VSCEXT_4 (0x000006E0)
+#define MMSS_DP_VSCEXT_5 (0x000006E4)
+#define MMSS_DP_VSCEXT_6 (0x000006E8)
+#define MMSS_DP_VSCEXT_7 (0x000006EC)
+#define MMSS_DP_VSCEXT_8 (0x000006F0)
+#define MMSS_DP_VSCEXT_9 (0x000006F4)
+
#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10)
#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88)
@@ -205,4 +218,14 @@
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
+/* USB3 DP COM registers */
+#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C)
+#define USB3_DP_COM_PHY_MODE_CTRL (0x00)
+#define USB3_DP_COM_SW_RESET (0x04)
+#define USB3_DP_COM_TYPEC_CTRL (0x10)
+#define USB3_DP_COM_SWI_CTRL (0x0c)
+#define USB3_DP_COM_POWER_DOWN_CTRL (0x08)
+
+
+
#endif /* _DP_REG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index bd7a66e..c0bcdda 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -377,6 +377,18 @@
pd->dp_usbpd.orientation = usbpd_get_plug_orientation(pd->pd);
+ /*
+ * By default, USB reserves two lanes for Super Speed.
+ * Which means DP has remaining two lanes to operate on.
+ * If multi-function is not supported, request USB to
+ * release the Super Speed lanes so that DP can use
+ * all four lanes in case DPCD indicates support for
+ * four lanes.
+ */
+ if (!pd->dp_usbpd.multi_func)
+ pd->svid_handler.request_usb_ss_lane(pd->pd,
+ &pd->svid_handler);
+
if (pd->dp_cb && pd->dp_cb->configure)
pd->dp_cb->configure(pd->dev);
break;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index dcde566..4756bf6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1193,7 +1193,9 @@
msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, aspace);
+ mutex_lock(&dsi_ctrl->drm_dev->struct_mutex);
msm_gem_free_object(dsi_ctrl->tx_cmd_buf);
+ mutex_unlock(&dsi_ctrl->drm_dev->struct_mutex);
dsi_ctrl->tx_cmd_buf = NULL;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index aa81d55..5c22e65 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -84,6 +84,10 @@
return -EINVAL;
panel = dsi_display->panel;
+
+ if (!dsi_panel_initialized(panel))
+ return -EINVAL;
+
panel->bl_config.bl_level = bl_lvl;
/* scale backlight */
@@ -1708,7 +1712,9 @@
put_iova:
msm_gem_put_iova(display->tx_cmd_buf, aspace);
free_gem:
+ mutex_lock(&display->drm_dev->struct_mutex);
msm_gem_free_object(display->tx_cmd_buf);
+ mutex_unlock(&display->drm_dev->struct_mutex);
error:
return rc;
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index b829460..f8c3df5 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -311,8 +311,7 @@
}
}
-static void
-put_iova(struct drm_gem_object *obj)
+static void put_iova(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -324,12 +323,14 @@
if (iommu_present(&platform_bus_type)) {
msm_gem_unmap_vma(domain->aspace, domain,
msm_obj->sgt, get_dmabuf_ptr(obj));
-
- msm_gem_remove_obj_from_aspace_active_list(
- domain->aspace,
- obj);
}
+ /*
+ * put_iova removes the domain connected to the obj which makes
+ * the aspace inaccessible. Store the aspace, as it is used to
+ * update the active_list during gem_free_obj and gem_purege.
+ */
+ msm_obj->aspace = domain->aspace;
obj_remove_domain(domain);
}
}
@@ -409,7 +410,8 @@
if (!ret && domain) {
*iova = domain->iova;
- msm_gem_add_obj_to_aspace_active_list(aspace, obj);
+ if (aspace && aspace->domain_attached)
+ msm_gem_add_obj_to_aspace_active_list(aspace, obj);
} else {
obj_remove_domain(domain);
}
@@ -485,24 +487,21 @@
/**
* Unmap active buffers,
* typically clients should do this when the callback is called,
- * but this needs to be done for the framebuffers which are not
- * attached to any planes. (background apps)
+ * but this needs to be done for the buffers which are not
+ * attached to any planes.
*/
list_for_each_entry(msm_obj, &aspace->active_list, iova_list) {
obj = &msm_obj->base;
- if (obj->import_attach) {
+ if (obj->import_attach)
put_iova(obj);
- put_pages(obj);
- }
}
} else {
/* map active buffers */
- list_for_each_entry(msm_obj, &aspace->active_list,
- iova_list) {
+ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) {
obj = &msm_obj->base;
ret = msm_gem_get_iova_locked(obj, aspace, &iova);
if (ret) {
- mutex_unlock(&obj->dev->struct_mutex);
+ mutex_unlock(&aspace->dev->struct_mutex);
return;
}
}
@@ -613,6 +612,7 @@
WARN_ON(obj->import_attach);
put_iova(obj);
+ msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, obj);
msm_gem_vunmap(obj);
@@ -841,6 +841,7 @@
list_del(&msm_obj->mm_list);
put_iova(obj);
+ msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, obj);
if (obj->import_attach) {
if (msm_obj->vaddr)
@@ -913,6 +914,8 @@
return -EINVAL;
}
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
if (!iommu_present(&platform_bus_type))
use_vram = true;
else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
@@ -946,6 +949,7 @@
INIT_LIST_HEAD(&msm_obj->submit_entry);
INIT_LIST_HEAD(&msm_obj->domains);
INIT_LIST_HEAD(&msm_obj->iova_list);
+ msm_obj->aspace = NULL;
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
@@ -987,7 +991,7 @@
struct dma_buf *dmabuf, struct sg_table *sgt)
{
struct msm_gem_object *msm_obj;
- struct drm_gem_object *obj;
+ struct drm_gem_object *obj = NULL;
uint32_t size;
int ret, npages;
@@ -999,7 +1003,12 @@
size = PAGE_ALIGN(dmabuf->size);
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ERR_PTR(ret);
+
ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj);
+ mutex_unlock(&dev->struct_mutex);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index c50c453..8521bea 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -122,6 +122,8 @@
*/
struct drm_mm_node *vram_node;
struct list_head iova_list;
+
+ struct msm_gem_address_space *aspace;
};
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 7243fe2..9ddca8c 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -722,6 +722,12 @@
(u32 *)&catalog->perf.max_bw_low);
debugfs_create_u32("threshold_high", 0600, perf->debugfs_root,
(u32 *)&catalog->perf.max_bw_high);
+ debugfs_create_u32("min_core_ib", 0600, perf->debugfs_root,
+ (u32 *)&catalog->perf.min_core_ib);
+ debugfs_create_u32("min_llcc_ib", 0600, perf->debugfs_root,
+ (u32 *)&catalog->perf.min_llcc_ib);
+ debugfs_create_u32("min_dram_ib", 0600, perf->debugfs_root,
+ (u32 *)&catalog->perf.min_dram_ib);
debugfs_create_file("perf_mode", 0600, perf->debugfs_root,
(u32 *)perf, &sde_core_perf_mode_fops);
debugfs_create_u32("bw_vote_mode", 0600, perf->debugfs_root,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 387f08d..efbbd24 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1263,7 +1263,7 @@
struct sde_hw_stage_cfg *stage_cfg;
struct sde_rect plane_crtc_roi;
- u32 flush_mask, flush_sbuf, flush_tmp;
+ u32 flush_mask, flush_sbuf;
uint32_t stage_idx, lm_idx;
int zpos_cnt[SDE_STAGE_MAX + 1] = { 0 };
int i;
@@ -1279,10 +1279,9 @@
lm = mixer->hw_lm;
stage_cfg = &sde_crtc->stage_cfg;
cstate = to_sde_crtc_state(crtc->state);
- flush_sbuf = 0x0;
- cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
cstate->sbuf_prefill_line = 0;
+ sde_crtc->sbuf_flush_mask = 0x0;
drm_atomic_crtc_for_each_plane(plane, crtc) {
state = plane->state;
@@ -1297,17 +1296,14 @@
pstate = to_sde_plane_state(state);
fb = state->fb;
- if (sde_plane_is_sbuf_mode(plane, &prefill))
- cstate->sbuf_cfg.rot_op_mode =
- SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
+ prefill = sde_plane_rot_calc_prefill(plane);
if (prefill > cstate->sbuf_prefill_line)
cstate->sbuf_prefill_line = prefill;
- sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_tmp);
+ sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_sbuf);
- /* persist rotator flush bit(s) for one more commit */
- flush_mask |= cstate->sbuf_flush_mask | flush_tmp;
- flush_sbuf |= flush_tmp;
+ /* save sbuf flush value for later */
+ sde_crtc->sbuf_flush_mask |= flush_sbuf;
SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
crtc->base.id,
@@ -1331,8 +1327,7 @@
state->src_w >> 16, state->src_h >> 16,
state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h,
- flush_tmp ? cstate->sbuf_cfg.rot_op_mode :
- SDE_CTL_ROT_OP_MODE_OFFLINE);
+ flush_sbuf != 0);
stage_idx = zpos_cnt[pstate->stage]++;
stage_cfg->stage[pstate->stage][stage_idx] =
@@ -1359,8 +1354,6 @@
}
}
- cstate->sbuf_flush_mask = flush_sbuf;
-
if (lm && lm->ops.setup_dim_layer) {
cstate = to_sde_crtc_state(crtc->state);
for (i = 0; i < cstate->num_dim_layers; i++)
@@ -1524,7 +1517,6 @@
static int _sde_crtc_find_plane_fb_modes(struct drm_crtc_state *state,
uint32_t *fb_ns,
uint32_t *fb_sec,
- uint32_t *fb_ns_dir,
uint32_t *fb_sec_dir)
{
struct drm_plane *plane;
@@ -1540,7 +1532,6 @@
*fb_ns = 0;
*fb_sec = 0;
- *fb_ns_dir = 0;
*fb_sec_dir = 0;
drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
if (IS_ERR_OR_NULL(pstate)) {
@@ -1560,16 +1551,12 @@
case SDE_DRM_FB_SEC:
(*fb_sec)++;
break;
- case SDE_DRM_FB_NON_SEC_DIR_TRANS:
- (*fb_ns_dir)++;
- break;
case SDE_DRM_FB_SEC_DIR_TRANS:
(*fb_sec_dir)++;
break;
default:
SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d",
- plane->base.id,
- mode);
+ plane->base.id, mode);
return -EINVAL;
}
}
@@ -1593,7 +1580,7 @@
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
struct sde_crtc_smmu_state_data *smmu_state;
- uint32_t translation_mode = 0;
+ uint32_t translation_mode = 0, secure_level;
int ops = 0;
bool post_commit = false;
@@ -1605,10 +1592,10 @@
sde_crtc = to_sde_crtc(crtc);
cstate = to_sde_crtc_state(crtc->state);
smmu_state = &sde_crtc->smmu_state;
+ secure_level = sde_crtc_get_secure_level(crtc, crtc->state);
- SDE_DEBUG("crtc%d, secure_level%d\n",
- crtc->base.id,
- sde_crtc_get_secure_level(crtc, crtc->state));
+ SDE_DEBUG("crtc%d, secure_level%d old_valid_fb%d\n",
+ crtc->base.id, secure_level, old_valid_fb);
/**
* SMMU operations need to be delayed in case of
@@ -1632,8 +1619,7 @@
PLANE_PROP_FB_TRANSLATION_MODE);
if (translation_mode > SDE_DRM_FB_SEC_DIR_TRANS) {
SDE_ERROR("crtc%d, invalid translation_mode%d\n",
- crtc->base.id,
- translation_mode);
+ crtc->base.id, translation_mode);
return -EINVAL;
}
@@ -1641,14 +1627,15 @@
* we can break if we find sec_fir or non_sec_dir
* plane
*/
- if ((translation_mode == SDE_DRM_FB_NON_SEC_DIR_TRANS) ||
- (translation_mode == SDE_DRM_FB_SEC_DIR_TRANS))
+ if (translation_mode == SDE_DRM_FB_SEC_DIR_TRANS)
break;
}
switch (translation_mode) {
- case SDE_DRM_FB_NON_SEC_DIR_TRANS:
- if (smmu_state->state == ATTACHED) {
+ case SDE_DRM_FB_SEC_DIR_TRANS:
+ /* secure display usecase */
+ if ((smmu_state->state == ATTACHED) &&
+ (secure_level == SDE_DRM_SEC_ONLY)) {
smmu_state->state = DETACH_ALL_REQ;
smmu_state->transition_type = PRE_COMMIT;
ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
@@ -1656,10 +1643,8 @@
ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
SDE_KMS_OPS_CLEANUP_PLANE_FB);
}
- }
- break;
- case SDE_DRM_FB_SEC_DIR_TRANS:
- if (smmu_state->state == ATTACHED) {
+ /* secure camera usecase */
+ } else if (smmu_state->state == ATTACHED) {
smmu_state->state = DETACH_SEC_REQ;
smmu_state->transition_type = PRE_COMMIT;
ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
@@ -1667,14 +1652,18 @@
break;
case SDE_DRM_FB_SEC:
case SDE_DRM_FB_NON_SEC:
- if (smmu_state->state == DETACHED_SEC) {
+ if ((smmu_state->state == DETACHED_SEC) ||
+ (smmu_state->state == DETACH_SEC_REQ)) {
smmu_state->state = ATTACH_SEC_REQ;
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
if (translation_mode == SDE_DRM_FB_SEC)
ops |= SDE_KMS_OPS_PREPARE_PLANE_FB;
- } else if (smmu_state->state == DETACHED) {
+ if (old_valid_fb)
+ ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE;
+ } else if ((smmu_state->state == DETACHED) ||
+ (smmu_state->state == DETACH_ALL_REQ)) {
smmu_state->state = ATTACH_ALL_REQ;
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
@@ -1686,15 +1675,13 @@
}
break;
default:
- SDE_ERROR("invalid plane fb_mode:%d\n",
- translation_mode);
+ SDE_ERROR("invalid plane fb_mode:%d\n", translation_mode);
ops = 0;
return -EINVAL;
}
SDE_DEBUG("SMMU State:%d, type:%d ops:%x\n", smmu_state->state,
- smmu_state->transition_type,
- ops);
+ smmu_state->transition_type, ops);
return ops;
}
@@ -1722,13 +1709,13 @@
*/
sec_sid[0] = SEC_SID_MASK_0;
sec_sid[1] = SEC_SID_MASK_1;
- dmac_flush_range(&sec_sid, &sec_sid + num_sids);
+ dmac_flush_range(sec_sid, sec_sid + num_sids);
SDE_DEBUG("calling scm_call for vmid %d", vmid);
desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
desc.args[0] = MDP_DEVICE_ID;
- desc.args[1] = SCM_BUFFER_PHYS(&sec_sid);
+ desc.args[1] = SCM_BUFFER_PHYS(sec_sid);
desc.args[2] = sizeof(uint32_t) * num_sids;
desc.args[3] = vmid;
@@ -1736,8 +1723,7 @@
mem_protect_sd_ctrl_id), &desc);
if (ret) {
SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
- desc.args[3],
- ret);
+ desc.args[3], ret);
}
kfree(sec_sid);
@@ -1780,7 +1766,6 @@
/* Bail out */
return 0;
-
/* Secure UI use case enable */
switch (smmu_state->state) {
case DETACH_ALL_REQ:
@@ -1856,11 +1841,10 @@
SDE_DEBUG("crtc: %d, old_state %d new_state %d\n", crtc->base.id,
old_smmu_state,
smmu_state->state);
- smmu_state->transition_error = false;
smmu_state->transition_type = NONE;
error:
- smmu_state->transition_error = true;
+ smmu_state->transition_error = ret ? true : false;
return ret;
}
@@ -2573,7 +2557,7 @@
* apply color processing properties only if
* smmu state is attached,
*/
- if ((smmu_state->state != DETACHED) ||
+ if ((smmu_state->state != DETACHED) &&
(smmu_state->state != DETACH_ALL_REQ))
sde_cp_crtc_apply_properties(crtc);
@@ -2740,17 +2724,73 @@
return rc;
}
-void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
+static void _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
+ struct sde_crtc_state *cstate)
{
struct drm_plane *plane;
+ struct sde_crtc *sde_crtc;
+ struct sde_hw_ctl *ctl, *master_ctl;
+ u32 flush_mask;
+ int i;
+
+ if (!crtc || !cstate)
+ return;
+
+ sde_crtc = to_sde_crtc(crtc);
+
+ /*
+ * Update sbuf configuration and flush bits if a flush
+ * mask has been defined for either the current or
+ * previous commit.
+ *
+ * Updates are also required for the first commit after
+ * sbuf_flush_mask becomes 0x0, to properly transition
+ * the hardware out of sbuf mode.
+ */
+ if (!sde_crtc->sbuf_flush_mask_old && !sde_crtc->sbuf_flush_mask)
+ return;
+
+ flush_mask = sde_crtc->sbuf_flush_mask_old | sde_crtc->sbuf_flush_mask;
+ sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask;
+
+ SDE_ATRACE_BEGIN("crtc_kickoff_rot");
+
+ if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ sde_plane_kickoff(plane);
+ }
+ }
+
+ master_ctl = NULL;
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ ctl = sde_crtc->mixers[i].hw_ctl;
+ if (!ctl || !ctl->ops.setup_sbuf_cfg ||
+ !ctl->ops.update_pending_flush)
+ continue;
+
+ if (!master_ctl || master_ctl->idx > ctl->idx)
+ master_ctl = ctl;
+
+ ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ }
+
+ if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
+ master_ctl && master_ctl->ops.trigger_rot_start)
+ master_ctl->ops.trigger_rot_start(master_ctl);
+
+ SDE_ATRACE_END("crtc_kickoff_rot");
+}
+
+void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
+{
struct drm_encoder *encoder;
struct drm_device *dev;
struct sde_crtc *sde_crtc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
struct sde_crtc_state *cstate;
- struct sde_hw_ctl *ctl;
- int ret, i;
+ int ret;
if (!crtc) {
SDE_ERROR("invalid argument\n");
@@ -2777,6 +2817,11 @@
return;
SDE_ATRACE_BEGIN("crtc_commit");
+
+ /* default to ASYNC mode for inline rotation */
+ cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask ?
+ SDE_CTL_ROT_OP_MODE_INLINE_ASYNC : SDE_CTL_ROT_OP_MODE_OFFLINE;
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct sde_encoder_kickoff_params params = { 0 };
@@ -2791,8 +2836,27 @@
params.affected_displays = _sde_crtc_get_displays_affected(crtc,
crtc->state);
sde_encoder_prepare_for_kickoff(encoder, ¶ms);
+
+ /*
+ * For inline ASYNC modes, the flush bits are not written
+ * to hardware atomically, so avoid using it if a video
+ * mode encoder is active on this CRTC.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode ==
+ SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
+ sde_encoder_get_intf_mode(encoder) ==
+ INTF_MODE_VIDEO)
+ cstate->sbuf_cfg.rot_op_mode =
+ SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
}
+ /*
+ * For ASYNC inline modes, kick off the rotator now so that the H/W
+ * can start as soon as it's ready.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
+ _sde_crtc_commit_kickoff_rot(crtc, cstate);
+
/* wait for frame_event_done completion */
SDE_ATRACE_BEGIN("wait_for_frame_done_event");
ret = _sde_crtc_wait_for_frame_done(crtc);
@@ -2807,22 +2871,24 @@
if (atomic_inc_return(&sde_crtc->frame_pending) == 1) {
/* acquire bandwidth and other resources */
SDE_DEBUG("crtc%d first commit\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE1);
+ SDE_EVT32(DRMID(crtc), cstate->sbuf_cfg.rot_op_mode,
+ SDE_EVTLOG_FUNC_CASE1);
} else {
SDE_DEBUG("crtc%d commit\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE2);
+ SDE_EVT32(DRMID(crtc), cstate->sbuf_cfg.rot_op_mode,
+ SDE_EVTLOG_FUNC_CASE2);
}
sde_crtc->play_count++;
- if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE)
- drm_atomic_crtc_for_each_plane(plane, crtc)
- sde_plane_kickoff(plane);
-
- for (i = 0; i < sde_crtc->num_mixers; i++) {
- ctl = sde_crtc->mixers[i].hw_ctl;
- if (ctl && ctl->ops.setup_sbuf_cfg)
- ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
- }
+ /*
+ * For SYNC inline modes, delay the kick off until after the
+ * wait for frame done in case the wait times out.
+ *
+ * Also perform a final kickoff when transitioning back to
+ * offline mode.
+ */
+ if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_INLINE_ASYNC)
+ _sde_crtc_commit_kickoff_rot(crtc, cstate);
sde_vbif_clear_errors(sde_kms);
@@ -3416,7 +3482,7 @@
struct drm_encoder *encoder;
struct sde_crtc_state *cstate;
uint32_t secure;
- uint32_t fb_ns = 0, fb_sec = 0, fb_ns_dir = 0, fb_sec_dir = 0;
+ uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
int encoder_cnt = 0;
int rc;
@@ -3433,26 +3499,21 @@
rc = _sde_crtc_find_plane_fb_modes(state,
&fb_ns,
&fb_sec,
- &fb_ns_dir,
&fb_sec_dir);
if (rc)
return rc;
/**
* validate planes
- * fb_ns_dir is for secure display use case,
- * fb_sec_dir is for secure camera preview use case,
+ * fb_sec_dir is for secure camera preview and secure display use case,
* fb_sec is for secure video playback,
* fb_ns is for normal non secure use cases.
*/
- if (((secure == SDE_DRM_SEC_ONLY) &&
- (fb_ns || fb_sec || fb_sec_dir)) ||
- (fb_sec && fb_sec_dir)) {
+ if ((secure == SDE_DRM_SEC_ONLY) &&
+ (fb_ns || fb_sec || (fb_sec && fb_sec_dir))) {
SDE_ERROR(
- "crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n",
- crtc->base.id,
- fb_sec, fb_ns, fb_sec_dir,
- fb_ns_dir);
+ "crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d\n",
+ crtc->base.id, fb_sec, fb_ns, fb_sec_dir);
return -EINVAL;
}
@@ -3460,7 +3521,7 @@
* secure_crtc is not allowed in a shared toppolgy
* across different encoders.
*/
- if (fb_ns_dir || fb_sec_dir) {
+ if (fb_sec_dir) {
drm_for_each_encoder(encoder, crtc->dev)
if (encoder->crtc == crtc)
encoder_cnt++;
@@ -3922,6 +3983,15 @@
if (catalog->perf.max_bw_high)
sde_kms_info_add_keyint(info, "max_bandwidth_high",
catalog->perf.max_bw_high * 1000LL);
+ if (catalog->perf.min_core_ib)
+ sde_kms_info_add_keyint(info, "min_core_ib",
+ catalog->perf.min_core_ib * 1000LL);
+ if (catalog->perf.min_llcc_ib)
+ sde_kms_info_add_keyint(info, "min_llcc_ib",
+ catalog->perf.min_llcc_ib * 1000LL);
+ if (catalog->perf.min_dram_ib)
+ sde_kms_info_add_keyint(info, "min_dram_ib",
+ catalog->perf.min_dram_ib * 1000LL);
if (sde_kms->perf.max_core_clk_rate)
sde_kms_info_add_keyint(info, "max_mdp_clk",
sde_kms->perf.max_core_clk_rate);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index ea606b3..0783f11 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -204,6 +204,8 @@
* @misr_enable : boolean entry indicates misr enable/disable status.
* @misr_frame_count : misr frame count provided by client
* @misr_data : store misr data before turning off the clocks.
+ * @sbuf_flush_mask: flush mask for inline rotator
+ * @sbuf_flush_mask_old: inline rotator flush mask for previous commit
* @power_event : registered power event handle
* @cur_perf : current performance committed to clock/bandwidth driver
* @rp_lock : serialization lock for resource pool
@@ -264,6 +266,9 @@
u32 misr_frame_count;
u32 misr_data[CRTC_DUAL_MIXERS];
+ u32 sbuf_flush_mask;
+ u32 sbuf_flush_mask_old;
+
struct sde_power_event *power_event;
struct sde_core_perf_params cur_perf;
@@ -357,7 +362,6 @@
* @new_perf: new performance state being requested
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
- * @sbuf_flush_mask: flush mask for inline rotator
*/
struct sde_crtc_state {
struct drm_crtc_state base;
@@ -385,7 +389,6 @@
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
u32 sbuf_prefill_line;
- u32 sbuf_flush_mask;
struct sde_crtc_respool rp;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 3e1ed7b..270e677 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -2224,11 +2224,13 @@
sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);
- if (sde_enc->cur_master) {
- sde_enc->cur_master->connector = NULL;
- sde_enc->cur_master = NULL;
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ if (sde_enc->phys_encs[i])
+ sde_enc->phys_encs[i]->connector = NULL;
}
+ sde_enc->cur_master = NULL;
+
SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");
sde_rm_release(&sde_kms->rm, drm_enc);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index b80ed1f..3158fe2 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -279,8 +279,9 @@
return;
SDE_DEBUG_VIDENC(vid_enc,
- "rot_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
- rot_fetch_lines, rot_fetch_start_vsync_counter);
+ "rot_fetch_lines %u vfp_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
+ rot_fetch_lines, vfp_fetch_lines,
+ rot_fetch_start_vsync_counter);
phys_enc->hw_ctl->ops.get_bitmask_intf(
phys_enc->hw_ctl, &flush_mask, vid_enc->hw_intf->idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index ccc4443..f35e999 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -146,6 +146,9 @@
enum {
PERF_MAX_BW_LOW,
PERF_MAX_BW_HIGH,
+ PERF_MIN_CORE_IB,
+ PERF_MIN_LLCC_IB,
+ PERF_MIN_DRAM_IB,
PERF_CORE_IB_FF,
PERF_CORE_CLK_FF,
PERF_COMP_RATIO_RT,
@@ -376,6 +379,9 @@
static struct sde_prop_type sde_perf_prop[] = {
{PERF_MAX_BW_LOW, "qcom,sde-max-bw-low-kbps", false, PROP_TYPE_U32},
{PERF_MAX_BW_HIGH, "qcom,sde-max-bw-high-kbps", false, PROP_TYPE_U32},
+ {PERF_MIN_CORE_IB, "qcom,sde-min-core-ib-kbps", false, PROP_TYPE_U32},
+ {PERF_MIN_LLCC_IB, "qcom,sde-min-llcc-ib-kbps", false, PROP_TYPE_U32},
+ {PERF_MIN_DRAM_IB, "qcom,sde-min-dram-ib-kbps", false, PROP_TYPE_U32},
{PERF_CORE_IB_FF, "qcom,sde-core-ib-ff", false, PROP_TYPE_STRING},
{PERF_CORE_CLK_FF, "qcom,sde-core-clk-ff", false, PROP_TYPE_STRING},
{PERF_COMP_RATIO_RT, "qcom,sde-comp-ratio-rt", false,
@@ -2691,6 +2697,18 @@
prop_exists[PERF_MAX_BW_HIGH] ?
PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0) :
DEFAULT_MAX_BW_HIGH;
+ cfg->perf.min_core_ib =
+ prop_exists[PERF_MIN_CORE_IB] ?
+ PROP_VALUE_ACCESS(prop_value, PERF_MIN_CORE_IB, 0) :
+ DEFAULT_MAX_BW_LOW;
+ cfg->perf.min_llcc_ib =
+ prop_exists[PERF_MIN_LLCC_IB] ?
+ PROP_VALUE_ACCESS(prop_value, PERF_MIN_LLCC_IB, 0) :
+ DEFAULT_MAX_BW_LOW;
+ cfg->perf.min_dram_ib =
+ prop_exists[PERF_MIN_DRAM_IB] ?
+ PROP_VALUE_ACCESS(prop_value, PERF_MIN_DRAM_IB, 0) :
+ DEFAULT_MAX_BW_LOW;
/*
* The following performance parameters (e.g. core_ib_ff) are
@@ -2873,7 +2891,8 @@
vig_list_size += ARRAY_SIZE(rgb_10bit_formats)
+ ARRAY_SIZE(tp10_ubwc_formats)
+ ARRAY_SIZE(p010_formats);
- if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400))
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) ||
+ (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)))
vig_list_size += ARRAY_SIZE(p010_ubwc_formats);
wb2_list_size += ARRAY_SIZE(rgb_10bit_formats)
@@ -2914,7 +2933,8 @@
ARRAY_SIZE(rgb_10bit_formats));
index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size,
index, p010_formats, ARRAY_SIZE(p010_formats));
- if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400))
+ if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) ||
+ (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)))
index += sde_copy_formats(sde_cfg->vig_formats,
vig_list_size, index, p010_ubwc_formats,
ARRAY_SIZE(p010_ubwc_formats));
@@ -2953,7 +2973,7 @@
sde_cfg->perf.min_prefill_lines = 25;
sde_cfg->vbif_qos_nlvl = 4;
sde_cfg->ts_prefill_rev = 1;
- } else if (IS_SDM845_TARGET(hw_rev)) {
+ } else if (IS_SDM845_TARGET(hw_rev) || IS_SDM670_TARGET(hw_rev)) {
/* update sdm845 target here */
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 24;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 48c3db7..7c43988 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -46,10 +46,12 @@
#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) /* sdm845 v1.0 */
#define SDE_HW_VER_401 SDE_HW_VER(4, 0, 1) /* sdm845 v2.0 */
+#define SDE_HW_VER_410 SDE_HW_VER(4, 1, 0) /* sdm670 v1.0 */
#define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170)
#define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300)
#define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
+#define IS_SDM670_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_410)
#define SDE_HW_BLK_NAME_LEN 16
@@ -803,6 +805,10 @@
* struct sde_perf_cfg - performance control settings
* @max_bw_low low threshold of maximum bandwidth (kbps)
* @max_bw_high high threshold of maximum bandwidth (kbps)
+ * @min_core_ib minimum bandwidth for core (kbps)
+ * @min_core_ib minimum mnoc ib vote in kbps
+ * @min_llcc_ib minimum llcc ib vote in kbps
+ * @min_dram_ib minimum dram ib vote in kbps
* @core_ib_ff core instantaneous bandwidth fudge factor
* @core_clk_ff core clock fudge factor
* @comp_ratio_rt string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio>
@@ -824,6 +830,9 @@
struct sde_perf_cfg {
u32 max_bw_low;
u32 max_bw_high;
+ u32 min_core_ib;
+ u32 min_llcc_ib;
+ u32 min_dram_ib;
const char *core_ib_ff;
const char *core_clk_ff;
const char *comp_ratio_rt;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
index 4191367..c8e732a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.c
@@ -12,6 +12,7 @@
#include <drm/msm_drm_pp.h>
#include "sde_hw_color_processing_v1_7.h"
+#include "sde_hw_ctl.h"
#define PA_HUE_VIG_OFF 0x110
#define PA_SAT_VIG_OFF 0x114
@@ -26,6 +27,9 @@
#define PA_LUTV_DSPP_OFF 0x1400
#define PA_LUT_SWAP_OFF 0x234
+#define PA_LUTV_DSPP_CTRL_OFF 0x4c
+#define PA_LUTV_DSPP_SWAP_OFF 0x18
+
#define PA_HUE_MASK 0xFFF
#define PA_SAT_MASK 0xFFFF
#define PA_VAL_MASK 0xFF
@@ -458,6 +462,62 @@
SDE_REG_WRITE(&ctx->hw, base, op_mode);
}
+void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg)
+{
+ struct drm_msm_pa_vlut *payload = NULL;
+ struct sde_hw_cp_cfg *hw_cfg = cfg;
+ struct sde_hw_ctl *ctl = NULL;
+ u32 vlut_base, pa_hist_base;
+ u32 ctrl_off, swap_off;
+ u32 tmp = 0;
+ int i = 0, j = 0;
+ u32 flush_mask = 0;
+
+ if (!ctx) {
+ DRM_ERROR("invalid input parameter NULL ctx\n");
+ return;
+ }
+
+ if (!hw_cfg || (hw_cfg->payload && hw_cfg->len !=
+ sizeof(struct drm_msm_pa_vlut))) {
+ DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n",
+ hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
+ ((hw_cfg) ? hw_cfg->len : 0),
+ sizeof(struct drm_msm_pa_vlut));
+ return;
+ }
+
+ ctl = hw_cfg->ctl;
+ vlut_base = ctx->cap->sblk->vlut.base;
+ pa_hist_base = ctx->cap->sblk->hist.base;
+ ctrl_off = pa_hist_base + PA_LUTV_DSPP_CTRL_OFF;
+ swap_off = pa_hist_base + PA_LUTV_DSPP_SWAP_OFF;
+
+ if (!hw_cfg->payload) {
+ DRM_DEBUG_DRIVER("Disable vlut feature\n");
+ SDE_REG_WRITE(&ctx->hw, ctrl_off, 0);
+ goto exit;
+ }
+
+ payload = hw_cfg->payload;
+ DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
+ for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) {
+ tmp = (payload->val[i] & REG_MASK(10)) |
+ ((payload->val[i + 1] & REG_MASK(10)) << 16);
+ SDE_REG_WRITE(&ctx->hw, (vlut_base + j), tmp);
+ }
+ SDE_REG_WRITE(&ctx->hw, ctrl_off, 1);
+ SDE_REG_WRITE(&ctx->hw, swap_off, 1);
+
+exit:
+ /* update flush bit */
+ if (ctl && ctl->ops.get_bitmask_dspp_pavlut) {
+ ctl->ops.get_bitmask_dspp_pavlut(ctl, &flush_mask, ctx->idx);
+ if (ctl->ops.update_pending_flush)
+ ctl->ops.update_pending_flush(ctl, flush_mask);
+ }
+}
+
void sde_setup_dspp_gc_v1_7(struct sde_hw_dspp *ctx, void *cfg)
{
struct drm_msm_pgc_lut *payload = NULL;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
index 25e446b7..4cd2e5a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_processing_v1_7.h
@@ -76,6 +76,13 @@
void sde_setup_dspp_pa_vlut_v1_7(struct sde_hw_dspp *ctx, void *cfg);
/**
+ * sde_setup_dspp_pa_vlut_v1_8 - setup DSPP PA vLUT feature in v1.8 hardware
+ * @ctx: Pointer to DSPP context
+ * @cfg: Pointer to vLUT data
+ */
+void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg);
+
+/**
* sde_setup_dspp_gc_v1_7 - setup DSPP gc feature in v1.7 hardware
* @ctx: Pointer to DSPP context
* @cfg: Pointer to gc data
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 621a172..95b7a6d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -89,6 +89,11 @@
static inline void sde_hw_ctl_trigger_rot_start(struct sde_hw_ctl *ctx)
{
+ /* ROT flush bit is latched during ROT start, so set it first */
+ if (CTL_FLUSH_MASK_ROT & ctx->pending_flush_mask) {
+ ctx->pending_flush_mask &= ~CTL_FLUSH_MASK_ROT;
+ SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, CTL_FLUSH_MASK_ROT);
+ }
SDE_REG_WRITE(&ctx->hw, CTL_ROT_START, BIT(0));
}
@@ -235,6 +240,22 @@
return 0;
}
+static inline int sde_hw_ctl_get_bitmask_dspp_pavlut(struct sde_hw_ctl *ctx,
+ u32 *flushbits, enum sde_dspp dspp)
+{
+ switch (dspp) {
+ case DSPP_0:
+ *flushbits |= BIT(3);
+ break;
+ case DSPP_1:
+ *flushbits |= BIT(4);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static inline int sde_hw_ctl_get_bitmask_intf(struct sde_hw_ctl *ctx,
u32 *flushbits, enum sde_intf intf)
{
@@ -568,6 +589,7 @@
ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp;
ops->get_bitmask_mixer = sde_hw_ctl_get_bitmask_mixer;
ops->get_bitmask_dspp = sde_hw_ctl_get_bitmask_dspp;
+ ops->get_bitmask_dspp_pavlut = sde_hw_ctl_get_bitmask_dspp_pavlut;
ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf;
ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm;
ops->get_bitmask_wb = sde_hw_ctl_get_bitmask_wb;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 5d3ced3..97bc1c1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -173,6 +173,10 @@
u32 *flushbits,
enum sde_dspp blk);
+ int (*get_bitmask_dspp_pavlut)(struct sde_hw_ctl *ctx,
+ u32 *flushbits,
+ enum sde_dspp blk);
+
int (*get_bitmask_intf)(struct sde_hw_ctl *ctx,
u32 *flushbits,
enum sde_intf blk);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 5b3f51e..d30c0ae 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -82,9 +82,12 @@
} else if (c->cap->sblk->vlut.version ==
(SDE_COLOR_PROCESS_VER(0x1, 0x8))) {
ret = reg_dmav1_init_dspp_op_v4(i, c->idx);
- if (ret)
+ if (!ret)
c->ops.setup_vlut =
reg_dmav1_setup_dspp_vlutv18;
+ else
+ c->ops.setup_vlut =
+ sde_setup_dspp_pa_vlut_v1_8;
}
break;
case SDE_DSPP_GAMUT:
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 3d282ee..4e677c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -262,7 +262,7 @@
unsigned long features)
{
ops->setup_mixer_out = sde_hw_lm_setup_out;
- if (IS_SDM845_TARGET(m->hwversion))
+ if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion))
ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845;
else
ops->setup_blend_config = sde_hw_lm_setup_blend_config;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 4487d78..93637a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -582,7 +582,7 @@
return 0;
}
-static void sde_reg_dma_aspace_cb(void *cb_data, bool attach)
+static void sde_reg_dma_aspace_cb_locked(void *cb_data, bool is_detach)
{
struct sde_reg_dma_buffer *dma_buf = NULL;
struct msm_gem_address_space *aspace = NULL;
@@ -597,14 +597,23 @@
dma_buf = (struct sde_reg_dma_buffer *)cb_data;
aspace = dma_buf->aspace;
- if (attach) {
- rc = msm_gem_get_iova(dma_buf->buf, aspace, &dma_buf->iova);
+ if (is_detach) {
+ /* invalidate the stored iova */
+ dma_buf->iova = 0;
+
+ /* return the virtual address mapping */
+ msm_gem_put_vaddr_locked(dma_buf->buf);
+ msm_gem_vunmap(dma_buf->buf);
+
+ } else {
+ rc = msm_gem_get_iova_locked(dma_buf->buf, aspace,
+ &dma_buf->iova);
if (rc) {
DRM_ERROR("failed to get the iova rc %d\n", rc);
return;
}
- dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf);
+ dma_buf->vaddr = msm_gem_get_vaddr_locked(dma_buf->buf);
if (IS_ERR_OR_NULL(dma_buf->vaddr)) {
DRM_ERROR("failed to get va rc %d\n", rc);
return;
@@ -615,13 +624,6 @@
dma_buf->iova = dma_buf->iova + offset;
dma_buf->vaddr = (void *)(((u8 *)dma_buf->vaddr) + offset);
dma_buf->next_op_allowed = DECODE_SEL_OP;
- } else {
- /* invalidate the stored iova */
- dma_buf->iova = 0;
-
- /* return the virtual address mapping */
- msm_gem_put_vaddr(dma_buf->buf);
- msm_gem_vunmap(dma_buf->buf);
}
}
@@ -661,7 +663,7 @@
/* register to aspace */
rc = msm_gem_address_space_register_cb(aspace,
- sde_reg_dma_aspace_cb,
+ sde_reg_dma_aspace_cb_locked,
(void *)dma_buf);
if (rc) {
DRM_ERROR("failed to register callback %d", rc);
@@ -694,8 +696,8 @@
put_iova:
msm_gem_put_iova(dma_buf->buf, aspace);
free_aspace_cb:
- msm_gem_address_space_unregister_cb(aspace, sde_reg_dma_aspace_cb,
- dma_buf);
+ msm_gem_address_space_unregister_cb(aspace,
+ sde_reg_dma_aspace_cb_locked, dma_buf);
free_gem:
msm_gem_free_object(dma_buf->buf);
fail:
@@ -713,7 +715,7 @@
if (dma_buf->buf) {
msm_gem_put_iova(dma_buf->buf, 0);
msm_gem_address_space_unregister_cb(dma_buf->aspace,
- sde_reg_dma_aspace_cb, dma_buf);
+ sde_reg_dma_aspace_cb_locked, dma_buf);
mutex_lock(®_dma->drm_dev->struct_mutex);
msm_gem_free_object(dma_buf->buf);
mutex_unlock(®_dma->drm_dev->struct_mutex);
@@ -774,6 +776,11 @@
return -EINVAL;
}
+ if (!last_cmd_buf->iova) {
+ DRM_DEBUG("iova not set, possible secure session\n");
+ return 0;
+ }
+
cfg.dma_buf = last_cmd_buf;
reset_reg_dma_buffer_v1(last_cmd_buf);
if (validate_last_cmd(&cfg)) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 55cb260..b59dd16 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -44,7 +44,7 @@
static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX];
static u32 feature_map[SDE_DSPP_MAX] = {
- [SDE_DSPP_VLUT] = VLUT,
+ [SDE_DSPP_VLUT] = REG_DMA_FEATURES_MAX,
[SDE_DSPP_GAMUT] = GAMUT,
[SDE_DSPP_IGC] = IGC,
[SDE_DSPP_PCC] = PCC,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 1a00517..c5af3a9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -656,7 +656,7 @@
SDE_ERROR("failed to get dst format\n");
return -EINVAL;
}
- } else if (hw_cmd == SDE_HW_ROT_CMD_COMMIT) {
+ } else {
rc = sde_hw_rot_to_v4l2_pixfmt(data->dst_pixel_format,
data->dst_modifier, &rot_cmd.dst_pixfmt);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index a4564c1..e5f6471 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -119,57 +119,6 @@
#define COMP1_2_INIT_PHASE_Y 0x2C
#define VIG_0_QSEED2_SHARP 0x30
-/* SDE_SSPP_SCALER_QSEED3 */
-#define QSEED3_HW_VERSION 0x00
-#define QSEED3_OP_MODE 0x04
-#define QSEED3_RGB2Y_COEFF 0x08
-#define QSEED3_PHASE_INIT 0x0C
-#define QSEED3_PHASE_STEP_Y_H 0x10
-#define QSEED3_PHASE_STEP_Y_V 0x14
-#define QSEED3_PHASE_STEP_UV_H 0x18
-#define QSEED3_PHASE_STEP_UV_V 0x1C
-#define QSEED3_PRELOAD 0x20
-#define QSEED3_DE_SHARPEN 0x24
-#define QSEED3_DE_SHARPEN_CTL 0x28
-#define QSEED3_DE_SHAPE_CTL 0x2C
-#define QSEED3_DE_THRESHOLD 0x30
-#define QSEED3_DE_ADJUST_DATA_0 0x34
-#define QSEED3_DE_ADJUST_DATA_1 0x38
-#define QSEED3_DE_ADJUST_DATA_2 0x3C
-#define QSEED3_SRC_SIZE_Y_RGB_A 0x40
-#define QSEED3_SRC_SIZE_UV 0x44
-#define QSEED3_DST_SIZE 0x48
-#define QSEED3_COEF_LUT_CTRL 0x4C
-#define QSEED3_COEF_LUT_SWAP_BIT 0
-#define QSEED3_COEF_LUT_DIR_BIT 1
-#define QSEED3_COEF_LUT_Y_CIR_BIT 2
-#define QSEED3_COEF_LUT_UV_CIR_BIT 3
-#define QSEED3_COEF_LUT_Y_SEP_BIT 4
-#define QSEED3_COEF_LUT_UV_SEP_BIT 5
-#define QSEED3_BUFFER_CTRL 0x50
-#define QSEED3_CLK_CTRL0 0x54
-#define QSEED3_CLK_CTRL1 0x58
-#define QSEED3_CLK_STATUS 0x5C
-#define QSEED3_MISR_CTRL 0x70
-#define QSEED3_MISR_SIGNATURE_0 0x74
-#define QSEED3_MISR_SIGNATURE_1 0x78
-#define QSEED3_PHASE_INIT_Y_H 0x90
-#define QSEED3_PHASE_INIT_Y_V 0x94
-#define QSEED3_PHASE_INIT_UV_H 0x98
-#define QSEED3_PHASE_INIT_UV_V 0x9C
-#define QSEED3_COEF_LUT 0x100
-#define QSEED3_FILTERS 5
-#define QSEED3_LUT_REGIONS 4
-#define QSEED3_CIRCULAR_LUTS 9
-#define QSEED3_SEPARABLE_LUTS 10
-#define QSEED3_LUT_SIZE 60
-#define QSEED3_ENABLE 2
-#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32))
-#define QSEED3_CIR_LUT_SIZE \
- (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32))
-#define QSEED3_SEP_LUT_SIZE \
- (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32))
-
/*
* Definitions for ViG op modes
*/
@@ -422,19 +371,19 @@
if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
return;
- if (rect_mode == SDE_SSPP_RECT_SOLO || rect_mode == SDE_SSPP_RECT_0)
- secure_bit_mask = (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF :
- 0x5;
- else
- secure_bit_mask = 0xA;
-
c = &ctx->hw;
- secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
- if (enable)
+ if (enable) {
+ if ((rect_mode == SDE_SSPP_RECT_SOLO)
+ || (rect_mode == SDE_SSPP_RECT_0))
+ secure_bit_mask =
+ (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
+ else
+ secure_bit_mask = 0xA;
+
+ secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
secure |= secure_bit_mask;
- else
- secure &= ~secure_bit_mask;
+ }
SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
}
@@ -556,144 +505,12 @@
pe->phase_step_y[SDE_SSPP_COMP_1_2]);
}
-static void _sde_hw_sspp_setup_scaler3_lut(struct sde_hw_pipe *ctx,
- struct sde_hw_scaler3_cfg *scaler3_cfg)
-{
- u32 idx;
- int i, j, filter;
- int config_lut = 0x0;
- unsigned long lut_flags;
- u32 lut_addr, lut_offset, lut_len;
- u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL};
- static const uint32_t offset[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = {
- {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} },
- {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} },
- {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} },
- {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} },
- {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} },
- };
-
- if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx) ||
- !scaler3_cfg)
- return;
-
- lut_flags = (unsigned long) scaler3_cfg->lut_flag;
- if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) &&
- (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) {
- lut[0] = scaler3_cfg->dir_lut;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) &&
- (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
- (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
- lut[1] = scaler3_cfg->cir_lut +
- scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) &&
- (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
- (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
- lut[2] = scaler3_cfg->cir_lut +
- scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) &&
- (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
- (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
- lut[3] = scaler3_cfg->sep_lut +
- scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
- if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) &&
- (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
- (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
- lut[4] = scaler3_cfg->sep_lut +
- scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE;
- config_lut = 1;
- }
-
- if (config_lut) {
- for (filter = 0; filter < QSEED3_FILTERS; filter++) {
- if (!lut[filter])
- continue;
- lut_offset = 0;
- for (i = 0; i < QSEED3_LUT_REGIONS; i++) {
- lut_addr = QSEED3_COEF_LUT + idx
- + offset[filter][i][1];
- lut_len = offset[filter][i][0] << 2;
- for (j = 0; j < lut_len; j++) {
- SDE_REG_WRITE(&ctx->hw,
- lut_addr,
- (lut[filter])[lut_offset++]);
- lut_addr += 4;
- }
- }
- }
- }
-
- if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags))
- SDE_REG_WRITE(&ctx->hw, QSEED3_COEF_LUT_CTRL + idx, BIT(0));
-
-}
-
-static void _sde_hw_sspp_setup_scaler3_de(struct sde_hw_pipe *ctx,
- struct sde_hw_scaler3_de_cfg *de_cfg)
-{
- u32 idx;
- u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr;
- u32 adjust_a, adjust_b, adjust_c;
- struct sde_hw_blk_reg_map *hw;
-
- if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx) || !de_cfg)
- return;
-
- if (!de_cfg->enable)
- return;
-
- hw = &ctx->hw;
- sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) |
- ((de_cfg->sharpen_level2 & 0x1FF) << 16);
-
- sharp_ctl = ((de_cfg->limit & 0xF) << 9) |
- ((de_cfg->prec_shift & 0x7) << 13) |
- ((de_cfg->clip & 0x7) << 16);
-
- shape_ctl = (de_cfg->thr_quiet & 0xFF) |
- ((de_cfg->thr_dieout & 0x3FF) << 16);
-
- de_thr = (de_cfg->thr_low & 0x3FF) |
- ((de_cfg->thr_high & 0x3FF) << 16);
-
- adjust_a = (de_cfg->adjust_a[0] & 0x3FF) |
- ((de_cfg->adjust_a[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_a[2] & 0x3FF) << 20);
-
- adjust_b = (de_cfg->adjust_b[0] & 0x3FF) |
- ((de_cfg->adjust_b[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_b[2] & 0x3FF) << 20);
-
- adjust_c = (de_cfg->adjust_c[0] & 0x3FF) |
- ((de_cfg->adjust_c[1] & 0x3FF) << 10) |
- ((de_cfg->adjust_c[2] & 0x3FF) << 20);
-
- SDE_REG_WRITE(hw, QSEED3_DE_SHARPEN + idx, sharp_lvl);
- SDE_REG_WRITE(hw, QSEED3_DE_SHARPEN_CTL + idx, sharp_ctl);
- SDE_REG_WRITE(hw, QSEED3_DE_SHAPE_CTL + idx, shape_ctl);
- SDE_REG_WRITE(hw, QSEED3_DE_THRESHOLD + idx, de_thr);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_0 + idx, adjust_a);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_1 + idx, adjust_b);
- SDE_REG_WRITE(hw, QSEED3_DE_ADJUST_DATA_2 + idx, adjust_c);
-
-}
-
static void _sde_hw_sspp_setup_scaler3(struct sde_hw_pipe *ctx,
struct sde_hw_pipe_cfg *sspp,
struct sde_hw_pixel_ext *pe,
void *scaler_cfg)
{
u32 idx;
- u32 op_mode = 0;
- u32 phase_init, preload, src_y_rgb, src_uv, dst;
struct sde_hw_scaler3_cfg *scaler3_cfg = scaler_cfg;
(void)pe;
@@ -701,93 +518,9 @@
|| !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk)
return;
- if (!scaler3_cfg->enable)
- goto end;
-
- op_mode |= BIT(0);
- op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16;
-
- if (SDE_FORMAT_IS_YUV(sspp->layout.format)) {
- op_mode |= BIT(12);
- op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24;
- }
-
- op_mode |= (scaler3_cfg->blend_cfg & 1) << 31;
- op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0;
-
- preload =
- ((scaler3_cfg->preload_x[0] & 0x7F) << 0) |
- ((scaler3_cfg->preload_y[0] & 0x7F) << 8) |
- ((scaler3_cfg->preload_x[1] & 0x7F) << 16) |
- ((scaler3_cfg->preload_y[1] & 0x7F) << 24);
-
- src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) |
- ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16);
-
- src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) |
- ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16);
-
- dst = (scaler3_cfg->dst_width & 0x1FFFF) |
- ((scaler3_cfg->dst_height & 0x1FFFF) << 16);
-
- if (scaler3_cfg->de.enable) {
- _sde_hw_sspp_setup_scaler3_de(ctx, &scaler3_cfg->de);
- op_mode |= BIT(8);
- }
-
- if (scaler3_cfg->lut_flag)
- _sde_hw_sspp_setup_scaler3_lut(ctx, scaler3_cfg);
-
- if (ctx->cap->sblk->scaler_blk.version == 0x1002) {
- phase_init =
- ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) |
- ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) |
- ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) |
- ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT + idx, phase_init);
- } else {
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_Y_H + idx,
- scaler3_cfg->init_phase_x[0] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_Y_V + idx,
- scaler3_cfg->init_phase_y[0] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_UV_H + idx,
- scaler3_cfg->init_phase_x[1] & 0x1FFFFF);
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_INIT_UV_V + idx,
- scaler3_cfg->init_phase_y[1] & 0x1FFFFF);
- }
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_Y_H + idx,
- scaler3_cfg->phase_step_x[0] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_Y_V + idx,
- scaler3_cfg->phase_step_y[0] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_UV_H + idx,
- scaler3_cfg->phase_step_x[1] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PHASE_STEP_UV_V + idx,
- scaler3_cfg->phase_step_y[1] & 0xFFFFFF);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_PRELOAD + idx, preload);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_SRC_SIZE_Y_RGB_A + idx, src_y_rgb);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_SRC_SIZE_UV + idx, src_uv);
-
- SDE_REG_WRITE(&ctx->hw, QSEED3_DST_SIZE + idx, dst);
-
-end:
- if (!SDE_FORMAT_IS_DX(sspp->layout.format))
- op_mode |= BIT(14);
-
- if (sspp->layout.format->alpha_enable) {
- op_mode |= BIT(10);
- if (ctx->cap->sblk->scaler_blk.version == 0x1002)
- op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30;
- else
- op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29;
- }
- SDE_REG_WRITE(&ctx->hw, QSEED3_OP_MODE + idx, op_mode);
+ sde_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx,
+ ctx->cap->sblk->scaler_blk.version,
+ sspp->layout.format);
}
static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx)
@@ -797,7 +530,7 @@
if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx))
return 0;
- return SDE_REG_READ(&ctx->hw, QSEED3_HW_VERSION + idx);
+ return sde_hw_get_scaler3_ver(&ctx->hw, idx);
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 8700627..6e03ab1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -156,114 +156,6 @@
};
/**
- * struct sde_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration
- * @enable: detail enhancer enable/disable
- * @sharpen_level1: sharpening strength for noise
- * @sharpen_level2: sharpening strength for signal
- * @ clip: clip shift
- * @ limit: limit value
- * @ thr_quiet: quiet threshold
- * @ thr_dieout: dieout threshold
- * @ thr_high: low threshold
- * @ thr_high: high threshold
- * @ prec_shift: precision shift
- * @ adjust_a: A-coefficients for mapping curve
- * @ adjust_b: B-coefficients for mapping curve
- * @ adjust_c: C-coefficients for mapping curve
- */
-struct sde_hw_scaler3_de_cfg {
- u32 enable;
- int16_t sharpen_level1;
- int16_t sharpen_level2;
- uint16_t clip;
- uint16_t limit;
- uint16_t thr_quiet;
- uint16_t thr_dieout;
- uint16_t thr_low;
- uint16_t thr_high;
- uint16_t prec_shift;
- int16_t adjust_a[SDE_MAX_DE_CURVES];
- int16_t adjust_b[SDE_MAX_DE_CURVES];
- int16_t adjust_c[SDE_MAX_DE_CURVES];
-};
-
-/**
- * struct sde_hw_scaler3_cfg : QSEEDv3 configuration
- * @enable: scaler enable
- * @dir_en: direction detection block enable
- * @ init_phase_x: horizontal initial phase
- * @ phase_step_x: horizontal phase step
- * @ init_phase_y: vertical initial phase
- * @ phase_step_y: vertical phase step
- * @ preload_x: horizontal preload value
- * @ preload_y: vertical preload value
- * @ src_width: source width
- * @ src_height: source height
- * @ dst_width: destination width
- * @ dst_height: destination height
- * @ y_rgb_filter_cfg: y/rgb plane filter configuration
- * @ uv_filter_cfg: uv plane filter configuration
- * @ alpha_filter_cfg: alpha filter configuration
- * @ blend_cfg: blend coefficients configuration
- * @ lut_flag: scaler LUT update flags
- * 0x1 swap LUT bank
- * 0x2 update 2D filter LUT
- * 0x4 update y circular filter LUT
- * 0x8 update uv circular filter LUT
- * 0x10 update y separable filter LUT
- * 0x20 update uv separable filter LUT
- * @ dir_lut_idx: 2D filter LUT index
- * @ y_rgb_cir_lut_idx: y circular filter LUT index
- * @ uv_cir_lut_idx: uv circular filter LUT index
- * @ y_rgb_sep_lut_idx: y circular filter LUT index
- * @ uv_sep_lut_idx: uv separable filter LUT index
- * @ dir_lut: pointer to 2D LUT
- * @ cir_lut: pointer to circular filter LUT
- * @ sep_lut: pointer to separable filter LUT
- * @ de: detail enhancer configuration
- */
-struct sde_hw_scaler3_cfg {
- u32 enable;
- u32 dir_en;
- int32_t init_phase_x[SDE_MAX_PLANES];
- int32_t phase_step_x[SDE_MAX_PLANES];
- int32_t init_phase_y[SDE_MAX_PLANES];
- int32_t phase_step_y[SDE_MAX_PLANES];
-
- u32 preload_x[SDE_MAX_PLANES];
- u32 preload_y[SDE_MAX_PLANES];
- u32 src_width[SDE_MAX_PLANES];
- u32 src_height[SDE_MAX_PLANES];
-
- u32 dst_width;
- u32 dst_height;
-
- u32 y_rgb_filter_cfg;
- u32 uv_filter_cfg;
- u32 alpha_filter_cfg;
- u32 blend_cfg;
-
- u32 lut_flag;
- u32 dir_lut_idx;
-
- u32 y_rgb_cir_lut_idx;
- u32 uv_cir_lut_idx;
- u32 y_rgb_sep_lut_idx;
- u32 uv_sep_lut_idx;
- u32 *dir_lut;
- size_t dir_len;
- u32 *cir_lut;
- size_t cir_len;
- u32 *sep_lut;
- size_t sep_len;
-
- /*
- * Detail enhancer settings
- */
- struct sde_hw_scaler3_de_cfg de;
-};
-
-/**
* struct sde_hw_pipe_cfg : Pipe description
* @layout: format layout information for programming buffer to hardware
* @src_rect: src ROI, caller takes into account the different operations
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.c b/drivers/gpu/drm/msm/sde/sde_hw_util.c
index 7df5736..08fe5e1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.c
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include <uapi/drm/sde_drm.h>
#include "msm_drv.h"
#include "sde_kms.h"
#include "sde_hw_mdss.h"
@@ -18,6 +20,57 @@
/* using a file static variables for debugfs access */
static u32 sde_hw_util_log_mask = SDE_DBG_MASK_NONE;
+/* SDE_SCALER_QSEED3 */
+#define QSEED3_HW_VERSION 0x00
+#define QSEED3_OP_MODE 0x04
+#define QSEED3_RGB2Y_COEFF 0x08
+#define QSEED3_PHASE_INIT 0x0C
+#define QSEED3_PHASE_STEP_Y_H 0x10
+#define QSEED3_PHASE_STEP_Y_V 0x14
+#define QSEED3_PHASE_STEP_UV_H 0x18
+#define QSEED3_PHASE_STEP_UV_V 0x1C
+#define QSEED3_PRELOAD 0x20
+#define QSEED3_DE_SHARPEN 0x24
+#define QSEED3_DE_SHARPEN_CTL 0x28
+#define QSEED3_DE_SHAPE_CTL 0x2C
+#define QSEED3_DE_THRESHOLD 0x30
+#define QSEED3_DE_ADJUST_DATA_0 0x34
+#define QSEED3_DE_ADJUST_DATA_1 0x38
+#define QSEED3_DE_ADJUST_DATA_2 0x3C
+#define QSEED3_SRC_SIZE_Y_RGB_A 0x40
+#define QSEED3_SRC_SIZE_UV 0x44
+#define QSEED3_DST_SIZE 0x48
+#define QSEED3_COEF_LUT_CTRL 0x4C
+#define QSEED3_COEF_LUT_SWAP_BIT 0
+#define QSEED3_COEF_LUT_DIR_BIT 1
+#define QSEED3_COEF_LUT_Y_CIR_BIT 2
+#define QSEED3_COEF_LUT_UV_CIR_BIT 3
+#define QSEED3_COEF_LUT_Y_SEP_BIT 4
+#define QSEED3_COEF_LUT_UV_SEP_BIT 5
+#define QSEED3_BUFFER_CTRL 0x50
+#define QSEED3_CLK_CTRL0 0x54
+#define QSEED3_CLK_CTRL1 0x58
+#define QSEED3_CLK_STATUS 0x5C
+#define QSEED3_MISR_CTRL 0x70
+#define QSEED3_MISR_SIGNATURE_0 0x74
+#define QSEED3_MISR_SIGNATURE_1 0x78
+#define QSEED3_PHASE_INIT_Y_H 0x90
+#define QSEED3_PHASE_INIT_Y_V 0x94
+#define QSEED3_PHASE_INIT_UV_H 0x98
+#define QSEED3_PHASE_INIT_UV_V 0x9C
+#define QSEED3_COEF_LUT 0x100
+#define QSEED3_FILTERS 5
+#define QSEED3_LUT_REGIONS 4
+#define QSEED3_CIRCULAR_LUTS 9
+#define QSEED3_SEPARABLE_LUTS 10
+#define QSEED3_LUT_SIZE 60
+#define QSEED3_ENABLE 2
+#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32))
+#define QSEED3_CIR_LUT_SIZE \
+ (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32))
+#define QSEED3_SEP_LUT_SIZE \
+ (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32))
+
void sde_reg_write(struct sde_hw_blk_reg_map *c,
u32 reg_off,
u32 val,
@@ -40,6 +93,283 @@
return &sde_hw_util_log_mask;
}
+void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg,
+ const struct sde_drm_scaler_v2 *scale_v2)
+{
+ int i;
+
+ cfg->enable = scale_v2->enable;
+ cfg->dir_en = scale_v2->dir_en;
+
+ for (i = 0; i < SDE_MAX_PLANES; i++) {
+ cfg->init_phase_x[i] = scale_v2->init_phase_x[i];
+ cfg->phase_step_x[i] = scale_v2->phase_step_x[i];
+ cfg->init_phase_y[i] = scale_v2->init_phase_y[i];
+ cfg->phase_step_y[i] = scale_v2->phase_step_y[i];
+
+ cfg->preload_x[i] = scale_v2->preload_x[i];
+ cfg->preload_y[i] = scale_v2->preload_y[i];
+ cfg->src_width[i] = scale_v2->src_width[i];
+ cfg->src_height[i] = scale_v2->src_height[i];
+ }
+
+ cfg->dst_width = scale_v2->dst_width;
+ cfg->dst_height = scale_v2->dst_height;
+
+ cfg->y_rgb_filter_cfg = scale_v2->y_rgb_filter_cfg;
+ cfg->uv_filter_cfg = scale_v2->uv_filter_cfg;
+ cfg->alpha_filter_cfg = scale_v2->alpha_filter_cfg;
+ cfg->blend_cfg = scale_v2->blend_cfg;
+
+ cfg->lut_flag = scale_v2->lut_flag;
+ cfg->dir_lut_idx = scale_v2->dir_lut_idx;
+ cfg->y_rgb_cir_lut_idx = scale_v2->y_rgb_cir_lut_idx;
+ cfg->uv_cir_lut_idx = scale_v2->uv_cir_lut_idx;
+ cfg->y_rgb_sep_lut_idx = scale_v2->y_rgb_sep_lut_idx;
+ cfg->uv_sep_lut_idx = scale_v2->uv_sep_lut_idx;
+
+ cfg->de.enable = scale_v2->de.enable;
+ cfg->de.sharpen_level1 = scale_v2->de.sharpen_level1;
+ cfg->de.sharpen_level2 = scale_v2->de.sharpen_level2;
+ cfg->de.clip = scale_v2->de.clip;
+ cfg->de.limit = scale_v2->de.limit;
+ cfg->de.thr_quiet = scale_v2->de.thr_quiet;
+ cfg->de.thr_dieout = scale_v2->de.thr_dieout;
+ cfg->de.thr_low = scale_v2->de.thr_low;
+ cfg->de.thr_high = scale_v2->de.thr_high;
+ cfg->de.prec_shift = scale_v2->de.prec_shift;
+
+ for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
+ cfg->de.adjust_a[i] = scale_v2->de.adjust_a[i];
+ cfg->de.adjust_b[i] = scale_v2->de.adjust_b[i];
+ cfg->de.adjust_c[i] = scale_v2->de.adjust_c[i];
+ }
+}
+
+static void _sde_hw_setup_scaler3_lut(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset)
+{
+ int i, j, filter;
+ int config_lut = 0x0;
+ unsigned long lut_flags;
+ u32 lut_addr, lut_offset, lut_len;
+ u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL};
+ static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = {
+ {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} },
+ {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} },
+ {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} },
+ {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} },
+ {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} },
+ };
+
+ lut_flags = (unsigned long) scaler3_cfg->lut_flag;
+ if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) &&
+ (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) {
+ lut[0] = scaler3_cfg->dir_lut;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) &&
+ (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
+ (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
+ lut[1] = scaler3_cfg->cir_lut +
+ scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) &&
+ (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) &&
+ (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) {
+ lut[2] = scaler3_cfg->cir_lut +
+ scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) &&
+ (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
+ (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
+ lut[3] = scaler3_cfg->sep_lut +
+ scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+ if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) &&
+ (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) &&
+ (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) {
+ lut[4] = scaler3_cfg->sep_lut +
+ scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE;
+ config_lut = 1;
+ }
+
+ if (config_lut) {
+ for (filter = 0; filter < QSEED3_FILTERS; filter++) {
+ if (!lut[filter])
+ continue;
+ lut_offset = 0;
+ for (i = 0; i < QSEED3_LUT_REGIONS; i++) {
+ lut_addr = QSEED3_COEF_LUT + offset
+ + off_tbl[filter][i][1];
+ lut_len = off_tbl[filter][i][0] << 2;
+ for (j = 0; j < lut_len; j++) {
+ SDE_REG_WRITE(c,
+ lut_addr,
+ (lut[filter])[lut_offset++]);
+ lut_addr += 4;
+ }
+ }
+ }
+ }
+
+ if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags))
+ SDE_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0));
+
+}
+
+static void _sde_hw_setup_scaler3_de(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_de_cfg *de_cfg, u32 offset)
+{
+ u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr;
+ u32 adjust_a, adjust_b, adjust_c;
+
+ if (!de_cfg->enable)
+ return;
+
+ sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) |
+ ((de_cfg->sharpen_level2 & 0x1FF) << 16);
+
+ sharp_ctl = ((de_cfg->limit & 0xF) << 9) |
+ ((de_cfg->prec_shift & 0x7) << 13) |
+ ((de_cfg->clip & 0x7) << 16);
+
+ shape_ctl = (de_cfg->thr_quiet & 0xFF) |
+ ((de_cfg->thr_dieout & 0x3FF) << 16);
+
+ de_thr = (de_cfg->thr_low & 0x3FF) |
+ ((de_cfg->thr_high & 0x3FF) << 16);
+
+ adjust_a = (de_cfg->adjust_a[0] & 0x3FF) |
+ ((de_cfg->adjust_a[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_a[2] & 0x3FF) << 20);
+
+ adjust_b = (de_cfg->adjust_b[0] & 0x3FF) |
+ ((de_cfg->adjust_b[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_b[2] & 0x3FF) << 20);
+
+ adjust_c = (de_cfg->adjust_c[0] & 0x3FF) |
+ ((de_cfg->adjust_c[1] & 0x3FF) << 10) |
+ ((de_cfg->adjust_c[2] & 0x3FF) << 20);
+
+ SDE_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl);
+ SDE_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl);
+ SDE_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl);
+ SDE_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b);
+ SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c);
+
+}
+
+void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg,
+ u32 scaler_offset, u32 scaler_version,
+ const struct sde_format *format)
+{
+ u32 op_mode = 0;
+ u32 phase_init, preload, src_y_rgb, src_uv, dst;
+
+ if (!scaler3_cfg->enable)
+ goto end;
+
+ op_mode |= BIT(0);
+ op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16;
+
+ if (format && SDE_FORMAT_IS_YUV(format)) {
+ op_mode |= BIT(12);
+ op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24;
+ }
+
+ op_mode |= (scaler3_cfg->blend_cfg & 1) << 31;
+ op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0;
+
+ preload =
+ ((scaler3_cfg->preload_x[0] & 0x7F) << 0) |
+ ((scaler3_cfg->preload_y[0] & 0x7F) << 8) |
+ ((scaler3_cfg->preload_x[1] & 0x7F) << 16) |
+ ((scaler3_cfg->preload_y[1] & 0x7F) << 24);
+
+ src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) |
+ ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16);
+
+ src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) |
+ ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16);
+
+ dst = (scaler3_cfg->dst_width & 0x1FFFF) |
+ ((scaler3_cfg->dst_height & 0x1FFFF) << 16);
+
+ if (scaler3_cfg->de.enable) {
+ _sde_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset);
+ op_mode |= BIT(8);
+ }
+
+ if (scaler3_cfg->lut_flag)
+ _sde_hw_setup_scaler3_lut(c, scaler3_cfg,
+ scaler_offset);
+
+ if (scaler_version == 0x1002) {
+ phase_init =
+ ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) |
+ ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) |
+ ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) |
+ ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init);
+ } else {
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset,
+ scaler3_cfg->init_phase_x[0] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset,
+ scaler3_cfg->init_phase_y[0] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset,
+ scaler3_cfg->init_phase_x[1] & 0x1FFFFF);
+ SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset,
+ scaler3_cfg->init_phase_y[1] & 0x1FFFFF);
+ }
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset,
+ scaler3_cfg->phase_step_x[0] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset,
+ scaler3_cfg->phase_step_y[0] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset,
+ scaler3_cfg->phase_step_x[1] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset,
+ scaler3_cfg->phase_step_y[1] & 0xFFFFFF);
+
+ SDE_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload);
+
+ SDE_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb);
+
+ SDE_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv);
+
+ SDE_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst);
+
+end:
+ if (format && !SDE_FORMAT_IS_DX(format))
+ op_mode |= BIT(14);
+
+ if (format && format->alpha_enable) {
+ op_mode |= BIT(10);
+ if (scaler_version == 0x1002)
+ op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30;
+ else
+ op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29;
+ }
+
+ SDE_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode);
+}
+
+u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c,
+ u32 scaler_offset)
+{
+ return SDE_REG_READ(c, QSEED3_HW_VERSION + scaler_offset);
+}
+
void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c,
u32 csc_reg_off,
struct sde_csc_cfg *data, bool csc10)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h
index aa3d5b9..720e113 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h
@@ -39,6 +39,125 @@
u32 log_mask;
};
+/**
+ * struct sde_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration
+ * @enable: detail enhancer enable/disable
+ * @sharpen_level1: sharpening strength for noise
+ * @sharpen_level2: sharpening strength for signal
+ * @ clip: clip shift
+ * @ limit: limit value
+ * @ thr_quiet: quiet threshold
+ * @ thr_dieout: dieout threshold
+ * @ thr_high: low threshold
+ * @ thr_high: high threshold
+ * @ prec_shift: precision shift
+ * @ adjust_a: A-coefficients for mapping curve
+ * @ adjust_b: B-coefficients for mapping curve
+ * @ adjust_c: C-coefficients for mapping curve
+ */
+struct sde_hw_scaler3_de_cfg {
+ u32 enable;
+ int16_t sharpen_level1;
+ int16_t sharpen_level2;
+ uint16_t clip;
+ uint16_t limit;
+ uint16_t thr_quiet;
+ uint16_t thr_dieout;
+ uint16_t thr_low;
+ uint16_t thr_high;
+ uint16_t prec_shift;
+ int16_t adjust_a[SDE_MAX_DE_CURVES];
+ int16_t adjust_b[SDE_MAX_DE_CURVES];
+ int16_t adjust_c[SDE_MAX_DE_CURVES];
+};
+
+
+/**
+ * struct sde_hw_scaler3_cfg : QSEEDv3 configuration
+ * @enable: scaler enable
+ * @dir_en: direction detection block enable
+ * @ init_phase_x: horizontal initial phase
+ * @ phase_step_x: horizontal phase step
+ * @ init_phase_y: vertical initial phase
+ * @ phase_step_y: vertical phase step
+ * @ preload_x: horizontal preload value
+ * @ preload_y: vertical preload value
+ * @ src_width: source width
+ * @ src_height: source height
+ * @ dst_width: destination width
+ * @ dst_height: destination height
+ * @ y_rgb_filter_cfg: y/rgb plane filter configuration
+ * @ uv_filter_cfg: uv plane filter configuration
+ * @ alpha_filter_cfg: alpha filter configuration
+ * @ blend_cfg: blend coefficients configuration
+ * @ lut_flag: scaler LUT update flags
+ * 0x1 swap LUT bank
+ * 0x2 update 2D filter LUT
+ * 0x4 update y circular filter LUT
+ * 0x8 update uv circular filter LUT
+ * 0x10 update y separable filter LUT
+ * 0x20 update uv separable filter LUT
+ * @ dir_lut_idx: 2D filter LUT index
+ * @ y_rgb_cir_lut_idx: y circular filter LUT index
+ * @ uv_cir_lut_idx: uv circular filter LUT index
+ * @ y_rgb_sep_lut_idx: y circular filter LUT index
+ * @ uv_sep_lut_idx: uv separable filter LUT index
+ * @ dir_lut: pointer to 2D LUT
+ * @ cir_lut: pointer to circular filter LUT
+ * @ sep_lut: pointer to separable filter LUT
+ * @ de: detail enhancer configuration
+ */
+struct sde_hw_scaler3_cfg {
+ u32 enable;
+ u32 dir_en;
+ int32_t init_phase_x[SDE_MAX_PLANES];
+ int32_t phase_step_x[SDE_MAX_PLANES];
+ int32_t init_phase_y[SDE_MAX_PLANES];
+ int32_t phase_step_y[SDE_MAX_PLANES];
+
+ u32 preload_x[SDE_MAX_PLANES];
+ u32 preload_y[SDE_MAX_PLANES];
+ u32 src_width[SDE_MAX_PLANES];
+ u32 src_height[SDE_MAX_PLANES];
+
+ u32 dst_width;
+ u32 dst_height;
+
+ u32 y_rgb_filter_cfg;
+ u32 uv_filter_cfg;
+ u32 alpha_filter_cfg;
+ u32 blend_cfg;
+
+ u32 lut_flag;
+ u32 dir_lut_idx;
+
+ u32 y_rgb_cir_lut_idx;
+ u32 uv_cir_lut_idx;
+ u32 y_rgb_sep_lut_idx;
+ u32 uv_sep_lut_idx;
+ u32 *dir_lut;
+ size_t dir_len;
+ u32 *cir_lut;
+ size_t cir_len;
+ u32 *sep_lut;
+ size_t sep_len;
+
+ /*
+ * Detail enhancer settings
+ */
+ struct sde_hw_scaler3_de_cfg de;
+};
+
+struct sde_hw_scaler3_lut_cfg {
+ bool is_configured;
+ u32 *dir_lut;
+ size_t dir_len;
+ u32 *cir_lut;
+ size_t cir_len;
+ u32 *sep_lut;
+ size_t sep_len;
+};
+
u32 *sde_hw_util_get_log_mask_ptr(void);
void sde_reg_write(struct sde_hw_blk_reg_map *c,
@@ -58,6 +177,17 @@
void *sde_hw_util_get_dir(void);
+void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg,
+ const struct sde_drm_scaler_v2 *scale_v2);
+
+void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c,
+ struct sde_hw_scaler3_cfg *scaler3_cfg,
+ u32 scaler_offset, u32 scaler_version,
+ const struct sde_format *format);
+
+u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c,
+ u32 scaler_offset);
+
void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c,
u32 csc_reg_off,
struct sde_csc_cfg *data, bool csc10);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index a121b2e..edd1611 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -878,7 +878,6 @@
return -EINVAL;
break;
case SDE_DRM_FB_SEC_DIR_TRANS:
- case SDE_DRM_FB_NON_SEC_DIR_TRANS:
*aspace = NULL;
break;
default:
@@ -1519,7 +1518,7 @@
* @plane: Pointer to drm plane
* return: prefill time in line
*/
-static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
+u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
{
struct drm_plane_state *state;
struct sde_plane_state *pstate;
@@ -1548,33 +1547,19 @@
&blocksize, &blocksize);
prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
-
- SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
+ prefill_line = mult_frac(prefill_line, rstate->out_src_h >> 16,
+ state->crtc_h);
+ SDE_DEBUG(
+ "plane%d.%d blk:%u head:%u vdst/vsrc:%u/%u prefill:%u\n",
+ plane->base.id, rstate->sequence_id,
+ blocksize, sde_kms->catalog->sbuf_headroom,
+ state->crtc_h, rstate->out_src_h >> 16,
+ prefill_line);
return prefill_line;
}
/**
- * sde_plane_is_sbuf_mode - check if sspp of given plane is in streaming
- * buffer mode
- * @plane: Pointer to drm plane
- * @prefill: Pointer to prefill line count
- * return: true if sspp is in stream buffer mode
- */
-bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill)
-{
- struct sde_plane_state *pstate = plane && plane->state ?
- to_sde_plane_state(plane->state) : NULL;
- struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
- bool sbuf_mode = rstate ? rstate->out_sbuf : false;
-
- if (prefill)
- *prefill = sde_plane_rot_calc_prefill(plane);
-
- return sbuf_mode;
-}
-
-/**
* sde_plane_rot_calc_cfg - calculate rotator/sspp configuration by
* enumerating over all planes attached to the same rotator
* @plane: Pointer to drm plane
@@ -2753,7 +2738,7 @@
return;
*flush_rot = 0x0;
- if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
+ if (rstate && rstate->out_sbuf && rstate->rot_hw &&
ctl->ops.get_bitmask_rot)
ctl->ops.get_bitmask_rot(ctl, flush_rot, rstate->rot_hw->idx);
}
@@ -2791,6 +2776,18 @@
new_rstate = &to_sde_plane_state(new_state)->rot;
if (pstate->aspace) {
+ /*
+ * when transitioning from secure to non-secure,
+ * plane->prepare_fb happens before the commit. In such case,
+ * return early, as prepare_fb would be handled as part
+ * of the transition after attaching the domains,
+ * during the commit
+ */
+ if (!pstate->aspace->domain_attached) {
+ SDE_DEBUG_PLANE(psde,
+ "domain not attached, prepare_fb handled later\n");
+ return 0;
+ }
ret = msm_framebuffer_prepare(new_rstate->out_fb,
pstate->aspace);
if (ret) {
@@ -4067,51 +4064,11 @@
&pstate->property_state, PLANE_PROP_SCALER_V2);
/* populate from user space */
+ sde_set_scaler_v2(cfg, &scale_v2);
+
pe = &pstate->pixel_ext;
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
- cfg->enable = scale_v2.enable;
- cfg->dir_en = scale_v2.dir_en;
- for (i = 0; i < SDE_MAX_PLANES; i++) {
- cfg->init_phase_x[i] = scale_v2.init_phase_x[i];
- cfg->phase_step_x[i] = scale_v2.phase_step_x[i];
- cfg->init_phase_y[i] = scale_v2.init_phase_y[i];
- cfg->phase_step_y[i] = scale_v2.phase_step_y[i];
- cfg->preload_x[i] = scale_v2.preload_x[i];
- cfg->preload_y[i] = scale_v2.preload_y[i];
- cfg->src_width[i] = scale_v2.src_width[i];
- cfg->src_height[i] = scale_v2.src_height[i];
- }
- cfg->dst_width = scale_v2.dst_width;
- cfg->dst_height = scale_v2.dst_height;
-
- cfg->y_rgb_filter_cfg = scale_v2.y_rgb_filter_cfg;
- cfg->uv_filter_cfg = scale_v2.uv_filter_cfg;
- cfg->alpha_filter_cfg = scale_v2.alpha_filter_cfg;
- cfg->blend_cfg = scale_v2.blend_cfg;
-
- cfg->lut_flag = scale_v2.lut_flag;
- cfg->dir_lut_idx = scale_v2.dir_lut_idx;
- cfg->y_rgb_cir_lut_idx = scale_v2.y_rgb_cir_lut_idx;
- cfg->uv_cir_lut_idx = scale_v2.uv_cir_lut_idx;
- cfg->y_rgb_sep_lut_idx = scale_v2.y_rgb_sep_lut_idx;
- cfg->uv_sep_lut_idx = scale_v2.uv_sep_lut_idx;
-
- cfg->de.enable = scale_v2.de.enable;
- cfg->de.sharpen_level1 = scale_v2.de.sharpen_level1;
- cfg->de.sharpen_level2 = scale_v2.de.sharpen_level2;
- cfg->de.clip = scale_v2.de.clip;
- cfg->de.limit = scale_v2.de.limit;
- cfg->de.thr_quiet = scale_v2.de.thr_quiet;
- cfg->de.thr_dieout = scale_v2.de.thr_dieout;
- cfg->de.thr_low = scale_v2.de.thr_low;
- cfg->de.thr_high = scale_v2.de.thr_high;
- cfg->de.prec_shift = scale_v2.de.prec_shift;
- for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
- cfg->de.adjust_a[i] = scale_v2.de.adjust_a[i];
- cfg->de.adjust_b[i] = scale_v2.de.adjust_b[i];
- cfg->de.adjust_c[i] = scale_v2.de.adjust_c[i];
- }
for (i = 0; i < SDE_MAX_PLANES; i++) {
pe->left_ftch[i] = scale_v2.pe.left_ftch[i];
pe->right_ftch[i] = scale_v2.pe.right_ftch[i];
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 913647f..c956345 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -207,12 +207,11 @@
u32 *flush_sspp, u32 *flush_rot);
/**
- * sde_plane_is_sbuf_mode - return status of stream buffer mode
- * @plane: Pointer to DRM plane object
- * @prefill: Pointer to updated prefill in stream buffer mode (optional)
- * Returns: true if plane is in stream buffer mode
+ * sde_plane_rot_calc_prefill - calculate rotator start prefill
+ * @plane: Pointer to drm plane
+ * return: prefill time in line
*/
-bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill);
+u32 sde_plane_rot_calc_prefill(struct drm_plane *plane);
/**
* sde_plane_restore - restore hw state if previously power collapsed
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 768dfbd..7143a8b 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -3075,7 +3075,7 @@
dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
dbg->dbgbus_vbif_rt.cmn.entries_size =
ARRAY_SIZE(vbif_dbg_bus_msm8998);
- } else if (IS_SDM845_TARGET(hwversion)) {
+ } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) {
dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845;
dbg->dbgbus_sde.cmn.entries_size =
ARRAY_SIZE(dbg_bus_sde_sdm845);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7316fc7..a2ec6d8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -149,8 +149,8 @@
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
/* Signal polarities */
- value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
- | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
+ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
+ | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
| DSMR_DIPM_DISP | DSMR_CSPM;
rcar_du_crtc_write(rcrtc, DSMR, value);
@@ -172,7 +172,7 @@
mode->crtc_vsync_start - 1);
rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1);
- rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
+ rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start - 1);
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index cfc302c..c58602b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -453,13 +453,13 @@
}
ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
- of_node_put(encoder);
- of_node_put(connector);
-
if (ret && ret != -EPROBE_DEFER)
dev_warn(rcdu->dev,
- "failed to initialize encoder %s (%d), skipping\n",
- encoder->full_name, ret);
+ "failed to initialize encoder %s on output %u (%d), skipping\n",
+ of_node_full_name(encoder), output, ret);
+
+ of_node_put(encoder);
+ of_node_put(connector);
return ret;
}
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index a37de5d..ddd6badd 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -612,7 +612,7 @@
} else {
pr_err("Failed to fill pool (%p)\n", pool);
/* If we have any pages left put them to the pool. */
- list_for_each_entry(p, &pool->list, lru) {
+ list_for_each_entry(p, &new_pages, lru) {
++cpages;
}
list_splice(&new_pages, &pool->list);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index 2242a80..dc2976c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -337,7 +337,7 @@
info->fbops = &virtio_gpufb_ops;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->screen_base = obj->vmap;
+ info->screen_buffer = obj->vmap;
info->screen_size = obj->gem_base.size;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &vfbdev->helper,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d16e42d..780cefe 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2464,7 +2464,7 @@
dev_err(device->dev, " hwfault=%8.8X\n", hwfault);
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, adreno_gmu_gpu_fault(adreno_dev));
}
/**
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 36bd656..49dc5ed 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1329,6 +1329,10 @@
smp_wmb();
}
+static inline bool adreno_gmu_gpu_fault(struct adreno_device *adreno_dev)
+{
+ return adreno_gpu_fault(adreno_dev) & ADRENO_GMU_FAULT;
+}
/**
* adreno_clear_gpu_fault() - Clear the GPU fault register
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5d7fb21..356d7c2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -685,7 +685,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
dev_err(device->dev, "CP initialization failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
return ret;
@@ -1823,7 +1823,7 @@
if (ret) {
KGSL_DRV_ERR(device, "microcode bootstrap failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
/* Clear the chicken bit for speed up on A430 and its derivatives */
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index c807b67..0cf909e 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -1535,7 +1535,7 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
dev_err(device->dev, "CP initialization failed to idle\n");
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, false);
}
return ret;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 12824b0..b9df4ec 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1943,9 +1943,7 @@
/* If SPTP_RAC is on, turn off SPTP_RAC HS */
a6xx_sptprac_disable(adreno_dev);
- /* Disconnect GPU from BUS. Clear and reconnected after reset */
- adreno_vbif_clear_pending_transactions(device);
- /* Unnecessary: a6xx_soft_reset(adreno_dev); */
+ /* Disconnect GPU from BUS is not needed if CX GDSC goes off later */
/* Check no outstanding RPMh voting */
a6xx_complete_rpmh_votes(device);
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 25aeaef..6bdc486 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2046,7 +2046,7 @@
kfree(replay);
}
-static void do_header_and_snapshot(struct kgsl_device *device,
+static void do_header_and_snapshot(struct kgsl_device *device, int fault,
struct adreno_ringbuffer *rb, struct kgsl_drawobj_cmd *cmdobj)
{
struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj);
@@ -2054,7 +2054,7 @@
/* Always dump the snapshot on a non-drawobj failure */
if (cmdobj == NULL) {
adreno_fault_header(device, rb, NULL);
- kgsl_device_snapshot(device, NULL);
+ kgsl_device_snapshot(device, NULL, fault & ADRENO_GMU_FAULT);
return;
}
@@ -2066,7 +2066,8 @@
adreno_fault_header(device, rb, cmdobj);
if (!(drawobj->context->flags & KGSL_CONTEXT_NO_SNAPSHOT))
- kgsl_device_snapshot(device, drawobj->context);
+ kgsl_device_snapshot(device, drawobj->context,
+ fault & ADRENO_GMU_FAULT);
}
static int dispatcher_do_fault(struct adreno_device *adreno_dev)
@@ -2192,7 +2193,7 @@
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &base);
- do_header_and_snapshot(device, hung_rb, cmdobj);
+ do_header_and_snapshot(device, fault, hung_rb, cmdobj);
/* Turn off the KEEPALIVE vote from the ISR for hard fault */
if (gpudev->gpu_keepalive && fault & ADRENO_HARD_FAULT)
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 0882447..2615d44 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -533,7 +533,8 @@
drawctxt->internal_timestamp,
drawctxt->type, ret);
device->force_panic = 1;
- kgsl_device_snapshot(device, context);
+ kgsl_device_snapshot(device, context,
+ adreno_gmu_gpu_fault(adreno_dev));
}
kgsl_sharedmem_writel(device, &device->memstore,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 8b87ee2..09c1ae6 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -25,6 +25,7 @@
#include "adreno_iommu.h"
#include "adreno_pm4types.h"
#include "adreno_ringbuffer.h"
+#include "adreno_trace.h"
#include "a3xx_reg.h"
#include "adreno_a5xx.h"
@@ -37,6 +38,7 @@
((_rb)->buffer_desc.gpuaddr + ((_pos) * sizeof(unsigned int)))
static void adreno_get_submit_time(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb,
struct adreno_submit_time *time)
{
unsigned long flags;
@@ -66,6 +68,9 @@
} else
time->ticks = 0;
+ /* Trace the GPU time to create a mapping to ftrace time */
+ trace_adreno_cmdbatch_sync(rb->drawctxt_active, time->ticks);
+
/* Get the kernel clock for time since boot */
time->ktime = local_clock();
@@ -148,7 +153,7 @@
struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
if (time != NULL)
- adreno_get_submit_time(adreno_dev, time);
+ adreno_get_submit_time(adreno_dev, rb, time);
adreno_ringbuffer_wptr(adreno_dev, rb);
}
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
index 7bc4c93..e33060a 100644
--- a/drivers/gpu/msm/adreno_trace.h
+++ b/drivers/gpu/msm/adreno_trace.h
@@ -148,6 +148,29 @@
)
);
+TRACE_EVENT(adreno_cmdbatch_sync,
+ TP_PROTO(struct adreno_context *drawctxt,
+ uint64_t ticks),
+ TP_ARGS(drawctxt, ticks),
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(unsigned int, timestamp)
+ __field(uint64_t, ticks)
+ __field(int, prio)
+ ),
+ TP_fast_assign(
+ __entry->id = drawctxt->base.id;
+ __entry->timestamp = drawctxt->timestamp;
+ __entry->ticks = ticks;
+ __entry->prio = drawctxt->base.priority;
+ ),
+ TP_printk(
+ "ctx=%u ctx_prio=%d ts=%u ticks=%lld",
+ __entry->id, __entry->prio, __entry->timestamp,
+ __entry->ticks
+ )
+);
+
TRACE_EVENT(adreno_cmdbatch_fault,
TP_PROTO(struct kgsl_drawobj_cmd *cmdobj, unsigned int fault),
TP_ARGS(cmdobj, fault),
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2cc1869..f8d5f5b 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -493,7 +493,9 @@
* @work: worker to dump the frozen memory
* @dump_gate: completion gate signaled by worker when it is finished.
* @process: the process that caused the hang, if known.
- * @sysfs_read: An atomic for concurrent snapshot reads via syfs.
+ * @sysfs_read: Count of current reads via sysfs
+ * @first_read: True until the snapshot read is started
+ * @gmu_fault: Snapshot collected when GMU fault happened
*/
struct kgsl_snapshot {
uint64_t ib1base;
@@ -514,7 +516,9 @@
struct work_struct work;
struct completion dump_gate;
struct kgsl_process_private *process;
- atomic_t sysfs_read;
+ unsigned int sysfs_read;
+ bool first_read;
+ bool gmu_fault;
};
/**
@@ -700,7 +704,7 @@
int kgsl_device_snapshot_init(struct kgsl_device *device);
void kgsl_device_snapshot(struct kgsl_device *device,
- struct kgsl_context *context);
+ struct kgsl_context *context, bool gmu_fault);
void kgsl_device_snapshot_close(struct kgsl_device *device);
void kgsl_snapshot_save_frozen_objs(struct work_struct *work);
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 9b04543..3bd7cf3 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -456,11 +456,12 @@
GMU_DCVS_NOHFI, perf_idx, bw_idx);
if (ret) {
- dev_err(&gmu->pdev->dev,
+ dev_err_ratelimited(&gmu->pdev->dev,
"Failed to set GPU perf idx %d, bw idx %d\n",
perf_idx, bw_idx);
- gmu_snapshot(device);
+ adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT);
+ adreno_dispatcher_schedule(device);
}
return ret;
@@ -1341,6 +1342,7 @@
gmu_disable_clks(gmu);
gmu_disable_gdsc(gmu);
+ dev_err(&gmu->pdev->dev, "Suspended GMU\n");
return 0;
}
@@ -1349,7 +1351,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
- if (!test_and_set_bit(GMU_FAULT, &gmu->flags)) {
+ if (!gmu->fault_count) {
/* Mask so there's no interrupt caused by NMI */
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
@@ -1364,7 +1366,7 @@
/* Wait for the NMI to be handled */
wmb();
udelay(100);
- kgsl_device_snapshot(device, ERR_PTR(-EINVAL));
+ kgsl_device_snapshot(device, ERR_PTR(-EINVAL), true);
adreno_write_gmureg(adreno_dev,
ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
@@ -1372,6 +1374,8 @@
ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
(unsigned int) ~HFI_IRQ_MASK);
}
+
+ gmu->fault_count++;
}
/* To be called to power on both GPU and GMU */
@@ -1389,32 +1393,29 @@
WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
/* Vote for 300MHz DDR for GMU to init */
ret = msm_bus_scale_client_update_request(gmu->pcl,
pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
- if (ret) {
+ if (ret)
dev_err(&gmu->pdev->dev,
- "Failed to allocate gmu b/w\n");
- goto error_clks;
- }
+ "Failed to allocate gmu b/w: %d\n", ret);
ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
GMU_COLD_BOOT, 0);
if (ret)
- goto error_bus;
-
- gmu_irq_enable(device);
+ goto error_gmu;
ret = hfi_start(gmu, GMU_COLD_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
/* Send default DCVS level */
ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel,
pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
msm_bus_scale_client_update_request(gmu->pcl, 0);
break;
@@ -1423,49 +1424,49 @@
WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
GMU_WARM_BOOT, 0);
if (ret)
- goto error_clks;
-
- gmu_irq_enable(device);
+ goto error_gmu;
ret = hfi_start(gmu, GMU_WARM_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel,
pwr->pwrlevels[gmu->wakeup_pwrlevel].bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
break;
case KGSL_STATE_RESET:
- if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv)) {
+ if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv) ||
+ test_bit(GMU_FAULT, &gmu->flags)) {
gmu_suspend(device);
gmu_enable_gdsc(gmu);
gmu_enable_clks(gmu);
+ gmu_irq_enable(device);
ret = gpudev->rpmh_gpu_pwrctrl(
adreno_dev, GMU_FW_START, GMU_RESET, 0);
if (ret)
- goto error_clks;
+ goto error_gmu;
- gmu_irq_enable(device);
ret = hfi_start(gmu, GMU_COLD_BOOT);
if (ret)
- goto error_gpu;
+ goto error_gmu;
/* Send DCVS level prior to reset*/
ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel,
pwr->pwrlevels[pwr->active_pwrlevel]
.bus_freq);
if (ret)
- goto error_gpu;
+ goto error_gmu;
ret = gpudev->oob_set(adreno_dev,
OOB_CPINIT_SET_MASK,
@@ -1485,20 +1486,8 @@
return ret;
-error_gpu:
+error_gmu:
gmu_snapshot(device);
- hfi_stop(gmu);
- gmu_irq_disable(device);
- if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
- gpudev->oob_clear(adreno_dev,
- OOB_BOOT_SLUMBER_CLEAR_MASK);
- gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
-error_bus:
- msm_bus_scale_client_update_request(gmu->pcl, 0);
-error_clks:
- gmu_snapshot(device);
- gmu_disable_clks(gmu);
- gmu_disable_gdsc(gmu);
return ret;
}
@@ -1535,18 +1524,30 @@
if (!idle || (gpudev->wait_for_gmu_idle &&
gpudev->wait_for_gmu_idle(adreno_dev))) {
dev_err(&gmu->pdev->dev, "Stopping GMU before it is idle\n");
+ idle = false;
+ set_bit(GMU_FAULT, &gmu->flags);
+ } else {
+ idle = true;
}
- /* Pending message in all queues are abandoned */
- hfi_stop(gmu);
- clear_bit(GMU_HFI_ON, &gmu->flags);
- gmu_irq_disable(device);
+ if (idle) {
+ /* Pending message in all queues are abandoned */
+ hfi_stop(gmu);
+ clear_bit(GMU_HFI_ON, &gmu->flags);
+ gmu_irq_disable(device);
- gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
- gmu_disable_clks(gmu);
- gmu_disable_gdsc(gmu);
-
- /* TODO: Vote CX, MX retention off */
+ gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
+ gmu_disable_clks(gmu);
+ gmu_disable_gdsc(gmu);
+ } else {
+ /*
+ * The power controller will change state to SLUMBER anyway
+ * Set GMU_FAULT flag to indicate to power contrller
+ * that hang recovery is needed to power on GPU
+ */
+ set_bit(GMU_FAULT, &gmu->flags);
+ gmu_snapshot(device);
+ }
msm_bus_scale_client_update_request(gmu->pcl, 0);
}
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index 63ca028..ff65f66 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -193,6 +193,7 @@
* @pcl: GPU BW scaling client
* @ccl: CNOC BW scaling client
* @idle_level: Minimal GPU idle power level
+ * @fault_count: GMU fault count
*/
struct gmu_device {
unsigned int ver;
@@ -226,6 +227,7 @@
unsigned int pcl;
unsigned int ccl;
unsigned int idle_level;
+ unsigned int fault_count;
};
bool kgsl_gmu_isenabled(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index 685ce3e..c31a85b 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -65,19 +65,26 @@
/* Map the page into kernel and zero it out */
static void
-_kgsl_pool_zero_page(struct page *p)
+_kgsl_pool_zero_page(struct page *p, unsigned int pool_order)
{
- void *addr = kmap_atomic(p);
+ int i;
- memset(addr, 0, PAGE_SIZE);
- dmac_flush_range(addr, addr + PAGE_SIZE);
- kunmap_atomic(addr);
+ for (i = 0; i < (1 << pool_order); i++) {
+ struct page *page = nth_page(p, i);
+ void *addr = kmap_atomic(page);
+
+ memset(addr, 0, PAGE_SIZE);
+ dmac_flush_range(addr, addr + PAGE_SIZE);
+ kunmap_atomic(addr);
+ }
}
/* Add a page to specified pool */
static void
_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
{
+ _kgsl_pool_zero_page(p, pool->pool_order);
+
spin_lock(&pool->list_lock);
list_add_tail(&p->lru, &pool->page_list);
pool->page_count++;
@@ -322,6 +329,7 @@
} else
return -ENOMEM;
}
+ _kgsl_pool_zero_page(page, order);
goto done;
}
@@ -341,6 +349,7 @@
page = alloc_pages(gfp_mask, order);
if (page == NULL)
return -ENOMEM;
+ _kgsl_pool_zero_page(page, order);
goto done;
}
}
@@ -370,12 +379,13 @@
} else
return -ENOMEM;
}
+
+ _kgsl_pool_zero_page(page, order);
}
done:
for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) {
p = nth_page(page, j);
- _kgsl_pool_zero_page(p);
pages[pcount] = p;
pcount++;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6e55395..007121c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2629,6 +2629,7 @@
_aware(struct kgsl_device *device)
{
int status = 0;
+ struct gmu_device *gmu = &device->gmu;
switch (device->state) {
case KGSL_STATE_RESET:
@@ -2648,15 +2649,42 @@
kgsl_pwrscale_midframe_timer_cancel(device);
break;
case KGSL_STATE_SLUMBER:
+ /* if GMU already in FAULT */
+ if (kgsl_gmu_isenabled(device) &&
+ test_bit(GMU_FAULT, &gmu->flags)) {
+ status = -EINVAL;
+ break;
+ }
+
status = kgsl_pwrctrl_enable(device);
break;
default:
status = -EINVAL;
}
- if (status)
+
+ if (status) {
+ if (kgsl_gmu_isenabled(device)) {
+ /* GMU hang recovery */
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
+ set_bit(GMU_FAULT, &gmu->flags);
+ status = kgsl_pwrctrl_enable(device);
+ if (status) {
+ /*
+ * Cannot recover GMU failure
+ * GPU will not be powered on
+ */
+ WARN_ONCE(1, "Failed to recover GMU\n");
+ }
+
+ clear_bit(GMU_FAULT, &gmu->flags);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+ return status;
+ }
+
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
- else
+ } else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+ }
return status;
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index e704db7..f9494a4 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -573,16 +573,34 @@
snapshot->size += header->size;
}
+static void kgsl_free_snapshot(struct kgsl_snapshot *snapshot)
+{
+ struct kgsl_snapshot_object *obj, *tmp;
+
+ wait_for_completion(&snapshot->dump_gate);
+
+ list_for_each_entry_safe(obj, tmp,
+ &snapshot->obj_list, node)
+ kgsl_snapshot_put_object(obj);
+
+ if (snapshot->mempool)
+ vfree(snapshot->mempool);
+
+ kfree(snapshot);
+ KGSL_CORE_ERR("snapshot: objects released\n");
+}
+
/**
* kgsl_snapshot() - construct a device snapshot
* @device: device to snapshot
* @context: the context that is hung, might be NULL if unknown.
+ * @gmu_fault: whether this snapshot is triggered by a GMU fault.
*
* Given a device, construct a binary snapshot dump of the current device state
* and store it in the device snapshot memory.
*/
void kgsl_device_snapshot(struct kgsl_device *device,
- struct kgsl_context *context)
+ struct kgsl_context *context, bool gmu_fault)
{
struct kgsl_snapshot_header *header = device->snapshot_memory.ptr;
struct kgsl_snapshot *snapshot;
@@ -603,11 +621,20 @@
device->snapshot_faultcount++;
/*
- * The first hang is always the one we are interested in. Don't capture
- * a new snapshot instance if the old one hasn't been grabbed yet
+ * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
*/
- if (device->snapshot != NULL)
- return;
+ if (device->snapshot != NULL) {
+ if (!gmu_fault || device->snapshot->gmu_fault)
+ return;
+
+ /*
+ * If another thread is currently reading it, that thread
+ * will free it, otherwise free it now.
+ */
+ if (!device->snapshot->sysfs_read)
+ kgsl_free_snapshot(device->snapshot);
+ device->snapshot = NULL;
+ }
/* Allocate memory for the snapshot instance */
snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
@@ -622,7 +649,9 @@
snapshot->start = device->snapshot_memory.ptr;
snapshot->ptr = device->snapshot_memory.ptr;
snapshot->remain = device->snapshot_memory.size;
- atomic_set(&snapshot->sysfs_read, 0);
+ snapshot->gmu_fault = gmu_fault;
+ snapshot->first_read = true;
+ snapshot->sysfs_read = 0;
header = (struct kgsl_snapshot_header *) snapshot->ptr;
@@ -711,6 +740,30 @@
#define kobj_to_device(a) \
container_of(a, struct kgsl_device, snapshot_kobj)
+static int snapshot_release(struct kgsl_device *device,
+ struct kgsl_snapshot *snapshot)
+{
+ bool snapshot_free = false;
+ int ret = 0;
+
+ mutex_lock(&device->mutex);
+ snapshot->sysfs_read--;
+
+ /*
+ * If someone's replaced the snapshot, return an error and free
+ * the snapshot if this is the last thread to read it.
+ */
+ if (device->snapshot != snapshot) {
+ ret = -EIO;
+ if (!snapshot->sysfs_read)
+ snapshot_free = true;
+ }
+ mutex_unlock(&device->mutex);
+ if (snapshot_free)
+ kgsl_free_snapshot(snapshot);
+ return ret;
+}
+
/* Dump the sysfs binary data to the user */
static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off,
@@ -718,20 +771,35 @@
{
struct kgsl_device *device = kobj_to_device(kobj);
struct kgsl_snapshot *snapshot;
- struct kgsl_snapshot_object *obj, *tmp;
struct kgsl_snapshot_section_header head;
struct snapshot_obj_itr itr;
- int ret;
+ int ret = 0;
if (device == NULL)
return 0;
mutex_lock(&device->mutex);
snapshot = device->snapshot;
- if (snapshot != NULL)
- atomic_inc(&snapshot->sysfs_read);
+ if (snapshot != NULL) {
+ /*
+ * If we're reading at a non-zero offset from a new snapshot,
+ * that means we want to read from the previous snapshot (which
+ * was overwritten), so return an error
+ */
+ if (snapshot->first_read) {
+ if (off)
+ ret = -EIO;
+ else
+ snapshot->first_read = false;
+ }
+ if (!ret)
+ snapshot->sysfs_read++;
+ }
mutex_unlock(&device->mutex);
+ if (ret)
+ return ret;
+
/* Return nothing if we haven't taken a snapshot yet */
if (snapshot == NULL)
return 0;
@@ -742,7 +810,7 @@
*/
ret = wait_for_completion_interruptible(&snapshot->dump_gate);
if (ret) {
- atomic_dec(&snapshot->sysfs_read);
+ snapshot_release(device, snapshot);
return ret;
}
@@ -779,29 +847,21 @@
bool snapshot_free = false;
mutex_lock(&device->mutex);
- if (atomic_dec_and_test(&snapshot->sysfs_read)) {
- device->snapshot = NULL;
+ if (--snapshot->sysfs_read == 0) {
+ if (device->snapshot == snapshot)
+ device->snapshot = NULL;
snapshot_free = true;
}
mutex_unlock(&device->mutex);
- if (snapshot_free) {
- list_for_each_entry_safe(obj, tmp,
- &snapshot->obj_list, node)
- kgsl_snapshot_put_object(obj);
-
- if (snapshot->mempool)
- vfree(snapshot->mempool);
-
- kfree(snapshot);
- KGSL_CORE_ERR("snapshot: objects released\n");
- }
+ if (snapshot_free)
+ kgsl_free_snapshot(snapshot);
return 0;
}
done:
- atomic_dec(&snapshot->sysfs_read);
- return itr.write;
+ ret = snapshot_release(device, snapshot);
+ return (ret < 0) ? ret : itr.write;
}
/* Show the total number of hangs since device boot */
@@ -872,9 +932,11 @@
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
- unsigned long timestamp =
- device->snapshot ? device->snapshot->timestamp : 0;
+ unsigned long timestamp;
+ mutex_lock(&device->mutex);
+ timestamp = device->snapshot ? device->snapshot->timestamp : 0;
+ mutex_unlock(&device->mutex);
return snprintf(buf, PAGE_SIZE, "%lu\n", timestamp);
}
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index ae494d7..8d242f8 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -156,6 +156,17 @@
occurrence. These events can be controlled by using module
parameters.
+config CORESIGHT_TGU
+ bool "CoreSight Trigger Generation Unit driver"
+ help
+ This driver provides support for Trigger Generation Unit that is
+ used to detect patterns or sequences on a given set of signals.
+ TGU is used to monitor a particular bus within a given region to
+ detect illegal transaction sequences or slave responses. It is also
+ used to monitor a data stream to detect protocol violations and to
+ provide a trigger point for centering data around a specific event
+ within the trace data buffer.
+
config CORESIGHT_CSR
bool "CoreSight Slave Register driver"
help
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 0b5e434..44e55ff 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -21,6 +21,7 @@
obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
+obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
diff --git a/drivers/hwtracing/coresight/coresight-tgu.c b/drivers/hwtracing/coresight/coresight-tgu.c
new file mode 100644
index 0000000..e919f47
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tgu.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/amba/bus.h>
+#include <linux/topology.h>
+#include <linux/of.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define tgu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
+#define tgu_readl(drvdata, off) __raw_readl(drvdata->base + off)
+
+#define TGU_LOCK(drvdata) \
+do { \
+ mb(); /* ensure configuration take effect before we lock it */ \
+ tgu_writel(drvdata, 0x0, CORESIGHT_LAR); \
+} while (0)
+#define TGU_UNLOCK(drvdata) \
+do { \
+ tgu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ mb(); /* ensure unlock take effect before we configure */ \
+} while (0)
+
+#define TGU_CONTROL 0x0000
+#define TIMER0_STATUS 0x0004
+#define COUNTER0_STATUS 0x000C
+#define TGU_STATUS 0x0014
+#define TIMER0_COMPARE_STEP(n) (0x0040 + 0x1D8 * n)
+#define COUNTER0_COMPARE_STEP(n) (0x0048 + 0x1D8 * n)
+#define GROUP_REG_STEP(grp, reg, step) (0x0074 + 0x60 * grp + 0x4 * reg + \
+ 0x1D8 * step)
+#define CONDITION_DECODE_STEP(m, n) (0x0050 + 0x4 * m + 0x1D8 * n)
+#define CONDITION_SELECT_STEP(m, n) (0x0060 + 0x4 * m + 0x1D8 * n)
+#define GROUP0 0x0074
+#define GROUP1 0x00D4
+#define GROUP2 0x0134
+#define GROUP3 0x0194
+#define TGU_LAR 0x0FB0
+
+#define MAX_GROUP_SETS 256
+#define MAX_GROUPS 4
+#define MAX_CONDITION_SETS 64
+#define MAX_TIMER_COUNTER_SETS 8
+
+#define to_tgu_drvdata(c) container_of(c, struct tgu_drvdata, tgu)
+
+struct Trigger_group_data {
+ unsigned long grpaddr;
+ unsigned long value;
+};
+
+struct Trigger_condition_data {
+ unsigned long condaddr;
+ unsigned long value;
+};
+
+struct Trigger_select_data {
+ unsigned long selectaddr;
+ unsigned long value;
+};
+
+struct Trigger_timer_data {
+ unsigned long timeraddr;
+ unsigned long value;
+};
+
+struct Trigger_counter_data {
+ unsigned long counteraddr;
+ unsigned long value;
+};
+struct tgu_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ struct clk *clk;
+ spinlock_t spinlock;
+ int max_steps;
+ int max_conditions;
+ int max_regs;
+ int max_timer_counter;
+ struct Trigger_group_data *grp_data;
+ struct Trigger_condition_data *condition_data;
+ struct Trigger_select_data *select_data;
+ struct Trigger_timer_data *timer_data;
+ struct Trigger_counter_data *counter_data;
+ int grp_refcnt;
+ int cond_refcnt;
+ int select_refcnt;
+ int timer_refcnt;
+ int counter_refcnt;
+ bool enable;
+};
+
+static ssize_t enable_tgu(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long value;
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int ret, i, j;
+
+ if (kstrtoul(buf, 16, &value))
+ return -EINVAL;
+
+ /* Enable clock */
+ ret = pm_runtime_get_sync(drvdata->dev);
+ if (ret)
+ return ret;
+
+ spin_lock(&drvdata->spinlock);
+ /* Unlock the TGU LAR */
+ TGU_UNLOCK(drvdata);
+
+ if (value) {
+
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+
+ /* program the TGU Group data for the desired use case*/
+
+ for (i = 0; i <= drvdata->grp_refcnt; i++)
+ tgu_writel(drvdata, drvdata->grp_data[i].value,
+ drvdata->grp_data[i].grpaddr);
+
+ /* program the unused Condition Decode registers NOT bits to 1*/
+ for (i = 0; i <= drvdata->max_conditions; i++) {
+ for (j = 0; j <= drvdata->max_steps; j++)
+ tgu_writel(drvdata, 0x1000000,
+ CONDITION_DECODE_STEP(i, j));
+ }
+ /* program the TGU Condition Decode for the desired use case*/
+ for (i = 0; i <= drvdata->cond_refcnt; i++)
+ tgu_writel(drvdata, drvdata->condition_data[i].value,
+ drvdata->condition_data[i].condaddr);
+
+ /* program the TGU Condition Select for the desired use case*/
+ for (i = 0; i <= drvdata->select_refcnt; i++)
+ tgu_writel(drvdata, drvdata->select_data[i].value,
+ drvdata->select_data[i].selectaddr);
+
+ /* Timer and Counter Check */
+ for (i = 0; i <= drvdata->timer_refcnt; i++)
+ tgu_writel(drvdata, drvdata->timer_data[i].value,
+ drvdata->timer_data[i].timeraddr);
+
+ for (i = 0; i <= drvdata->counter_refcnt; i++)
+ tgu_writel(drvdata, drvdata->counter_data[i].value,
+ drvdata->counter_data[i].counteraddr);
+
+ /* Enable TGU to program the triggers */
+ tgu_writel(drvdata, 1, TGU_CONTROL);
+
+ drvdata->enable = true;
+ dev_dbg(dev, "Coresight-TGU enabled\n");
+
+ } else {
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+
+ pm_runtime_put(drvdata->dev);
+ dev_dbg(dev, "Coresight-TGU disabled\n");
+ }
+
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR(enable_tgu, 0200, NULL, enable_tgu);
+
+static ssize_t reset_tgu(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long value;
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int ret;
+
+ if (kstrtoul(buf, 16, &value))
+ return -EINVAL;
+
+ if (!drvdata->enable) {
+ /* Enable clock */
+ ret = pm_runtime_get_sync(drvdata->dev);
+ if (ret)
+ return ret;
+ }
+
+ spin_lock(&drvdata->spinlock);
+ /* Unlock the TGU LAR */
+ TGU_UNLOCK(drvdata);
+
+ if (value) {
+ /* Disable TGU to program the triggers */
+ tgu_writel(drvdata, 0, TGU_CONTROL);
+
+ /* Reset the Reference counters*/
+ drvdata->grp_refcnt = 0;
+ drvdata->cond_refcnt = 0;
+ drvdata->select_refcnt = 0;
+ drvdata->timer_refcnt = 0;
+ drvdata->counter_refcnt = 0;
+
+ dev_dbg(dev, "Coresight-TGU disabled\n");
+ } else
+ dev_dbg(dev, "Invalid input to reset the TGU\n");
+
+ TGU_LOCK(drvdata);
+ spin_unlock(&drvdata->spinlock);
+ pm_runtime_put(drvdata->dev);
+ return size;
+}
+static DEVICE_ATTR(reset_tgu, 0200, NULL, reset_tgu);
+
+static ssize_t set_group(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ int grp, reg, step;
+ unsigned long value;
+
+ if (drvdata->grp_refcnt >= MAX_GROUP_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %d %lx", &grp, ®, &step, &value) != 4)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if ((grp <= MAX_GROUPS) && (reg <= drvdata->max_regs)) {
+ drvdata->grp_data[drvdata->grp_refcnt].grpaddr =
+ GROUP_REG_STEP(grp, reg, step);
+ drvdata->grp_data[drvdata->grp_refcnt].value = value;
+ drvdata->grp_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid group data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_group, 0200, NULL, set_group);
+
+static ssize_t tgu_set_condition(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int cond, step;
+
+ if (drvdata->cond_refcnt >= MAX_CONDITION_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %lx", &cond, &step, &value) != 3)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if ((cond <= drvdata->max_conditions) && (step <=
+ drvdata->max_steps)) {
+ drvdata->condition_data[drvdata->cond_refcnt].condaddr =
+ CONDITION_DECODE_STEP(cond, step);
+ drvdata->condition_data[drvdata->cond_refcnt].value = value;
+ drvdata->cond_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid condition decode data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_condition, 0200, NULL, tgu_set_condition);
+
+static ssize_t tgu_set_select(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int select, step;
+
+ if (drvdata->select_refcnt >= MAX_CONDITION_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %d %lx", &select, &step, &value) != 3)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+
+ if ((select <= drvdata->max_conditions) && (step <=
+ drvdata->max_steps)) {
+ drvdata->select_data[drvdata->select_refcnt].selectaddr =
+ CONDITION_SELECT_STEP(select, step);
+ drvdata->select_data[drvdata->select_refcnt].value = value;
+ drvdata->select_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid select decode data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_select, 0200, NULL, tgu_set_select);
+
+static ssize_t tgu_set_timers(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int step;
+
+ if (drvdata->select_refcnt >= MAX_TIMER_COUNTER_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %lx", &step, &value) != 2)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (step <= drvdata->max_timer_counter) {
+ drvdata->timer_data[drvdata->timer_refcnt].timeraddr =
+ TIMER0_COMPARE_STEP(step);
+ drvdata->timer_data[drvdata->timer_refcnt].value = value;
+ drvdata->timer_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid TGU timer data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_timer, 0200, NULL, tgu_set_timers);
+
+static ssize_t tgu_set_counters(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t size)
+{
+ struct tgu_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long value;
+ int step;
+
+ if (drvdata->counter_refcnt >= MAX_TIMER_COUNTER_SETS) {
+ dev_err(drvdata->dev, " Too many groups are being configured");
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d %lx", &step, &value) != 2)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (step <= drvdata->max_timer_counter) {
+ drvdata->counter_data[drvdata->counter_refcnt].counteraddr =
+ COUNTER0_COMPARE_STEP(step);
+ drvdata->counter_data[drvdata->counter_refcnt].value = value;
+ drvdata->counter_refcnt++;
+ } else
+ dev_err(drvdata->dev, "Invalid TGU counter data\n");
+
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR(set_counter, 0200, NULL, tgu_set_counters);
+
+static struct attribute *tgu_attrs[] = {
+ &dev_attr_enable_tgu.attr,
+ &dev_attr_reset_tgu.attr,
+ &dev_attr_set_group.attr,
+ &dev_attr_set_condition.attr,
+ &dev_attr_set_select.attr,
+ &dev_attr_set_timer.attr,
+ &dev_attr_set_counter.attr,
+ NULL,
+};
+
+static struct attribute_group tgu_attr_grp = {
+ .attrs = tgu_attrs,
+};
+
+static const struct attribute_group *tgu_attr_grps[] = {
+ &tgu_attr_grp,
+ NULL,
+};
+
+static int tgu_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ int ret = 0;
+ struct device *dev = &adev->dev;
+ struct coresight_platform_data *pdata;
+ struct tgu_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &adev->dev;
+
+ dev_set_drvdata(dev, drvdata);
+
+ drvdata->base = devm_ioremap_resource(dev, &adev->res);
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ spin_lock_init(&drvdata->spinlock);
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-steps",
+ &drvdata->max_steps);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-conditions",
+ &drvdata->max_conditions);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-regs",
+ &drvdata->max_regs);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_property_read_u32(adev->dev.of_node, "tgu-timer-counters",
+ &drvdata->max_timer_counter);
+ if (ret)
+ return -EINVAL;
+
+ /* Alloc memory for Grps, Conditions and Steps */
+ drvdata->grp_data = devm_kzalloc(dev, MAX_GROUP_SETS *
+ sizeof(*drvdata->grp_data),
+ GFP_KERNEL);
+ if (!drvdata->grp_data)
+ return -ENOMEM;
+
+ drvdata->condition_data = devm_kzalloc(dev, MAX_CONDITION_SETS *
+ sizeof(*drvdata->condition_data),
+ GFP_KERNEL);
+
+ if (!drvdata->condition_data)
+ return -ENOMEM;
+
+ drvdata->select_data = devm_kzalloc(dev, MAX_CONDITION_SETS *
+ sizeof(*drvdata->select_data),
+ GFP_KERNEL);
+ if (!drvdata->select_data)
+ return -ENOMEM;
+
+ drvdata->timer_data = devm_kzalloc(dev, MAX_TIMER_COUNTER_SETS *
+ sizeof(*drvdata->timer_data),
+ GFP_KERNEL);
+ if (!drvdata->timer_data)
+ return -ENOMEM;
+
+ drvdata->counter_data = devm_kzalloc(dev, MAX_TIMER_COUNTER_SETS *
+ sizeof(*drvdata->counter_data),
+ GFP_KERNEL);
+ if (!drvdata->counter_data)
+ return -ENOMEM;
+
+ drvdata->enable = false;
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = adev->dev.platform_data;
+ desc->dev = &adev->dev;
+ desc->groups = tgu_attr_grps;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev)) {
+ ret = PTR_ERR(drvdata->csdev);
+ goto err;
+ }
+
+ pm_runtime_put(&adev->dev);
+ dev_dbg(dev, "TGU initialized\n");
+ return 0;
+err:
+ pm_runtime_put(&adev->dev);
+ return ret;
+}
+
+static struct amba_id tgu_ids[] = {
+ {
+ .id = 0x0003b999,
+ .mask = 0x0003ffff,
+ .data = "TGU",
+ },
+ { 0, 0},
+};
+
+static struct amba_driver tgu_driver = {
+ .drv = {
+ .name = "coresight-tgu",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
+ },
+ .probe = tgu_probe,
+ .id_table = tgu_ids,
+};
+
+builtin_amba_driver(tgu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight TGU driver");
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0b42a12..b42d95f 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -319,7 +319,7 @@
#endif
#ifdef CONFIG_PM
-static int dw_i2c_plat_suspend(struct device *dev)
+static int dw_i2c_plat_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -343,11 +343,21 @@
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int dw_i2c_plat_suspend(struct device *dev)
+{
+ pm_runtime_resume(dev);
+ return dw_i2c_plat_runtime_suspend(dev);
+}
+#endif
+
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = dw_i2c_plat_prepare,
.complete = dw_i2c_plat_complete,
SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
- SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
+ SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
+ dw_i2c_plat_resume,
+ NULL)
};
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index f573448..8477292 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -341,8 +341,10 @@
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_I2C_BLOCK_DATA:
- memcpy(&data->block[1], dma_buffer, desc->rxbytes);
- data->block[0] = desc->rxbytes;
+ if (desc->rxbytes != dma_buffer[0] + 1)
+ return -EMSGSIZE;
+
+ memcpy(data->block, dma_buffer, desc->rxbytes);
break;
}
return 0;
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index 3de0e25..4daed7f 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -2164,7 +2164,6 @@
++cur_buf->msg_idx;
++cur_msg;
- }
} else {
cur_buf->is_init = true;
}
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 59b380d..c388882 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -193,7 +193,6 @@
struct regmap *regmap;
int irq;
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
- atomic_t active_intr;
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
struct mutex mutex;
u8 fifo_mode, watermark;
@@ -493,11 +492,6 @@
goto out_fix_power_state;
}
- if (state)
- atomic_inc(&data->active_intr);
- else
- atomic_dec(&data->active_intr);
-
return 0;
out_fix_power_state:
@@ -1709,8 +1703,7 @@
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
- if (atomic_read(&data->active_intr))
- bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
+ bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
bmc150_accel_fifo_set_mode(data);
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index b055ff6..357bfb2 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -180,6 +180,9 @@
#define FG_ADC_RR_VOLT_INPUT_FACTOR 8
#define FG_ADC_RR_CURR_INPUT_FACTOR 2000
#define FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL 1886
+#define FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL 9
+#define FG_ADC_RR_CURR_USBIN_660_UV_VAL 579500
+
#define FG_ADC_SCALE_MILLI_FACTOR 1000
#define FG_ADC_KELVINMIL_CELSIUSMIL 273150
@@ -192,6 +195,9 @@
#define FG_RR_CONV_CONTINUOUS_TIME_MIN_US 50000
#define FG_RR_CONV_CONTINUOUS_TIME_MAX_US 51000
#define FG_RR_CONV_MAX_RETRY_CNT 50
+#define FG_RR_TP_REV_VERSION1 21
+#define FG_RR_TP_REV_VERSION2 29
+#define FG_RR_TP_REV_VERSION3 32
/*
* The channel number is not a physical index in hardware,
@@ -228,6 +234,7 @@
struct rradc_chan_prop *chan_props;
struct device_node *revid_dev_node;
struct pmic_revid_data *pmic_fab_id;
+ int volt;
};
struct rradc_channels {
@@ -353,7 +360,7 @@
return 0;
}
-static int rradc_post_process_curr(struct rradc_chip *chip,
+static int rradc_post_process_usbin_curr(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_ua)
{
@@ -361,11 +368,33 @@
if (!prop)
return -EINVAL;
-
- if (prop->channel == RR_ADC_USBIN_I)
- scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
- else
- scale = FG_ADC_RR_CURR_INPUT_FACTOR;
+ if (chip->revid_dev_node) {
+ switch (chip->pmic_fab_id->pmic_subtype) {
+ case PM660_SUBTYPE:
+ if (((chip->pmic_fab_id->tp_rev
+ >= FG_RR_TP_REV_VERSION1)
+ && (chip->pmic_fab_id->tp_rev
+ <= FG_RR_TP_REV_VERSION2))
+ || (chip->pmic_fab_id->tp_rev
+ >= FG_RR_TP_REV_VERSION3)) {
+ chip->volt = div64_s64(chip->volt, 1000);
+ chip->volt = chip->volt *
+ FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL;
+ chip->volt = FG_ADC_RR_CURR_USBIN_660_UV_VAL -
+ (chip->volt);
+ chip->volt = div64_s64(1000000000, chip->volt);
+ scale = chip->volt;
+ } else
+ scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
+ break;
+ case PMI8998_SUBTYPE:
+ scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
+ break;
+ default:
+ pr_err("No PMIC subtype found\n");
+ return -EINVAL;
+ }
+ }
/* scale * V/A; 2.5V ADC full scale */
ua = ((int64_t)adc_code * scale);
@@ -376,6 +405,24 @@
return 0;
}
+static int rradc_post_process_dcin_curr(struct rradc_chip *chip,
+ struct rradc_chan_prop *prop, u16 adc_code,
+ int *result_ua)
+{
+ int64_t ua = 0;
+
+ if (!prop)
+ return -EINVAL;
+
+ /* 0.5 V/A; 2.5V ADC full scale */
+ ua = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR);
+ ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
+ ua = div64_s64(ua, (FG_MAX_ADC_READINGS * 1000));
+ *result_ua = ua;
+
+ return 0;
+}
+
static int rradc_post_process_die_temp(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_millidegc)
@@ -591,13 +638,13 @@
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB,
FG_ADC_RR_AUX_THERM_STS)
- RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_curr,
+ RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_usbin_curr,
FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB,
FG_ADC_RR_USB_IN_I_STS)
RR_ADC_CHAN_VOLT("usbin_v", &rradc_post_process_volt,
FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB,
FG_ADC_RR_USB_IN_V_STS)
- RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_curr,
+ RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_dcin_curr,
FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB,
FG_ADC_RR_DC_IN_I_STS)
RR_ADC_CHAN_VOLT("dcin_v", &rradc_post_process_volt,
@@ -955,6 +1002,21 @@
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
+ if (((chip->pmic_fab_id->tp_rev
+ >= FG_RR_TP_REV_VERSION1)
+ && (chip->pmic_fab_id->tp_rev
+ <= FG_RR_TP_REV_VERSION2))
+ || (chip->pmic_fab_id->tp_rev
+ >= FG_RR_TP_REV_VERSION3)) {
+ if (chan->address == RR_ADC_USBIN_I) {
+ prop = &chip->chan_props[RR_ADC_USBIN_V];
+ rc = rradc_do_conversion(chip, prop, &adc_code);
+ if (rc)
+ break;
+ prop->scale(chip, prop, adc_code, &chip->volt);
+ }
+ }
+
prop = &chip->chan_props[chan->address];
rc = rradc_do_conversion(chip, prop, &adc_code);
if (rc)
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 228a003..d1bde6d 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -77,7 +77,7 @@
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
-#define VF610_ADC_REFSEL_VALT 0x100
+#define VF610_ADC_REFSEL_VALT 0x800
#define VF610_ADC_REFSEL_VBG 0x1000
#define VF610_ADC_ADTRG_HARD 0x2000
#define VF610_ADC_AVGS_8 0x4000
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 6082934..b60e5d8 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -36,8 +36,6 @@
s32 poll_value = 0;
if (state) {
- if (!atomic_read(&st->user_requested_state))
- return 0;
if (sensor_hub_device_open(st->hsdev))
return -EIO;
@@ -86,6 +84,9 @@
&report_val);
}
+ pr_debug("HID_SENSOR %s set power_state %d report_state %d\n",
+ st->pdev->name, state_val, report_val);
+
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
sizeof(state_val), &state_val);
@@ -107,6 +108,7 @@
ret = pm_runtime_get_sync(&st->pdev->dev);
else {
pm_runtime_mark_last_busy(&st->pdev->dev);
+ pm_runtime_use_autosuspend(&st->pdev->dev);
ret = pm_runtime_put_autosuspend(&st->pdev->dev);
}
if (ret < 0) {
@@ -201,8 +203,6 @@
/* Default to 3 seconds, but can be changed from sysfs */
pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
3000);
- pm_runtime_use_autosuspend(&attrb->pdev->dev);
-
return ret;
error_unreg_trigger:
iio_trigger_unregister(trig);
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 8cf84d3..1289842 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -696,7 +696,7 @@
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(12500),
- .accel_max_scale = 5,
+ .accel_max_scale = 10,
},
[ADIS16485] = {
.channels = adis16485_channels,
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 04598ae..f0d3f74 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -626,7 +626,7 @@
struct tsl2563_chip *chip = iio_priv(dev_info);
iio_push_event(dev_info,
- IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_EITHER),
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index f1510cc..9398143 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -1804,20 +1804,21 @@
skb_trim(skb, dlen);
mutex_lock(&ep->com.mutex);
- /* update RX credits */
- update_rx_credits(ep, dlen);
-
switch (ep->com.state) {
case MPA_REQ_SENT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_reply(ep, skb);
break;
case MPA_REQ_WAIT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_request(ep, skb);
break;
case FPDU_MODE: {
struct c4iw_qp_attributes attrs;
+
+ update_rx_credits(ep, dlen);
BUG_ON(!ep->com.qp);
if (status)
pr_err("%s Unexpected streaming data." \
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 7a6f50b..66d1499 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -92,6 +92,7 @@
struct kobject *sysfs_kobject;
s16 ROI[MAX_ROI_SIZE];
s16 accelBuffer[MAX_ACCEL_SIZE];
+ u32 display_status;
};
static struct hbtp_data *hbtp;
@@ -1425,10 +1426,11 @@
if (ret) {
pr_err("hbtp: ret error: %zd\n", ret);
mutex_unlock(&hbtp->mutex);
- return ret;
+ return 0;
}
- if (!hbtp || !hbtp->input_dev) {
- pr_err("hbtp: hbtp or hbtp->input_dev not ready!\n");
+ hbtp->display_status = status;
+ if (!hbtp->input_dev) {
+ pr_err("hbtp: hbtp->input_dev not ready!\n");
mutex_unlock(&hbtp->mutex);
return ret;
}
@@ -1445,8 +1447,20 @@
return count;
}
+static ssize_t hbtp_display_pwr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ mutex_lock(&hbtp->mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%u\n", hbtp->display_status);
+ mutex_unlock(&hbtp->mutex);
+ return ret;
+}
+
static struct kobj_attribute hbtp_display_attribute =
- __ATTR(display_pwr, 0660, NULL, hbtp_display_pwr_store);
+ __ATTR(display_pwr, 0660, hbtp_display_pwr_show,
+ hbtp_display_pwr_store);
static int __init hbtp_init(void)
{
@@ -1463,6 +1477,7 @@
mutex_init(&hbtp->mutex);
mutex_init(&hbtp->sensormutex);
+ hbtp->display_status = 1;
error = misc_register(&hbtp_input_misc);
if (error) {
@@ -1545,6 +1560,8 @@
sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
kobject_put(sensor_kobject);
+ sysfs_remove_file(hbtp->sysfs_kobject, &hbtp_display_attribute.attr);
+ kobject_put(hbtp->sysfs_kobject);
misc_deregister(&hbtp_input_misc);
if (hbtp->input_dev)
input_unregister_device(hbtp->input_dev);
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c
index c5ab3dd..fdcc146 100644
--- a/drivers/input/misc/keychord.c
+++ b/drivers/input/misc/keychord.c
@@ -60,6 +60,10 @@
unsigned char head;
unsigned char tail;
__u16 buff[BUFFER_SIZE];
+ /* Bit to serialize writes to this device */
+#define KEYCHORD_BUSY 0x01
+ unsigned long flags;
+ wait_queue_head_t write_waitq;
};
static int check_keychord(struct keychord_device *kdev,
@@ -172,7 +176,6 @@
goto err_input_open_device;
pr_info("keychord: using input dev %s for fevent\n", dev->name);
-
return 0;
err_input_open_device:
@@ -225,6 +228,41 @@
}
/*
+ * serializes writes on a device. can use mutex_lock_interruptible()
+ * for this particular use case as well - a matter of preference.
+ */
+static int
+keychord_write_lock(struct keychord_device *kdev)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kdev->lock, flags);
+ while (kdev->flags & KEYCHORD_BUSY) {
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ ret = wait_event_interruptible(kdev->write_waitq,
+ ((kdev->flags & KEYCHORD_BUSY) == 0));
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&kdev->lock, flags);
+ }
+ kdev->flags |= KEYCHORD_BUSY;
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ return 0;
+}
+
+static void
+keychord_write_unlock(struct keychord_device *kdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kdev->lock, flags);
+ kdev->flags &= ~KEYCHORD_BUSY;
+ spin_unlock_irqrestore(&kdev->lock, flags);
+ wake_up_interruptible(&kdev->write_waitq);
+}
+
+/*
* keychord_write is used to configure the driver
*/
static ssize_t keychord_write(struct file *file, const char __user *buffer,
@@ -250,6 +288,22 @@
return -EFAULT;
}
+ /*
+ * Serialize writes to this device to prevent various races.
+ * 1) writers racing here could do duplicate input_unregister_handler()
+ * calls, resulting in attempting to unlink a node from a list that
+ * does not exist.
+ * 2) writers racing here could do duplicate input_register_handler() calls
+ * below, resulting in a duplicate insertion of a node into the list.
+ * 3) a double kfree of keychords can occur (in the event that
+ * input_register_handler() fails below.
+ */
+ ret = keychord_write_lock(kdev);
+ if (ret) {
+ kfree(keychords);
+ return ret;
+ }
+
/* unregister handler before changing configuration */
if (kdev->registered) {
input_unregister_handler(&kdev->input_handler);
@@ -318,15 +372,19 @@
if (ret) {
kfree(keychords);
kdev->keychords = 0;
+ keychord_write_unlock(kdev);
return ret;
}
kdev->registered = 1;
+ keychord_write_unlock(kdev);
+
return count;
err_unlock_return:
spin_unlock_irqrestore(&kdev->lock, flags);
kfree(keychords);
+ keychord_write_unlock(kdev);
return -EINVAL;
}
@@ -352,6 +410,7 @@
spin_lock_init(&kdev->lock);
init_waitqueue_head(&kdev->waitq);
+ init_waitqueue_head(&kdev->write_waitq);
kdev->input_handler.event = keychord_event;
kdev->input_handler.connect = keychord_connect;
@@ -373,6 +432,7 @@
if (kdev->registered)
input_unregister_handler(&kdev->input_handler);
+ kfree(kdev->keychords);
kfree(kdev);
return 0;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 518e8a7..f26807c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1212,14 +1212,24 @@
case SS4_PACKET_ID_TWO:
if (priv->flags & ALPS_BUTTONPAD) {
- f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
+ }
f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0);
- f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1);
} else {
- f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+ }
f->mt[0].y = SS4_STD_MF_Y_V2(p, 0);
- f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
f->mt[1].y = SS4_STD_MF_Y_V2(p, 1);
}
f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
@@ -1236,16 +1246,27 @@
case SS4_PACKET_ID_MULTI:
if (priv->flags & ALPS_BUTTONPAD) {
- f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+ } else {
+ f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
+ f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
+ }
+
f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
- f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
no_data_x = SS4_MFPACKET_NO_AX_BL;
no_data_y = SS4_MFPACKET_NO_AY_BL;
} else {
- f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
+ f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+ } else {
+ f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
+ f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+ }
f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
- f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
no_data_x = SS4_MFPACKET_NO_AX;
no_data_y = SS4_MFPACKET_NO_AY;
@@ -2535,8 +2556,8 @@
memset(otp, 0, sizeof(otp));
- if (alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]) ||
- alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]))
+ if (alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]) ||
+ alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]))
return -1;
alps_update_device_area_ss4_v2(otp, priv);
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index dbfd260..7931237 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -91,6 +91,10 @@
((_b[1 + _i * 3] << 5) & 0x1F00) \
)
+#define SS4_PLUS_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 4) & 0x0070) | \
+ ((_b[1 + (_i) * 3] << 4) & 0x0F80) \
+ )
+
#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \
((_b[2 + (_i) * 3] << 5) & 0x01E0) | \
((_b[2 + (_i) * 3] << 4) & 0x0E00) \
@@ -100,6 +104,10 @@
((_b[0 + (_i) * 3] >> 3) & 0x0010) \
)
+#define SS4_PLUS_BTL_MF_X_V2(_b, _i) (SS4_PLUS_STD_MF_X_V2(_b, _i) | \
+ ((_b[0 + (_i) * 3] >> 4) & 0x0008) \
+ )
+
#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
((_b[0 + (_i) * 3] >> 3) & 0x0008) \
)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index da5458d..681dce1 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1234,7 +1234,12 @@
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
{ "ELAN0600", 0 },
+ { "ELAN0602", 0 },
{ "ELAN0605", 0 },
+ { "ELAN0608", 0 },
+ { "ELAN0605", 0 },
+ { "ELAN0609", 0 },
+ { "ELAN060B", 0 },
{ "ELAN1000", 0 },
{ }
};
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 354d47e..ce6ff9b 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -265,7 +265,8 @@
if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
return -1;
- if (param[0] != TP_MAGIC_IDENT)
+ /* add new TP ID. */
+ if (!(param[0] & TP_MAGIC_IDENT))
return -1;
if (firmware_id)
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 5617ed3..8805575 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -21,8 +21,9 @@
#define TP_COMMAND 0xE2 /* Commands start with this */
#define TP_READ_ID 0xE1 /* Sent for device identification */
-#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */
+#define TP_MAGIC_IDENT 0x03 /* Sent after a TP_READ_ID followed */
/* by the firmware ID */
+ /* Firmware ID includes 0x1, 0x2, 0x3 */
/*
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 41800b6..c380b7e 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4294,6 +4294,7 @@
/* Setting */
irte->hi.fields.ga_root_ptr = (pi_data->base >> 12);
irte->hi.fields.vector = vcpu_pi_info->vector;
+ irte->lo.fields_vapic.ga_log_intr = 1;
irte->lo.fields_vapic.guest_mode = 1;
irte->lo.fields_vapic.ga_tag = pi_data->ga_tag;
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a2c5579..d49fd55 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -427,6 +427,7 @@
#define ARM_SMMU_OPT_DYNAMIC (1 << 3)
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
+#define ARM_SMMU_OPT_DISABLE_ATOS (1 << 6)
u32 options;
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
@@ -547,6 +548,7 @@
{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
+ { ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" },
{ 0, NULL},
};
@@ -2490,6 +2492,10 @@
phys_addr_t ret = 0;
unsigned long flags;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+ if (smmu->options & ARM_SMMU_OPT_DISABLE_ATOS)
+ return 0;
if (smmu_domain->smmu->arch_ops &&
smmu_domain->smmu->arch_ops->iova_to_phys_hard) {
@@ -2760,6 +2766,11 @@
& (1 << DOMAIN_ATTR_FAST));
ret = 0;
break;
+ case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
+ *((int *)data) = !!(smmu_domain->attributes
+ & (1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR));
+ ret = 0;
+ break;
case DOMAIN_ATTR_USE_UPSTREAM_HINT:
*((int *)data) = !!(smmu_domain->attributes &
(1 << DOMAIN_ATTR_USE_UPSTREAM_HINT));
@@ -2912,6 +2923,12 @@
}
smmu_domain->secure_vmid = *((int *)data);
break;
+ case DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR:
+ if (*((int *)data))
+ smmu_domain->attributes |=
+ 1 << DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR;
+ ret = 0;
+ break;
case DOMAIN_ATTR_FAST:
if (*((int *)data))
smmu_domain->attributes |= 1 << DOMAIN_ATTR_FAST;
@@ -3265,11 +3282,6 @@
u32 sctlr, sctlr_orig, fsr;
void __iomem *cb_base;
- if (smmu->model == QCOM_SMMUV2) {
- dev_err(smmu->dev, "ATOS support is disabled\n");
- return 0;
- }
-
ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
if (ret)
return ret;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index d92a352..da4d283 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -202,39 +202,58 @@
}
}
-static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size,
- dma_addr_t dma_limit)
+static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
+ size_t size, dma_addr_t dma_limit, struct device *dev)
{
struct iova_domain *iovad = cookie_iovad(domain);
unsigned long shift = iova_shift(iovad);
- unsigned long length = iova_align(iovad, size) >> shift;
+ unsigned long iova_len = size >> shift;
+ unsigned long iova = 0;
+ dma_addr_t limit;
+
+ /*
+ * Freeing non-power-of-two-sized allocations back into the IOVA caches
+ * will come back to bite us badly, so we have to waste a bit of space
+ * rounding up anything cacheable to make sure that can't happen. The
+ * order of the unadjusted size will still match upon freeing.
+ */
+ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+ iova_len = roundup_pow_of_two(iova_len);
if (domain->geometry.force_aperture)
dma_limit = min(dma_limit, domain->geometry.aperture_end);
+
/*
- * Enforce size-alignment to be safe - there could perhaps be an
- * attribute to control this per-device, or at least per-domain...
+ * Ensure iova is within range specified in iommu_dma_init_domain().
+ * This also prevents unnecessary work iterating through the entire
+ * rb_tree.
*/
- return alloc_iova(iovad, length, dma_limit >> shift, true);
+ limit = min_t(dma_addr_t, dma_limit >> shift, iovad->dma_32bit_pfn);
+ iova = alloc_iova_fast(iovad, iova_len, limit);
+
+ return (dma_addr_t)iova << shift;
}
-/* The IOVA allocator knows what we mapped, so just unmap whatever that was */
-static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr)
+static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
+ dma_addr_t iova, size_t size)
+{
+ struct iova_domain *iovad = &cookie->iovad;
+ unsigned long shift = iova_shift(iovad);
+
+ free_iova_fast(iovad, iova >> shift, size >> shift);
+}
+
+static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
+ size_t size)
{
struct iova_domain *iovad = cookie_iovad(domain);
- unsigned long shift = iova_shift(iovad);
- unsigned long pfn = dma_addr >> shift;
- struct iova *iova = find_iova(iovad, pfn);
- size_t size;
+ size_t iova_off = iova_offset(iovad, dma_addr);
- if (WARN_ON(!iova))
- return;
+ dma_addr -= iova_off;
+ size = iova_align(iovad, size + iova_off);
- size = iova_size(iova) << shift;
- size -= iommu_unmap(domain, pfn << shift, size);
- /* ...and if we can't, then something is horribly, horribly wrong */
- WARN_ON(size > 0);
- __free_iova(iovad, iova);
+ WARN_ON(iommu_unmap(domain, dma_addr, size) != size);
+ iommu_dma_free_iova(domain->iova_cookie, dma_addr, size);
}
static void __iommu_dma_free_pages(struct page **pages, int count)
@@ -316,7 +335,7 @@
void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
dma_addr_t *handle)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size);
__iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
*handle = DMA_ERROR_CODE;
}
@@ -344,11 +363,11 @@
void (*flush_page)(struct device *, const void *, phys_addr_t))
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
- struct iova *iova;
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
struct page **pages;
struct sg_table sgt;
- dma_addr_t dma_addr;
+ dma_addr_t iova;
unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
*handle = DMA_ERROR_CODE;
@@ -368,11 +387,11 @@
if (!pages)
return NULL;
- iova = __alloc_iova(domain, size, dev->coherent_dma_mask);
+ size = iova_align(iovad, size);
+ iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev);
if (!iova)
goto out_free_pages;
- size = iova_align(iovad, size);
if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL))
goto out_free_iova;
@@ -388,19 +407,18 @@
sg_miter_stop(&miter);
}
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map_sg(domain, dma_addr, sgt.sgl, sgt.orig_nents, prot)
+ if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot)
< size)
goto out_free_sg;
- *handle = dma_addr;
+ *handle = iova;
sg_free_table(&sgt);
return pages;
out_free_sg:
sg_free_table(&sgt);
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, size);
out_free_pages:
__iommu_dma_free_pages(pages, count);
return NULL;
@@ -434,22 +452,22 @@
static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
size_t size, int prot)
{
- dma_addr_t dma_addr;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
size_t iova_off = iova_offset(iovad, phys);
- size_t len = iova_align(iovad, size + iova_off);
- struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev));
+ dma_addr_t iova;
+ size = iova_align(iovad, size + iova_off);
+ iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
if (!iova)
return DMA_ERROR_CODE;
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) {
- __free_iova(iovad, iova);
+ if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+ iommu_dma_free_iova(cookie, iova, size);
return DMA_ERROR_CODE;
}
- return dma_addr + iova_off;
+ return iova + iova_off;
}
dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
@@ -461,7 +479,7 @@
void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
}
/*
@@ -550,10 +568,10 @@
int nents, int prot)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct iova_domain *iovad = cookie_iovad(domain);
- struct iova *iova;
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
struct scatterlist *s, *prev = NULL;
- dma_addr_t dma_addr;
+ dma_addr_t iova;
size_t iova_len = 0;
unsigned long mask = dma_get_seg_boundary(dev);
int i;
@@ -597,7 +615,7 @@
prev = s;
}
- iova = __alloc_iova(domain, iova_len, dma_get_mask(dev));
+ iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev);
if (!iova)
goto out_restore_sg;
@@ -605,14 +623,13 @@
* We'll leave any physical concatenation to the IOMMU driver's
* implementation - it knows better than we do.
*/
- dma_addr = iova_dma_addr(iovad, iova);
- if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len)
+ if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len)
goto out_free_iova;
- return __finalise_sg(dev, sg, nents, dma_addr);
+ return __finalise_sg(dev, sg, nents, iova);
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, iova_len);
out_restore_sg:
__invalidate_sg(sg, nents);
return 0;
@@ -621,11 +638,21 @@
void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, unsigned long attrs)
{
+ dma_addr_t start, end;
+ struct scatterlist *tmp;
+ int i;
/*
* The scatterlist segments are mapped into a single
* contiguous IOVA allocation, so this is incredibly easy.
*/
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg));
+ start = sg_dma_address(sg);
+ for_each_sg(sg_next(sg), tmp, nents - 1, i) {
+ if (sg_dma_len(tmp) == 0)
+ break;
+ sg = tmp;
+ }
+ end = sg_dma_address(sg) + sg_dma_len(sg);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start);
}
dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
@@ -638,7 +665,7 @@
void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+ __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
}
int iommu_dma_supported(struct device *dev, u64 mask)
@@ -662,7 +689,7 @@
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iommu_dma_msi_page *msi_page;
struct iova_domain *iovad = &cookie->iovad;
- struct iova *iova;
+ dma_addr_t iova;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
msi_addr &= ~(phys_addr_t)iova_mask(iovad);
@@ -674,12 +701,13 @@
if (!msi_page)
return NULL;
- iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev));
+ iova = iommu_dma_alloc_iova(domain, iovad->granule, dma_get_mask(dev),
+ dev);
if (!iova)
goto out_free_page;
msi_page->phys = msi_addr;
- msi_page->iova = iova_dma_addr(iovad, iova);
+ msi_page->iova = iova;
if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot))
goto out_free_iova;
@@ -688,7 +716,7 @@
return msi_page;
out_free_iova:
- __free_iova(iovad, iova);
+ iommu_dma_free_iova(cookie, iova, iovad->granule);
out_free_page:
kfree(msi_page);
return NULL;
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index b5e817b..04a5c09 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -855,29 +855,28 @@
spin_unlock_irqrestore(&mapping->lock, flags);
}
-
/**
- * fast_smmu_attach_device
+ * fast_smmu_init_mapping
* @dev: valid struct device pointer
* @mapping: io address space mapping structure (returned from
- * fast_smmu_create_mapping)
+ * arm_iommu_create_mapping)
*
- * Attaches specified io address space mapping to the provided device,
- * this replaces the dma operations (dma_map_ops pointer) with the
- * IOMMU aware version. More than one client might be attached to
- * the same io address space mapping.
+ * Called the first time a device is attached to this mapping.
+ * Not for dma client use.
*/
-int fast_smmu_attach_device(struct device *dev,
+int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
- int atomic_domain = 1;
+ int err, atomic_domain = 1;
struct iommu_domain *domain = mapping->domain;
struct iommu_group *group;
struct iommu_pgtbl_info info;
u64 size = (u64)mapping->bits << PAGE_SHIFT;
- if (mapping->base + size > (SZ_1G * 4ULL))
+ if (mapping->base + size > (SZ_1G * 4ULL)) {
+ dev_err(dev, "Iova end address too large\n");
return -EINVAL;
+ }
if (iommu_domain_set_attr(domain, DOMAIN_ATTR_ATOMIC,
&atomic_domain))
@@ -894,54 +893,67 @@
group = dev->iommu_group;
if (!group) {
dev_err(dev, "No iommu associated with device\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto release_mapping;
}
if (iommu_get_domain_for_dev(dev)) {
dev_err(dev, "Device already attached to other iommu_domain\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto release_mapping;
}
- if (iommu_attach_group(mapping->domain, group))
- return -EINVAL;
+ /*
+ * Need to attach prior to calling DOMAIN_ATTR_PGTBL_INFO and then
+ * detach to be in the expected state. Its a bit messy.
+ */
+ if (iommu_attach_group(mapping->domain, group)) {
+ err = -EINVAL;
+ goto release_mapping;
+ }
if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PGTBL_INFO,
&info)) {
dev_err(dev, "Couldn't get page table info\n");
- fast_smmu_detach_device(dev, mapping);
- return -EINVAL;
+ err = -EINVAL;
+ goto detach_group;
}
mapping->fast->pgtbl_pmds = info.pmds;
if (iommu_domain_get_attr(domain, DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
- &mapping->fast->is_smmu_pt_coherent))
- return -EINVAL;
+ &mapping->fast->is_smmu_pt_coherent)) {
+ err = -EINVAL;
+ goto detach_group;
+ }
mapping->fast->notifier.notifier_call = fast_smmu_notify;
av8l_register_notify(&mapping->fast->notifier);
- dev->archdata.mapping = mapping;
- set_dma_ops(dev, &fast_smmu_dma_ops);
-
+ iommu_detach_group(mapping->domain, group);
+ mapping->ops = &fast_smmu_dma_ops;
return 0;
+
+detach_group:
+ iommu_detach_group(mapping->domain, group);
+release_mapping:
+ kfree(mapping->fast->bitmap);
+ kfree(mapping->fast);
+ return err;
}
-EXPORT_SYMBOL(fast_smmu_attach_device);
/**
- * fast_smmu_detach_device
- * @dev: valid struct device pointer
+ * fast_smmu_release_mapping
+ * @kref: dma_iommu_mapping->kref
*
- * Detaches the provided device from a previously attached map.
- * This voids the dma operations (dma_map_ops pointer)
+ * Cleans up the given iommu mapping.
*/
-void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
+void fast_smmu_release_mapping(struct kref *kref)
{
- iommu_detach_group(mapping->domain, dev->iommu_group);
- dev->archdata.mapping = NULL;
- set_dma_ops(dev, NULL);
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
kvfree(mapping->fast->bitmap);
kfree(mapping->fast);
+ iommu_domain_free(mapping->domain);
+ kfree(mapping);
}
-EXPORT_SYMBOL(fast_smmu_detach_device);
diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c
index 28b26c8..0565070 100644
--- a/drivers/irqchip/irq-atmel-aic-common.c
+++ b/drivers/irqchip/irq-atmel-aic-common.c
@@ -142,9 +142,9 @@
struct device_node *np;
void __iomem *regs;
- np = of_find_compatible_node(root, NULL, "atmel,at91rm9200-rtc");
+ np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-rtc");
if (!np)
- np = of_find_compatible_node(root, NULL,
+ np = of_find_compatible_node(NULL, NULL,
"atmel,at91sam9x5-rtc");
if (!np)
@@ -196,7 +196,6 @@
return;
match = of_match_node(matches, root);
- of_node_put(root);
if (match) {
void (*fixup)(struct device_node *) = match->data;
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index c0178a1..d74374f 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -1115,8 +1115,11 @@
gic_len = resource_size(&res);
}
- if (mips_cm_present())
+ if (mips_cm_present()) {
write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
+ /* Ensure GIC region is enabled before trying to access it */
+ __sync();
+ }
gic_present = true;
__gic_init(gic_base, gic_len, cpu_vec, 0, node);
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index c9f3862..410c39c 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/leds.h>
#include <linux/reboot.h>
-#include <linux/suspend.h>
#include "../leds.h"
static int panic_heartbeats;
@@ -155,30 +154,6 @@
.deactivate = heartbeat_trig_deactivate,
};
-static int heartbeat_pm_notifier(struct notifier_block *nb,
- unsigned long pm_event, void *unused)
-{
- int rc;
-
- switch (pm_event) {
- case PM_SUSPEND_PREPARE:
- case PM_HIBERNATION_PREPARE:
- case PM_RESTORE_PREPARE:
- led_trigger_unregister(&heartbeat_led_trigger);
- break;
- case PM_POST_SUSPEND:
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
- rc = led_trigger_register(&heartbeat_led_trigger);
- if (rc)
- pr_err("could not re-register heartbeat trigger\n");
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
static int heartbeat_reboot_notifier(struct notifier_block *nb,
unsigned long code, void *unused)
{
@@ -193,10 +168,6 @@
return NOTIFY_DONE;
}
-static struct notifier_block heartbeat_pm_nb = {
- .notifier_call = heartbeat_pm_notifier,
-};
-
static struct notifier_block heartbeat_reboot_nb = {
.notifier_call = heartbeat_reboot_notifier,
};
@@ -213,14 +184,12 @@
atomic_notifier_chain_register(&panic_notifier_list,
&heartbeat_panic_nb);
register_reboot_notifier(&heartbeat_reboot_nb);
- register_pm_notifier(&heartbeat_pm_nb);
}
return rc;
}
static void __exit heartbeat_trig_exit(void)
{
- unregister_pm_notifier(&heartbeat_pm_nb);
unregister_reboot_notifier(&heartbeat_reboot_nb);
atomic_notifier_chain_unregister(&panic_notifier_list,
&heartbeat_panic_nb);
diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c
index a18fe5d..b4857cd 100644
--- a/drivers/media/pci/saa7164/saa7164-bus.c
+++ b/drivers/media/pci/saa7164/saa7164-bus.c
@@ -393,11 +393,11 @@
msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
+ memcpy(msg, &msg_tmp, sizeof(*msg));
/* No need to update the read positions, because this was a peek */
/* If the caller specifically want to peek, return */
if (peekonly) {
- memcpy(msg, &msg_tmp, sizeof(*msg));
goto peekout;
}
@@ -442,21 +442,15 @@
space_rem = bus->m_dwSizeGetRing - curr_grp;
if (space_rem < sizeof(*msg)) {
- /* msg wraps around the ring */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem);
- memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing,
- sizeof(*msg) - space_rem);
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
space_rem, buf_size);
} else if (space_rem == sizeof(*msg)) {
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
} else {
/* Additional data wraps around the ring */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf) {
memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
sizeof(*msg), space_rem - sizeof(*msg));
@@ -469,15 +463,10 @@
} else {
/* No wrapping */
- memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
buf_size);
}
- /* Convert from little endian to CPU */
- msg->size = le16_to_cpu((__force __le16)msg->size);
- msg->command = le32_to_cpu((__force __le32)msg->command);
- msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
/* Update the read positions, adjusting the ring */
saa7164_writel(bus->m_dwGetReadPos, new_grp);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 6efb2f1..bdb7a0a 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1725,27 +1725,9 @@
switch (cmd) {
case VPFE_CMD_S_CCDC_RAW_PARAMS:
+ ret = -EINVAL;
v4l2_warn(&vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
- if (ccdc_dev->hw_ops.set_params) {
- ret = ccdc_dev->hw_ops.set_params(param);
- if (ret) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Error setting parameters in CCDC\n");
- goto unlock_out;
- }
- ret = vpfe_get_ccdc_image_format(vpfe_dev,
- &vpfe_dev->fmt);
- if (ret < 0) {
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "Invalid image format at CCDC\n");
- goto unlock_out;
- }
- } else {
- ret = -EINVAL;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
- "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
- }
+ "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
break;
default:
ret = -ENOTTY;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 03c5eb3..b015452 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -71,6 +71,16 @@
PACKER_FMT_MAX = 0xF,
};
+enum cam_vfe_bus_comp_grp_id {
+ CAM_VFE_BUS_COMP_GROUP_NONE = -EINVAL,
+ CAM_VFE_BUS_COMP_GROUP_ID_0 = 0x0,
+ CAM_VFE_BUS_COMP_GROUP_ID_1 = 0x1,
+ CAM_VFE_BUS_COMP_GROUP_ID_2 = 0x2,
+ CAM_VFE_BUS_COMP_GROUP_ID_3 = 0x3,
+ CAM_VFE_BUS_COMP_GROUP_ID_4 = 0x4,
+ CAM_VFE_BUS_COMP_GROUP_ID_5 = 0x5,
+};
+
struct cam_vfe_bus_ver2_common_data {
uint32_t core_index;
void __iomem *mem_base;
@@ -136,6 +146,9 @@
uint32_t intra_client_mask;
uint32_t composite_mask;
+ uint32_t acquire_dev_cnt;
+ uint32_t irq_trigger_cnt;
+
void *ctx;
};
@@ -187,6 +200,28 @@
return 0;
}
+static enum cam_vfe_bus_comp_grp_id
+ cam_vfe_bus_comp_grp_id_convert(uint32_t comp_grp)
+{
+ switch (comp_grp) {
+ case CAM_ISP_RES_COMP_GROUP_ID_0:
+ return CAM_VFE_BUS_COMP_GROUP_ID_0;
+ case CAM_ISP_RES_COMP_GROUP_ID_1:
+ return CAM_VFE_BUS_COMP_GROUP_ID_1;
+ case CAM_ISP_RES_COMP_GROUP_ID_2:
+ return CAM_VFE_BUS_COMP_GROUP_ID_2;
+ case CAM_ISP_RES_COMP_GROUP_ID_3:
+ return CAM_VFE_BUS_COMP_GROUP_ID_3;
+ case CAM_ISP_RES_COMP_GROUP_ID_4:
+ return CAM_VFE_BUS_COMP_GROUP_ID_4;
+ case CAM_ISP_RES_COMP_GROUP_ID_5:
+ return CAM_VFE_BUS_COMP_GROUP_ID_5;
+ case CAM_ISP_RES_COMP_GROUP_NONE:
+ default:
+ return CAM_VFE_BUS_COMP_GROUP_NONE;
+ }
+}
+
static int cam_vfe_bus_put_evt_payload(void *core_info,
struct cam_vfe_bus_irq_evt_payload **evt_payload)
{
@@ -1188,12 +1223,18 @@
struct cam_isp_resource_node **comp_grp)
{
int rc = 0;
+ uint32_t bus_comp_grp_id;
struct cam_isp_resource_node *comp_grp_local = NULL;
struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL;
- /* Check if matching comp_grp already acquired */
- cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local,
- out_port_info->comp_grp_id, unique_id);
+ bus_comp_grp_id = cam_vfe_bus_comp_grp_id_convert(
+ out_port_info->comp_grp_id);
+ /* Perform match only if there is valid comp grp request */
+ if (out_port_info->comp_grp_id != CAM_ISP_RES_COMP_GROUP_NONE) {
+ /* Check if matching comp_grp already acquired */
+ cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local,
+ bus_comp_grp_id, unique_id);
+ }
if (!comp_grp_local) {
/* First find a free group */
@@ -1228,7 +1269,7 @@
rsrc_data->is_master = is_master;
rsrc_data->composite_mask = 0;
rsrc_data->unique_id = unique_id;
- rsrc_data->comp_grp_local_idx = out_port_info->comp_grp_id;
+ rsrc_data->comp_grp_local_idx = bus_comp_grp_id;
list_add_tail(&comp_grp_local->list,
&ver2_bus_priv->used_comp_grp);
@@ -1246,6 +1287,7 @@
}
rsrc_data->ctx = ctx;
+ rsrc_data->acquire_dev_cnt++;
*comp_grp = comp_grp_local;
return rc;
@@ -1260,15 +1302,21 @@
int match_found = 0;
if (!in_comp_grp) {
- CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_rsrc_data);
+ CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_comp_grp);
return -EINVAL;
}
if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) {
- /* Already Released. Do Nothing */
+ CAM_ERR(CAM_ISP, "Already released Comp Grp");
return 0;
}
+ if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+ CAM_ERR(CAM_ISP, "Invalid State %d",
+ in_comp_grp->res_state);
+ return -EBUSY;
+ }
+
in_rsrc_data = in_comp_grp->res_priv;
list_for_each_entry(comp_grp, &ver2_bus_priv->used_comp_grp, list) {
@@ -1284,23 +1332,31 @@
return -ENODEV;
}
+ in_rsrc_data->acquire_dev_cnt--;
+ if (in_rsrc_data->acquire_dev_cnt == 0) {
+ list_del(&comp_grp->list);
- list_del(&comp_grp->list);
- if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
- in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
- list_add_tail(&comp_grp->list,
- &ver2_bus_priv->free_dual_comp_grp);
- else if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0
- && in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)
- list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp);
+ in_rsrc_data->unique_id = 0;
+ in_rsrc_data->comp_grp_local_idx = CAM_VFE_BUS_COMP_GROUP_NONE;
+ in_rsrc_data->composite_mask = 0;
+ in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
- in_rsrc_data->unique_id = 0;
- in_rsrc_data->comp_grp_local_idx = 0;
- in_rsrc_data->composite_mask = 0;
- in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
+ comp_grp->tasklet_info = NULL;
+ comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
- comp_grp->tasklet_info = NULL;
- comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+ if (in_rsrc_data->comp_grp_type >=
+ CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+ in_rsrc_data->comp_grp_type <=
+ CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+ list_add_tail(&comp_grp->list,
+ &ver2_bus_priv->free_dual_comp_grp);
+ else if (in_rsrc_data->comp_grp_type >=
+ CAM_VFE_BUS_VER2_COMP_GRP_0 &&
+ in_rsrc_data->comp_grp_type <=
+ CAM_VFE_BUS_VER2_COMP_GRP_5)
+ list_add_tail(&comp_grp->list,
+ &ver2_bus_priv->free_comp_grp);
+ }
return 0;
}
@@ -1491,8 +1547,13 @@
/* Regular Composite SUCCESS */
if (status_reg & BIT(comp_grp_id + 5)) {
- cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &=
- ~BIT(comp_grp_id + 5);
+ rsrc_data->irq_trigger_cnt++;
+ if (rsrc_data->irq_trigger_cnt ==
+ rsrc_data->acquire_dev_cnt) {
+ cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &=
+ ~BIT(comp_grp_id + 5);
+ rsrc_data->irq_trigger_cnt = 0;
+ }
rc = CAM_VFE_IRQ_STATUS_SUCCESS;
}
@@ -1530,8 +1591,13 @@
/* DUAL Composite SUCCESS */
if (status_reg & BIT(comp_grp_id)) {
- cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &=
- ~BIT(comp_grp_id + 5);
+ rsrc_data->irq_trigger_cnt++;
+ if (rsrc_data->irq_trigger_cnt ==
+ rsrc_data->acquire_dev_cnt) {
+ cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &=
+ ~BIT(comp_grp_id + 5);
+ rsrc_data->irq_trigger_cnt = 0;
+ }
rc = CAM_VFE_IRQ_STATUS_SUCCESS;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
index b66480c..94a591c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile
new file mode 100644
index 0000000..ec1d2fd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
new file mode 100644
index 0000000..72cabf1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -0,0 +1,594 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <cam_sensor_cmn_header.h>
+#include "cam_ois_core.h"
+#include "cam_ois_soc.h"
+#include "cam_sensor_util.h"
+#include "cam_debug_util.h"
+
+/**
+ * cam_ois_get_dev_handle - get device handle
+ * @o_ctrl: ctrl structure
+ * @arg: Camera control command argument
+ *
+ * Returns success or failure
+ */
+static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl,
+ void *arg)
+{
+ struct cam_sensor_acquire_dev ois_acq_dev;
+ struct cam_create_dev_hdl bridge_params;
+ struct cam_control *cmd = (struct cam_control *)arg;
+
+ if (o_ctrl->bridge_intf.device_hdl != -1) {
+ CAM_ERR(CAM_OIS, "Device is already acquired");
+ return -EFAULT;
+ }
+ if (copy_from_user(&ois_acq_dev, (void __user *) cmd->handle,
+ sizeof(ois_acq_dev)))
+ return -EFAULT;
+
+ bridge_params.session_hdl = ois_acq_dev.session_handle;
+ bridge_params.ops = &o_ctrl->bridge_intf.ops;
+ bridge_params.v4l2_sub_dev_flag = 0;
+ bridge_params.media_entity_flag = 0;
+ bridge_params.priv = o_ctrl;
+
+ ois_acq_dev.device_handle =
+ cam_create_device_hdl(&bridge_params);
+ o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle;
+ o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle;
+
+ CAM_DBG(CAM_OIS, "Device Handle: %d", ois_acq_dev.device_handle);
+ if (copy_to_user((void __user *) cmd->handle, &ois_acq_dev,
+ sizeof(struct cam_sensor_acquire_dev))) {
+ CAM_ERR(CAM_OIS, "ACQUIRE_DEV: copy to user failed");
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int cam_ois_vreg_control(struct cam_ois_ctrl_t *o_ctrl,
+ int config)
+{
+ int rc = 0, cnt;
+ struct cam_hw_soc_info *soc_info;
+
+ soc_info = &o_ctrl->soc_info;
+ cnt = soc_info->num_rgltr;
+
+ if (!cnt)
+ return 0;
+
+ if (cnt >= CAM_SOC_MAX_REGULATOR) {
+ CAM_ERR(CAM_OIS, "Regulators more than supported %d", cnt);
+ return -EINVAL;
+ }
+
+ if (config)
+ rc = cam_soc_util_enable_platform_resource(soc_info, false, 0,
+ false);
+ else
+ rc = cam_soc_util_disable_platform_resource(soc_info, false,
+ false);
+
+ return rc;
+}
+
+static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl)
+{
+ int rc = 0;
+ struct cam_hw_soc_info *soc_info =
+ &o_ctrl->soc_info;
+ struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+ rc = cam_ois_vreg_control(o_ctrl, 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS Reg Failed %d", rc);
+ return rc;
+ }
+
+ gpio_num_info = o_ctrl->gpio_num_info;
+
+ if (soc_info->gpio_data &&
+ gpio_num_info &&
+ gpio_num_info->valid[SENSOR_VAF] == 1) {
+ rc = cam_soc_util_request_platform_resource(&o_ctrl->soc_info,
+ NULL, NULL);
+ rc = cam_soc_util_enable_platform_resource(&o_ctrl->soc_info,
+ false, 0, false);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "Failed in req gpio: %d", rc);
+ return rc;
+ }
+
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_VAF],
+ 1);
+ }
+
+ /* VREG needs some delay to power up */
+ usleep_range(2000, 2050);
+
+ return rc;
+}
+
+static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl)
+{
+ int32_t rc = 0;
+ struct cam_hw_soc_info *soc_info =
+ &o_ctrl->soc_info;
+ struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+ rc = cam_ois_vreg_control(o_ctrl, 0);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "Failed %d");
+ return rc;
+ }
+
+ gpio_num_info = o_ctrl->gpio_num_info;
+
+ if (soc_info->gpio_data &&
+ gpio_num_info &&
+ gpio_num_info->valid[SENSOR_VAF] == 1) {
+
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_VAF],
+ GPIOF_OUT_INIT_LOW);
+
+ rc = cam_soc_util_release_platform_resource(&o_ctrl->soc_info);
+ rc |= cam_soc_util_disable_platform_resource(&o_ctrl->soc_info,
+ 0, 0);
+ if (rc < 0)
+ CAM_ERR(CAM_OIS,
+ "Failed to disable platform resources: %d", rc);
+ }
+
+ return rc;
+}
+
+static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl,
+ struct i2c_settings_array *i2c_set)
+{
+ struct i2c_settings_list *i2c_list;
+ int32_t rc = 0;
+ uint32_t i, size;
+
+ if (o_ctrl == NULL || i2c_set == NULL) {
+ CAM_ERR(CAM_OIS, "Invalid Args");
+ return -EINVAL;
+ }
+
+ if (i2c_set->is_settings_valid != 1) {
+ CAM_ERR(CAM_OIS, " Invalid settings");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(i2c_list,
+ &(i2c_set->list_head), list) {
+ if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) {
+ rc = camera_io_dev_write(&(o_ctrl->io_master_info),
+ &(i2c_list->i2c_settings));
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "Failed in Applying i2c wrt settings");
+ return rc;
+ }
+ } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
+ size = i2c_list->i2c_settings.size;
+ for (i = 0; i < size; i++) {
+ rc = camera_io_dev_poll(
+ &(o_ctrl->io_master_info),
+ i2c_list->i2c_settings.
+ reg_setting[i].reg_addr,
+ i2c_list->i2c_settings.
+ reg_setting[i].reg_data,
+ i2c_list->i2c_settings.
+ reg_setting[i].data_mask,
+ i2c_list->i2c_settings.addr_type,
+ i2c_list->i2c_settings.data_type,
+ i2c_list->i2c_settings.
+ reg_setting[i].delay);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "i2c poll apply setting Fail");
+ return rc;
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
+ uint32_t *cmd_buf)
+{
+ int32_t rc = 0;
+ struct cam_cmd_ois_info *ois_info;
+
+ if (!o_ctrl || !cmd_buf) {
+ CAM_ERR(CAM_OIS, "Invalid Args");
+ return -EINVAL;
+ }
+
+ ois_info = (struct cam_cmd_ois_info *)cmd_buf;
+ if (o_ctrl->io_master_info.master_type == CCI_MASTER) {
+ o_ctrl->io_master_info.cci_client->i2c_freq_mode =
+ ois_info->i2c_freq_mode;
+ o_ctrl->io_master_info.cci_client->sid =
+ ois_info->slave_addr >> 1;
+ o_ctrl->ois_fw_flag = ois_info->ois_fw_flag;
+ o_ctrl->is_ois_calib = ois_info->is_ois_calib;
+ memcpy(o_ctrl->ois_name, ois_info->ois_name, 32);
+ o_ctrl->io_master_info.cci_client->retries = 3;
+ o_ctrl->io_master_info.cci_client->id_map = 0;
+ memcpy(&(o_ctrl->opcode), &(ois_info->opcode),
+ sizeof(struct cam_ois_opcode));
+ CAM_DBG(CAM_OIS, "Slave addr: 0x%x Freq Mode: %d",
+ ois_info->slave_addr, ois_info->i2c_freq_mode);
+ } else if (o_ctrl->io_master_info.master_type == I2C_MASTER) {
+ o_ctrl->io_master_info.client->addr = ois_info->slave_addr;
+ CAM_DBG(CAM_OIS, "Slave addr: 0x%x", ois_info->slave_addr);
+ } else {
+ CAM_ERR(CAM_OIS, "Invalid Master type : %d",
+ o_ctrl->io_master_info.master_type);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl)
+{
+ uint16_t total_bytes = 0;
+ uint8_t *ptr = NULL;
+ int32_t rc = 0, cnt;
+ const struct firmware *fw = NULL;
+ const char *fw_name_prog = NULL;
+ const char *fw_name_coeff = NULL;
+ char name_prog[32] = {0};
+ char name_coeff[32] = {0};
+ struct device *dev = &(o_ctrl->pdev->dev);
+ struct cam_sensor_i2c_reg_setting i2c_reg_setting;
+
+ if (!o_ctrl) {
+ CAM_ERR(CAM_OIS, "Invalid Args");
+ return -EINVAL;
+ }
+
+ snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name);
+
+ snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name);
+
+ /* cast pointer as const pointer*/
+ fw_name_prog = name_prog;
+ fw_name_coeff = name_coeff;
+
+ /* Load FW */
+ rc = request_firmware(&fw, fw_name_prog, dev);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_prog);
+ return rc;
+ }
+
+ total_bytes = fw->size;
+ i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+ i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+ i2c_reg_setting.size = total_bytes;
+ i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
+ kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
+ GFP_KERNEL);
+ if (!i2c_reg_setting.reg_setting) {
+ CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
+ cnt++, ptr++) {
+ i2c_reg_setting.reg_setting[cnt].reg_addr =
+ o_ctrl->opcode.prog;
+ i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
+ i2c_reg_setting.reg_setting[cnt].delay = 0;
+ i2c_reg_setting.reg_setting[cnt].data_mask = 0;
+ }
+
+ rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
+ &i2c_reg_setting, 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
+ goto release_firmware;
+ }
+ kfree(i2c_reg_setting.reg_setting);
+ release_firmware(fw);
+
+ rc = request_firmware(&fw, fw_name_coeff, dev);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff);
+ return rc;
+ }
+
+ total_bytes = fw->size;
+ i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+ i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+ i2c_reg_setting.size = total_bytes;
+ i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
+ kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
+ GFP_KERNEL);
+ if (!i2c_reg_setting.reg_setting) {
+ CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
+ cnt++, ptr++) {
+ i2c_reg_setting.reg_setting[cnt].reg_addr =
+ o_ctrl->opcode.coeff;
+ i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
+ i2c_reg_setting.reg_setting[cnt].delay = 0;
+ i2c_reg_setting.reg_setting[cnt].data_mask = 0;
+ }
+
+ rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
+ &i2c_reg_setting, 1);
+ if (rc < 0)
+ CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
+
+release_firmware:
+ kfree(i2c_reg_setting.reg_setting);
+ release_firmware(fw);
+
+ return rc;
+}
+
+/**
+ * cam_ois_pkt_parse - Parse csl packet
+ * @o_ctrl: ctrl structure
+ * @arg: Camera control command argument
+ *
+ * Returns success or failure
+ */
+static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
+{
+ int32_t rc = 0;
+ uint64_t generic_ptr;
+ struct cam_control *ioctl_ctrl = NULL;
+ struct cam_config_dev_cmd dev_config;
+ struct i2c_settings_array *i2c_reg_settings = NULL;
+ struct cam_cmd_buf_desc *cmd_desc = NULL;
+ uint64_t generic_pkt_addr;
+ size_t pkt_len;
+ struct cam_packet *csl_packet = NULL;
+ size_t len_of_buff = 0;
+ uint32_t *offset = NULL, *cmd_buf;
+
+ ioctl_ctrl = (struct cam_control *)arg;
+ if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle,
+ sizeof(dev_config)))
+ return -EFAULT;
+ rc = cam_mem_get_cpu_buf(dev_config.packet_handle,
+ (uint64_t *)&generic_pkt_addr, &pkt_len);
+ if (rc) {
+ CAM_ERR(CAM_OIS,
+ "error in converting command Handle Error: %d", rc);
+ return rc;
+ }
+
+ if (dev_config.offset > pkt_len) {
+ CAM_ERR(CAM_OIS,
+ "offset is out of bound: off: %lld len: %zu",
+ dev_config.offset, pkt_len);
+ return -EINVAL;
+ }
+
+ csl_packet = (struct cam_packet *)
+ (generic_pkt_addr + dev_config.offset);
+ switch (csl_packet->header.op_code & 0xFFFFFF) {
+ case CAM_OIS_PACKET_OPCODE_INIT:
+ offset = (uint32_t *)&csl_packet->payload;
+ offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
+ cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+
+ if ((csl_packet->num_cmd_buf < 2) &&
+ (csl_packet->num_cmd_buf > 3)) {
+ CAM_ERR(CAM_OIS, "wrong cmd Buffer count: %d",
+ csl_packet->num_cmd_buf);
+ return -EINVAL;
+ }
+
+ rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
+ (uint64_t *)&generic_ptr, &len_of_buff);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "Failed to get cpu buf");
+ return rc;
+ }
+
+ cmd_buf = (uint32_t *)generic_ptr;
+ cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+ rc = cam_ois_slaveInfo_pkt_parser(o_ctrl, cmd_buf);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "Failed in parsing the pkt");
+ return rc;
+ }
+
+ cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
+
+ i2c_reg_settings = &(o_ctrl->i2c_init_data);
+ i2c_reg_settings->is_settings_valid = 1;
+ i2c_reg_settings->request_id = 0;
+ rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+ &cmd_desc[1], 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d",
+ rc);
+ return rc;
+ }
+
+ if (o_ctrl->is_ois_calib) {
+ i2c_reg_settings = &(o_ctrl->i2c_calib_data);
+ i2c_reg_settings->is_settings_valid = 1;
+ i2c_reg_settings->request_id = 0;
+ rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+ &cmd_desc[2], 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "OIS pkt parsing failed: %d", rc);
+ return rc;
+ }
+ }
+ break;
+ case CAM_OIS_PACKET_OPCODE_OIS_CONTROL:
+ offset = (uint32_t *)&csl_packet->payload;
+ offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
+ cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+ i2c_reg_settings = &(o_ctrl->i2c_mode_data);
+ i2c_reg_settings->is_settings_valid = 1;
+ i2c_reg_settings->request_id = 0;
+ rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+ cmd_desc, 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc);
+ return rc;
+ }
+
+ rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings);
+ if (rc < 0)
+ CAM_ERR(CAM_OIS, "Cannot apply mode settings");
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+/**
+ * cam_ois_driver_cmd - Handle ois cmds
+ * @e_ctrl: ctrl structure
+ * @arg: Camera control command argument
+ *
+ * Returns success or failure
+ */
+int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg)
+{
+ int rc = 0;
+ struct cam_ois_query_cap_t ois_cap = {0};
+ struct cam_control *cmd = (struct cam_control *)arg;
+
+ if (!o_ctrl) {
+ CAM_ERR(CAM_OIS, "e_ctrl is NULL");
+ return -EINVAL;
+ }
+
+ mutex_lock(&(o_ctrl->ois_mutex));
+ switch (cmd->op_code) {
+ case CAM_QUERY_CAP:
+ ois_cap.slot_info = o_ctrl->subdev_id;
+
+ if (copy_to_user((void __user *) cmd->handle,
+ &ois_cap,
+ sizeof(struct cam_ois_query_cap_t))) {
+ CAM_ERR(CAM_OIS, "Failed Copy to User");
+ return -EFAULT;
+ goto release_mutex;
+ }
+ CAM_DBG(CAM_OIS, "ois_cap: ID: %d", ois_cap.slot_info);
+ break;
+ case CAM_ACQUIRE_DEV:
+ rc = cam_ois_get_dev_handle(o_ctrl, arg);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Failed to acquire dev");
+ goto release_mutex;
+ }
+ break;
+ case CAM_START_DEV:
+ rc = cam_ois_power_up(o_ctrl);
+ if (rc) {
+ CAM_ERR(CAM_OIS, " OIS Power up failed");
+ goto release_mutex;
+ }
+ rc = camera_io_init(&o_ctrl->io_master_info);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "cci_init failed");
+ goto pwr_dwn;
+ }
+
+ if (o_ctrl->ois_fw_flag) {
+ rc = cam_ois_fw_download(o_ctrl);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Failed OIS FW Download");
+ goto pwr_dwn;
+ }
+ }
+
+ rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "Cannot apply Init settings");
+ goto pwr_dwn;
+ }
+
+ if (o_ctrl->is_ois_calib) {
+ rc = cam_ois_apply_settings(o_ctrl,
+ &o_ctrl->i2c_calib_data);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Cannot apply calib data");
+ goto pwr_dwn;
+ }
+ }
+ break;
+ case CAM_CONFIG_DEV:
+ rc = cam_ois_pkt_parse(o_ctrl, arg);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "Failed in ois pkt Parsing");
+ goto release_mutex;
+ }
+ break;
+ case CAM_RELEASE_DEV:
+ if (o_ctrl->bridge_intf.device_hdl == -1) {
+ CAM_ERR(CAM_OIS, "link hdl: %d device hdl: %d",
+ o_ctrl->bridge_intf.device_hdl,
+ o_ctrl->bridge_intf.link_hdl);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+ rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl);
+ if (rc < 0)
+ CAM_ERR(CAM_OIS, "destroying the device hdl");
+ o_ctrl->bridge_intf.device_hdl = -1;
+ o_ctrl->bridge_intf.link_hdl = -1;
+ o_ctrl->bridge_intf.session_hdl = -1;
+ break;
+ case CAM_STOP_DEV:
+ rc = camera_io_release(&o_ctrl->io_master_info);
+ if (rc < 0)
+ CAM_ERR(CAM_OIS, "Failed in releasing CCI");
+ rc = cam_ois_power_down(o_ctrl);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS Power down failed");
+ goto release_mutex;
+ }
+ break;
+ default:
+ CAM_ERR(CAM_OIS, "invalid opcode");
+ goto release_mutex;
+ }
+pwr_dwn:
+ cam_ois_power_down(o_ctrl);
+release_mutex:
+ mutex_unlock(&(o_ctrl->ois_mutex));
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
new file mode 100644
index 0000000..13da82a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_CORE_H_
+#define _CAM_OIS_CORE_H_
+
+#include "cam_ois_dev.h"
+
+int cam_ois_driver_cmd(struct cam_ois_ctrl_t *e_ctrl, void *arg);
+
+#endif
+/* _CAM_OIS_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
new file mode 100644
index 0000000..aeab388
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_ois_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_ois_soc.h"
+#include "cam_ois_core.h"
+#include "cam_debug_util.h"
+
+static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd);
+
+ switch (cmd) {
+ case VIDIOC_CAM_CONTROL:
+ rc = cam_ois_driver_cmd(o_ctrl, arg);
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+
+ return rc;
+}
+
+static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl,
+ struct cam_ois_i2c_info_t *i2c_info)
+{
+ struct cam_sensor_cci_client *cci_client = NULL;
+
+ if (o_ctrl->io_master_info.master_type == CCI_MASTER) {
+ cci_client = o_ctrl->io_master_info.cci_client;
+ if (!cci_client) {
+ CAM_ERR(CAM_OIS, "failed: cci_client %pK",
+ cci_client);
+ return -EINVAL;
+ }
+ cci_client->cci_i2c_master = o_ctrl->cci_i2c_master;
+ cci_client->sid = (i2c_info->slave_addr) >> 1;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_ois_init_subdev_do_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, unsigned long arg)
+{
+ struct cam_control cmd_data;
+ int32_t rc = 0;
+
+ if (copy_from_user(&cmd_data, (void __user *)arg,
+ sizeof(cmd_data))) {
+ CAM_ERR(CAM_OIS,
+ "Failed to copy from user_ptr=%pK size=%zu",
+ (void __user *)arg, sizeof(cmd_data));
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case VIDIOC_CAM_CONTROL:
+ rc = cam_ois_subdev_ioctl(sd, cmd, &cmd_data);
+ if (rc) {
+ CAM_ERR(CAM_OIS,
+ "Failed in ois suddev handling rc %d",
+ rc);
+ return rc;
+ }
+ break;
+ default:
+ CAM_ERR(CAM_OIS, "Invalid compat ioctl: %d", cmd);
+ rc = -EINVAL;
+ }
+
+ if (!rc) {
+ if (copy_to_user((void __user *)arg, &cmd_data,
+ sizeof(cmd_data))) {
+ CAM_ERR(CAM_OIS,
+ "Failed to copy from user_ptr=%pK size=%zu",
+ (void __user *)arg, sizeof(cmd_data));
+ rc = -EFAULT;
+ }
+ }
+ return rc;
+}
+#endif
+
+static const struct v4l2_subdev_internal_ops cam_ois_internal_ops;
+
+static struct v4l2_subdev_core_ops cam_ois_subdev_core_ops = {
+ .ioctl = cam_ois_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = cam_ois_init_subdev_do_ioctl,
+#endif
+};
+
+static struct v4l2_subdev_ops cam_ois_subdev_ops = {
+ .core = &cam_ois_subdev_core_ops,
+};
+
+static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl)
+{
+ int rc = 0;
+
+ o_ctrl->v4l2_dev_str.internal_ops = &cam_ois_internal_ops;
+ o_ctrl->v4l2_dev_str.ops = &cam_ois_subdev_ops;
+ strlcpy(o_ctrl->device_name, CAM_OIS_NAME,
+ sizeof(o_ctrl->device_name));
+ o_ctrl->v4l2_dev_str.name = o_ctrl->device_name;
+ o_ctrl->v4l2_dev_str.sd_flags =
+ (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+ o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE;
+ o_ctrl->v4l2_dev_str.token = o_ctrl;
+
+ rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str));
+ if (rc)
+ CAM_ERR(CAM_OIS, "fail to create subdev");
+
+ return rc;
+}
+
+static int cam_ois_i2c_driver_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct cam_ois_ctrl_t *o_ctrl = NULL;
+ struct cam_ois_soc_private *soc_private = NULL;
+
+ if (client == NULL || id == NULL) {
+ CAM_ERR(CAM_OIS, "Invalid Args client: %pK id: %pK",
+ client, id);
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ CAM_ERR(CAM_OIS, "i2c_check_functionality failed");
+ goto probe_failure;
+ }
+
+ o_ctrl = kzalloc(sizeof(*o_ctrl), GFP_KERNEL);
+ if (!o_ctrl) {
+ CAM_ERR(CAM_OIS, "kzalloc failed");
+ rc = -ENOMEM;
+ goto probe_failure;
+ }
+
+ i2c_set_clientdata(client, o_ctrl);
+
+ o_ctrl->soc_info.dev = &client->dev;
+ o_ctrl->soc_info.dev_name = client->name;
+ o_ctrl->ois_device_type = MSM_CAMERA_I2C_DEVICE;
+ o_ctrl->io_master_info.master_type = I2C_MASTER;
+ o_ctrl->io_master_info.client = client;
+
+ soc_private = kzalloc(sizeof(struct cam_ois_soc_private),
+ GFP_KERNEL);
+ if (!soc_private) {
+ rc = -ENOMEM;
+ goto octrl_free;
+ }
+
+ o_ctrl->soc_info.soc_private = soc_private;
+ rc = cam_ois_driver_soc_init(o_ctrl);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "failed: cam_sensor_parse_dt rc %d", rc);
+ goto octrl_free;
+ }
+
+ rc = cam_ois_init_subdev_param(o_ctrl);
+ if (rc)
+ goto octrl_free;
+
+ return rc;
+
+octrl_free:
+ kfree(o_ctrl);
+probe_failure:
+ return rc;
+}
+
+static int cam_ois_i2c_driver_remove(struct i2c_client *client)
+{
+ struct cam_ois_ctrl_t *o_ctrl = i2c_get_clientdata(client);
+
+ if (!o_ctrl) {
+ CAM_ERR(CAM_OIS, "ois device is NULL");
+ return -EINVAL;
+ }
+
+ kfree(o_ctrl->soc_info.soc_private);
+ kfree(o_ctrl);
+
+ return 0;
+}
+
+static int32_t cam_ois_platform_driver_probe(
+ struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ struct cam_ois_ctrl_t *o_ctrl = NULL;
+ struct cam_ois_soc_private *soc_private = NULL;
+
+ o_ctrl = kzalloc(sizeof(struct cam_ois_ctrl_t), GFP_KERNEL);
+ if (!o_ctrl)
+ return -ENOMEM;
+
+ o_ctrl->soc_info.pdev = pdev;
+ o_ctrl->soc_info.dev = &pdev->dev;
+ o_ctrl->soc_info.dev_name = pdev->name;
+
+ o_ctrl->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+
+ o_ctrl->io_master_info.master_type = CCI_MASTER;
+ o_ctrl->io_master_info.cci_client = kzalloc(
+ sizeof(struct cam_sensor_cci_client), GFP_KERNEL);
+ if (!o_ctrl->io_master_info.cci_client)
+ goto free_o_ctrl;
+
+ soc_private = kzalloc(sizeof(struct cam_ois_soc_private),
+ GFP_KERNEL);
+ if (!soc_private) {
+ rc = -ENOMEM;
+ goto free_cci_client;
+ }
+ o_ctrl->soc_info.soc_private = soc_private;
+
+ INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head));
+ INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head));
+ INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head));
+ mutex_init(&(o_ctrl->ois_mutex));
+ rc = cam_ois_driver_soc_init(o_ctrl);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc);
+ goto free_soc;
+ }
+
+ rc = cam_ois_init_subdev_param(o_ctrl);
+ if (rc)
+ goto free_soc;
+
+ rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "failed: to update i2c info rc %d", rc);
+ goto unreg_subdev;
+ }
+ o_ctrl->bridge_intf.device_hdl = -1;
+
+ platform_set_drvdata(pdev, o_ctrl);
+ v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl);
+
+ return rc;
+unreg_subdev:
+ cam_unregister_subdev(&(o_ctrl->v4l2_dev_str));
+free_soc:
+ kfree(soc_private);
+free_cci_client:
+ kfree(o_ctrl->io_master_info.cci_client);
+free_o_ctrl:
+ kfree(o_ctrl);
+ return rc;
+}
+
+static int cam_ois_platform_driver_remove(struct platform_device *pdev)
+{
+ struct cam_ois_ctrl_t *o_ctrl;
+
+ o_ctrl = platform_get_drvdata(pdev);
+ if (!o_ctrl) {
+ CAM_ERR(CAM_OIS, "ois device is NULL");
+ return -EINVAL;
+ }
+
+ kfree(o_ctrl->soc_info.soc_private);
+ kfree(o_ctrl->io_master_info.cci_client);
+ kfree(o_ctrl);
+ return 0;
+}
+
+static const struct of_device_id cam_ois_dt_match[] = {
+ { .compatible = "qcom,ois" },
+ { }
+};
+
+
+MODULE_DEVICE_TABLE(of, cam_ois_dt_match);
+
+static struct platform_driver cam_ois_platform_driver = {
+ .driver = {
+ .name = "qcom,ois",
+ .owner = THIS_MODULE,
+ .of_match_table = cam_ois_dt_match,
+ },
+ .probe = cam_ois_platform_driver_probe,
+ .remove = cam_ois_platform_driver_remove,
+};
+static const struct i2c_device_id cam_ois_i2c_id[] = {
+ { "msm_ois", (kernel_ulong_t)NULL},
+ { }
+};
+
+static struct i2c_driver cam_ois_i2c_driver = {
+ .id_table = cam_ois_i2c_id,
+ .probe = cam_ois_i2c_driver_probe,
+ .remove = cam_ois_i2c_driver_remove,
+ .driver = {
+ .name = "msm_ois",
+ },
+};
+
+static struct cam_ois_registered_driver_t registered_driver = {
+ 0, 0};
+
+static int __init cam_ois_driver_init(void)
+{
+ int rc = 0;
+
+ rc = platform_driver_register(&cam_ois_platform_driver);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "platform_driver_register failed rc = %d",
+ rc);
+ return rc;
+ }
+
+ registered_driver.platform_driver = 1;
+
+ rc = i2c_add_driver(&cam_ois_i2c_driver);
+ if (rc) {
+ CAM_ERR(CAM_OIS, "i2c_add_driver failed rc = %d", rc);
+ return rc;
+ }
+
+ registered_driver.i2c_driver = 1;
+ return rc;
+}
+
+static void __exit cam_ois_driver_exit(void)
+{
+ if (registered_driver.platform_driver)
+ platform_driver_unregister(&cam_ois_platform_driver);
+
+ if (registered_driver.i2c_driver)
+ i2c_del_driver(&cam_ois_i2c_driver);
+}
+
+module_init(cam_ois_driver_init);
+module_exit(cam_ois_driver_exit);
+MODULE_DESCRIPTION("CAM OIS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
new file mode 100644
index 0000000..95ebed1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_DEV_H_
+#define _CAM_OIS_DEV_H_
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cam_sensor.h>
+#include <cam_sensor_i2c.h>
+#include <cam_sensor_spi.h>
+#include <cam_sensor_io.h>
+#include <cam_cci_dev.h>
+#include <cam_req_mgr_util.h>
+#include <cam_req_mgr_interface.h>
+#include <cam_mem_mgr.h>
+#include <cam_subdev.h>
+#include "cam_soc_util.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+/**
+ * struct cam_ois_registered_driver_t - registered driver info
+ * @platform_driver : flag indicates if platform driver is registered
+ * @i2c_driver : flag indicates if i2c driver is registered
+ *
+ */
+struct cam_ois_registered_driver_t {
+ bool platform_driver;
+ bool i2c_driver;
+};
+
+/**
+ * struct cam_ois_i2c_info_t - I2C info
+ * @slave_addr : slave address
+ * @i2c_freq_mode : i2c frequency mode
+ *
+ */
+struct cam_ois_i2c_info_t {
+ uint16_t slave_addr;
+ uint8_t i2c_freq_mode;
+};
+
+/**
+ * struct cam_ois_soc_private - ois soc private data structure
+ * @ois_name : ois name
+ * @i2c_info : i2c info structure
+ * @power_info : ois power info
+ *
+ */
+struct cam_ois_soc_private {
+ const char *ois_name;
+ struct cam_ois_i2c_info_t i2c_info;
+ struct cam_sensor_power_ctrl_t power_info;
+};
+
+/**
+ * struct cam_ois_intf_params - bridge interface params
+ * @device_hdl : Device Handle
+ * @session_hdl : Session Handle
+ * @ops : KMD operations
+ * @crm_cb : Callback API pointers
+ */
+struct cam_ois_intf_params {
+ int32_t device_hdl;
+ int32_t session_hdl;
+ int32_t link_hdl;
+ struct cam_req_mgr_kmd_ops ops;
+ struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct cam_ois_ctrl_t - OIS ctrl private data
+ * @pdev : platform device
+ * @ois_mutex : ois mutex
+ * @soc_info : ois soc related info
+ * @io_master_info : Information about the communication master
+ * @gpio_num_info : gpio info
+ * @cci_i2c_master : I2C structure
+ * @v4l2_dev_str : V4L2 device structure
+ * @bridge_intf : bridge interface params
+ * @i2c_init_data : ois i2c init settings
+ * @i2c_mode_data : ois i2c mode settings
+ * @i2c_calib_data : ois i2c calib settings
+ * @ois_device_type : ois device type
+ * @subdev_id : subdev id
+ * @ois_name : ois name
+ * @ois_fw_flag : flag for firmware download
+ * @is_ois_calib : flag for Calibration data
+ * @opcode : ois opcode
+ * @device_name : Device name
+ *
+ */
+struct cam_ois_ctrl_t {
+ struct platform_device *pdev;
+ struct mutex ois_mutex;
+ struct cam_hw_soc_info soc_info;
+ struct camera_io_master io_master_info;
+ struct msm_camera_gpio_num_info *gpio_num_info;
+ enum cci_i2c_master_t cci_i2c_master;
+ struct cam_subdev v4l2_dev_str;
+ struct cam_ois_intf_params bridge_intf;
+ struct i2c_settings_array i2c_init_data;
+ struct i2c_settings_array i2c_calib_data;
+ struct i2c_settings_array i2c_mode_data;
+ enum msm_camera_device_type_t ois_device_type;
+ uint32_t subdev_id;
+ char device_name[20];
+ char ois_name[32];
+ uint8_t ois_fw_flag;
+ uint8_t is_ois_calib;
+ struct cam_ois_opcode opcode;
+};
+
+#endif /*_CAM_OIS_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c
new file mode 100644
index 0000000..916e699
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_sensor_util.h>
+#include <cam_sensor_io.h>
+#include <cam_req_mgr_util.h>
+
+#include "cam_ois_soc.h"
+#include "cam_debug_util.h"
+
+/**
+ * @e_ctrl: ctrl structure
+ *
+ * Parses ois dt
+ */
+static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl)
+{
+ int rc = 0;
+ struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info;
+ struct cam_ois_soc_private *soc_private =
+ (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
+ struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info;
+ struct device_node *of_node = NULL;
+
+ of_node = soc_info->dev->of_node;
+
+ if (!of_node) {
+ CAM_ERR(CAM_OIS, "of_node is NULL, device type %d",
+ o_ctrl->ois_device_type);
+ return -EINVAL;
+ }
+ rc = cam_soc_util_get_dt_properties(soc_info);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "cam_soc_util_get_dt_properties rc %d",
+ rc);
+ return rc;
+ }
+
+ if (!soc_info->gpio_data) {
+ CAM_INFO(CAM_OIS, "No GPIO found");
+ return 0;
+ }
+
+ if (!soc_info->gpio_data->cam_gpio_common_tbl_size) {
+ CAM_INFO(CAM_OIS, "No GPIO found");
+ return -EINVAL;
+ }
+
+ rc = cam_sensor_util_init_gpio_pin_tbl(soc_info,
+ &power_info->gpio_num_info);
+ if ((rc < 0) || (!power_info->gpio_num_info)) {
+ CAM_ERR(CAM_OIS, "No/Error OIS GPIOs");
+ return -EINVAL;
+ }
+
+ return rc;
+}
+/**
+ * @o_ctrl: ctrl structure
+ *
+ * This function is called from cam_ois_platform/i2c_driver_probe, it parses
+ * the ois dt node.
+ */
+int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl)
+{
+ int rc = 0;
+ struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info;
+ struct device_node *of_node = NULL;
+
+ if (!soc_info->dev) {
+ CAM_ERR(CAM_OIS, "soc_info is not initialized");
+ return -EINVAL;
+ }
+
+ of_node = soc_info->dev->of_node;
+ if (!of_node) {
+ CAM_ERR(CAM_OIS, "dev.of_node NULL");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(of_node, "cell-index",
+ &o_ctrl->subdev_id);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "failed rc %d", rc);
+ return rc;
+ }
+
+ if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ rc = of_property_read_u32(of_node, "cci-master",
+ &o_ctrl->cci_i2c_master);
+ if (rc < 0) {
+ CAM_DBG(CAM_OIS, "failed rc %d", rc);
+ return rc;
+ }
+ }
+
+ rc = cam_ois_get_dt_data(o_ctrl);
+ if (rc < 0)
+ CAM_DBG(CAM_OIS, "failed: ois get dt data rc %d", rc);
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h
new file mode 100644
index 0000000..af04134
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_SOC_H_
+#define _CAM_OIS_SOC_H_
+
+#include "cam_ois_dev.h"
+
+int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl);
+
+#endif/* _CAM_OIS_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 6ebd58b..97b4c01 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -33,6 +33,7 @@
#define CAM_CSIPHY_NAME "cam-csiphy"
#define CAM_FLASH_NAME "cam-flash"
#define CAM_EEPROM_NAME "cam-eeprom"
+#define CAM_OIS_NAME "cam-ois"
#define MAX_SYSTEM_PIPELINE_DELAY 2
@@ -165,6 +166,11 @@
CAM_EEPROM_PACKET_OPCODE_INIT
};
+enum cam_ois_packet_opcodes {
+ CAM_OIS_PACKET_OPCODE_INIT,
+ CAM_OIS_PACKET_OPCODE_OIS_CONTROL
+};
+
enum msm_bus_perf_setting {
S_INIT,
S_PREVIEW,
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
index 21f90ca..f451155 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
@@ -83,6 +83,9 @@
case CAM_HFI:
name = "CAM-HFI";
break;
+ case CAM_OIS:
+ name = "CAM-OIS";
+ break;
default:
name = "CAM";
break;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index 7275d56..40dbe00 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -33,6 +33,7 @@
#define CAM_UTIL (1 << 17)
#define CAM_HFI (1 << 18)
#define CAM_CTXT (1 << 19)
+#define CAM_OIS (1 << 20)
#define STR_BUFFER_MAX_LENGTH 1024
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index f16c1ba..39793b6 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -523,13 +523,17 @@
int level;
struct mpq_demux *mpq_demux = fp->private_data;
- if (count >= 16)
+ if (count == 0 || count >= 16)
return -EINVAL;
- ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer,
+ memset(user_str, '\0', sizeof(user_str));
+
+ ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer,
count);
if (ret_count < 0)
return ret_count;
+ else if (ret_count == 0)
+ return -EINVAL;
ret = kstrtoint(user_str, 0, &level);
if (ret)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index b1438d5..400f53b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -39,6 +39,7 @@
#define SDE_MDP_HW_REV_300 SDE_MDP_REV(3, 0, 0) /* 8998 v1.0 */
#define SDE_MDP_HW_REV_301 SDE_MDP_REV(3, 0, 1) /* 8998 v1.1 */
#define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_MDP_HW_REV_410 SDE_MDP_REV(4, 1, 0) /* sdm670 v1.0 */
#define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4
#define SDE_MDP_VBIF_8_LEVEL_REMAPPER 8
@@ -157,6 +158,7 @@
struct reg_bus_client *reg_bus_clt;
bool domain_attached;
int domain;
+ u32 sid;
};
/*
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 0704602..03d4840 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -45,18 +45,12 @@
/* Rotator device id to be used in SCM call */
#define SDE_ROTATOR_DEVICE 21
-#ifndef VMID_CP_CAMERA_PREVIEW
-#define VMID_CP_CAMERA_PREVIEW VMID_INVAL
-#endif
-
-/* SCM call function id to be used for switching between secure and non
+/*
+ * SCM call function id to be used for switching between secure and non
* secure context
*/
#define MEM_PROTECT_SD_CTRL_SWITCH 0x18
-/* Rotator secure SID */
-#define SDE_ROTATOR_SECURE_SID 0xe01
-
/* waiting for hw time out, 3 vsync for 30fps*/
#define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100
@@ -601,7 +595,7 @@
if (test_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU,
mdata->sde_caps_map)) {
- sid_info = SDE_ROTATOR_SECURE_SID;
+ sid_info = mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_SECURE].sid;
desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
desc.args[0] = SDE_ROTATOR_DEVICE;
desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
@@ -631,9 +625,12 @@
return -EINVAL;
}
- SDEROT_DBG("scm_call(1) ret=%d, resp=%x",
+ SDEROT_DBG(
+ "scm(1) sid0x%x dev0x%llx vmid0x%llx ret%d resp%x\n",
+ sid_info, desc.args[0], desc.args[3],
ret, resp);
- SDEROT_EVTLOG(1);
+ SDEROT_EVTLOG(1, sid_info, desc.args[0], desc.args[3],
+ ret, resp);
} else if (mdata->sec_cam_en && !enable) {
/*
* Disable secure camera operation
@@ -648,12 +645,16 @@
MEM_PROTECT_SD_CTRL_SWITCH), &desc);
resp = desc.ret[0];
- SDEROT_DBG("scm_call(0): ret=%d, resp=%x",
+ SDEROT_DBG(
+ "scm(0) sid0x%x dev0x%llx vmid0x%llx ret%d resp%d\n",
+ sid_info, desc.args[0], desc.args[3],
ret, resp);
/* force smmu to reattach */
sde_smmu_secure_ctrl(1);
- SDEROT_EVTLOG(0);
+
+ SDEROT_EVTLOG(0, sid_info, desc.args[0], desc.args[3],
+ ret, resp);
}
} else {
return 0;
@@ -3079,7 +3080,9 @@
} else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
SDE_MDP_HW_REV_300) ||
IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
- SDE_MDP_HW_REV_400)) {
+ SDE_MDP_HW_REV_400) ||
+ IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
+ SDE_MDP_HW_REV_410)) {
mgr->ops_hw_init = sde_rotator_r3_init;
} else {
ret = -ENODEV;
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 4ad960d8..a838128 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1478,7 +1478,7 @@
}
SDEROT_DBG(
- "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu wb:%d vid:%d cmd:%d\n",
+ "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu prefill:%llu wb:%d vid:%d cmd:%d\n",
ctx->session_id, cmd->sequence_id,
cmd->src_rect_x, cmd->src_rect_y,
cmd->src_rect_w, cmd->src_rect_h,
@@ -1490,7 +1490,7 @@
cmd->dst_pixfmt >> 0, cmd->dst_pixfmt >> 8,
cmd->dst_pixfmt >> 16, cmd->dst_pixfmt >> 24,
cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps,
- cmd->clkrate, cmd->data_bw,
+ cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
cmd->dst_writeback, cmd->video_mode, cmd_type);
SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id,
cmd->src_rect_x, cmd->src_rect_y,
@@ -1498,11 +1498,11 @@
cmd->src_pixfmt,
cmd->dst_rect_w, cmd->dst_rect_h,
cmd->dst_pixfmt,
+ cmd->fps, cmd->clkrate, cmd->data_bw, cmd->prefill_bw,
(cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) |
(cmd->secure << 3) | (cmd->dst_writeback << 4) |
- (cmd->video_mode << 5),
- cmd->fps, cmd->clkrate, cmd->data_bw,
- cmd_type);
+ (cmd->video_mode << 5) |
+ (cmd_type << 24));
sde_rot_mgr_lock(rot_dev->mgr);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 1a9e84d..3d39fa2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1437,8 +1437,7 @@
wrptr = sde_hw_rotator_get_regdma_segment(ctx);
/* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
- if (!ctx->sbuf_mode &&
- (ctx->is_traffic_shaping || cfg->prefill_bw)) {
+ if (ctx->is_traffic_shaping || cfg->prefill_bw) {
u32 bw;
/*
@@ -2700,7 +2699,9 @@
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
/* features exposed via mdss h/w version */
- if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
+ if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400) ||
+ IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
+ SDE_MDP_HW_REV_410)) {
SDEROT_DBG("Supporting sys cache inline rotation\n");
set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map);
set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 9e47187..cc1407a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -517,6 +517,7 @@
const struct of_device_id *match;
struct sde_module_power *mp;
char name[MAX_CLIENT_NAME_LEN];
+ u32 sid = 0;
if (!mdata) {
SDEROT_INFO(
@@ -538,6 +539,11 @@
if (of_find_property(pdev->dev.of_node, "iommus", NULL)) {
dev = &pdev->dev;
+ rc = of_property_read_u32_index(pdev->dev.of_node, "iommus",
+ 1, &sid);
+ if (rc)
+ SDEROT_DBG("SID not defined for domain:%d",
+ smmu_domain.domain);
} else {
SDEROT_ERR("Invalid SMMU ctx for domain:%d\n",
smmu_domain.domain);
@@ -546,6 +552,7 @@
sde_smmu = &mdata->sde_smmu[smmu_domain.domain];
sde_smmu->domain = smmu_domain.domain;
+ sde_smmu->sid = sid;
mp = &sde_smmu->mp;
memset(mp, 0, sizeof(struct sde_module_power));
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index a11be2c..cf0413e 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1420,6 +1420,9 @@
case HAL_FLIP_VERTICAL:
hfi->flip = HFI_FLIP_VERTICAL;
break;
+ case HAL_FLIP_BOTH:
+ hfi->flip = HFI_FLIP_HORIZONTAL | HFI_FLIP_VERTICAL;
+ break;
default:
dprintk(VIDC_ERR, "Invalid flip setting: %#x\n",
prop->flip);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 56f9675..fa40091 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -448,14 +448,14 @@
static DEVICE_ATTR(thermal_level, 0644, show_thermal_level,
store_thermal_level);
-static ssize_t show_platform_version(struct device *dev,
+static ssize_t show_sku_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d",
- vidc_driver->platform_version);
+ vidc_driver->sku_version);
}
-static ssize_t store_platform_version(struct device *dev,
+static ssize_t store_sku_version(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -463,13 +463,13 @@
return count;
}
-static DEVICE_ATTR(platform_version, 0444, show_platform_version,
- store_platform_version);
+static DEVICE_ATTR(sku_version, 0444, show_sku_version,
+ store_sku_version);
static struct attribute *msm_vidc_core_attrs[] = {
&dev_attr_pwr_collapse_delay.attr,
&dev_attr_thermal_level.attr,
- &dev_attr_platform_version.attr,
+ &dev_attr_sku_version.attr,
NULL
};
@@ -487,8 +487,6 @@
static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
{
int rc = 0;
- void __iomem *base;
- struct resource *res;
struct msm_vidc_core *core;
struct device *dev;
int nr = BASE_DEVICE_NUMBER;
@@ -605,32 +603,7 @@
core->debugfs_root = msm_vidc_debugfs_init_core(
core, vidc_driver->debugfs_root);
- vidc_driver->platform_version = 0;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
- if (!res) {
- dprintk(VIDC_DBG, "failed to get efuse resource\n");
- } else {
- base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!base) {
- dprintk(VIDC_ERR,
- "failed efuse ioremap: res->start %#x, size %d\n",
- (u32)res->start, (u32)resource_size(res));
- } else {
- u32 efuse = 0;
- struct platform_version_table *pf_ver_tbl =
- core->resources.pf_ver_tbl;
-
- efuse = readl_relaxed(base);
- vidc_driver->platform_version =
- (efuse & pf_ver_tbl->version_mask) >>
- pf_ver_tbl->version_shift;
- dprintk(VIDC_DBG,
- "efuse 0x%x, platform version 0x%x\n",
- efuse, vidc_driver->platform_version);
-
- devm_iounmap(&pdev->dev, base);
- }
- }
+ vidc_driver->sku_version = core->resources.sku_version;
dprintk(VIDC_DBG, "populating sub devices\n");
/*
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index cb03576..a527717 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -413,7 +413,16 @@
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
- .step = OPERATING_FRAME_RATE_STEP,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ .name = "Set Decoder Frame rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
@@ -1127,11 +1136,27 @@
}
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
- dprintk(VIDC_DBG,
- "inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->clk_data.operating_rate >> 16,
- ctrl->val >> 16);
- inst->clk_data.operating_rate = ctrl->val;
+ if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+ ctrl->val != INT_MAX) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else if (ctrl->val == INT_MAX) {
+ dprintk(VIDC_DBG,
+ "inst(%pK) Request for turbo mode\n", inst);
+ inst->clk_data.turbo_mode = true;
+ } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+ dprintk(VIDC_ERR, "Failed to set operating rate\n");
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->clk_data.operating_rate >> 16,
+ ctrl->val >> 16);
+ inst->clk_data.operating_rate = ctrl->val;
+ inst->clk_data.turbo_mode = false;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
if (ctrl->val ==
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 0d8cb76..22c0df1 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -61,6 +61,14 @@
NULL
};
+static const char *const mpeg_video_flip[] = {
+ "No Flip",
+ "Horizontal Flip",
+ "Vertical Flip",
+ "Both",
+ NULL
+};
+
static const char *const h264_video_entropy_cabac_model[] = {
"Model 0",
"Model 1",
@@ -909,7 +917,16 @@
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
- .step = OPERATING_FRAME_RATE_STEP,
+ .step = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ .name = "Set Encoder Frame rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .default_value = 0,
+ .step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE,
@@ -1036,6 +1053,21 @@
.default_value = 0,
.step = 1,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ .name = "Flip",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH)
+ ),
+ .qmenu = mpeg_video_flip,
+ },
};
@@ -1112,6 +1144,13 @@
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
+ {
+ .name = "YCbCr Semiplanar 4:2:0 10bit",
+ .description = "Y/CbCr 4:2:0 10bit",
+ .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010,
+ .get_frame_size = get_frame_size_p010,
+ .type = OUTPUT_PORT,
+ },
};
static int msm_venc_set_csc(struct msm_vidc_inst *inst,
@@ -1420,11 +1459,27 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
{
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FLIP);
property_id = HAL_PARAM_VPE_ROTATION;
vpe_rotation.rotate = msm_comm_v4l2_to_hal(
V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
ctrl->val);
- vpe_rotation.flip = HAL_FLIP_NONE;
+ vpe_rotation.flip = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ temp_ctrl->val);
+ pdata = &vpe_rotation;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP:
+ {
+ temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+ property_id = HAL_PARAM_VPE_ROTATION;
+ vpe_rotation.rotate = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+ temp_ctrl->val);
+ vpe_rotation.flip = msm_comm_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP,
+ ctrl->val);
pdata = &vpe_rotation;
break;
}
@@ -1464,13 +1519,14 @@
pdata = &multi_slice_control;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
- bool codec_avc =
+ bool codecs_supported =
+ inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC ||
inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 ||
inst->fmts[CAPTURE_PORT].fourcc ==
V4L2_PIX_FMT_H264_NO_SC;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
- if (codec_avc && temp_ctrl->val ==
+ if (codecs_supported && temp_ctrl->val ==
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
enable.enable = true;
@@ -1817,12 +1873,27 @@
}
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
- dprintk(VIDC_DBG,
- "inst(%pK) operating rate changed from %d to %d\n",
- inst, inst->clk_data.operating_rate >> 16,
+ if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+ (ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+ ctrl->val != INT_MAX) {
+ dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+ (ctrl->val >> 16));
+ rc = -ENOTSUPP;
+ } else if (ctrl->val == INT_MAX) {
+ dprintk(VIDC_DBG, "inst(%pK) Request for turbo mode\n",
+ inst);
+ inst->clk_data.turbo_mode = true;
+ } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+ dprintk(VIDC_ERR, "Failed to set operating rate\n");
+ rc = -ENOTSUPP;
+ } else {
+ dprintk(VIDC_DBG,
+ "inst(%pK) operating rate changed from %d to %d\n",
+ inst, inst->clk_data.operating_rate >> 16,
ctrl->val >> 16);
- inst->clk_data.operating_rate = ctrl->val;
-
+ inst->clk_data.operating_rate = ctrl->val;
+ inst->clk_data.turbo_mode = false;
+ }
break;
case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 5149086..ae2a2c6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -179,6 +179,10 @@
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_bytes);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+ msm_vidc_ctrl_get_range(ctrl, &inst->capability.frame_rate);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
@@ -276,6 +280,7 @@
break;
case V4L2_PIX_FMT_NV12_TP10_UBWC:
color_format = COLOR_FMT_NV12_BPP10_UBWC;
+ break;
case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010:
color_format = COLOR_FMT_P010;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index d557959..c6d31f7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -553,7 +553,8 @@
static int msm_vidc_set_clocks(struct msm_vidc_core *core)
{
struct hfi_device *hdev;
- unsigned long freq = 0, rate = 0;
+ unsigned long freq_core_1 = 0, freq_core_2 = 0, rate = 0;
+ unsigned long freq_core_max = 0;
struct msm_vidc_inst *temp = NULL;
int rc = 0, i = 0;
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
@@ -568,14 +569,33 @@
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
- freq += temp->clk_data.curr_freq;
+
+ if (temp->clk_data.core_id == VIDC_CORE_ID_1)
+ freq_core_1 += temp->clk_data.min_freq;
+ else if (temp->clk_data.core_id == VIDC_CORE_ID_2)
+ freq_core_2 += temp->clk_data.min_freq;
+ else if (temp->clk_data.core_id == VIDC_CORE_ID_3) {
+ freq_core_1 += temp->clk_data.min_freq / 2;
+ freq_core_2 += temp->clk_data.min_freq / 2;
+ }
+
+ freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2);
+
+ if (temp->clk_data.turbo_mode) {
+ dprintk(VIDC_PROF,
+ "Found an instance with Turbo request\n");
+ freq_core_max = msm_vidc_max_freq(core);
+ break;
+ }
}
+
for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
rate = allowed_clks_tbl[i].clock_rate;
- if (rate >= freq)
+ if (rate >= freq_core_max)
break;
}
- core->min_freq = freq;
+
+ core->min_freq = freq_core_max;
core->curr_freq = rate;
mutex_unlock(&core->lock);
@@ -587,19 +607,22 @@
return rc;
}
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+ u32 operating_rate)
{
- struct v4l2_ctrl *ctrl = NULL;
struct msm_vidc_inst *temp;
struct msm_vidc_core *core;
unsigned long max_freq, freq_left, ops_left, load, cycles, freq = 0;
unsigned long mbs_per_second;
+ int rc = 0;
+ u32 curr_operating_rate = 0;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
return -EINVAL;
}
core = inst->core;
+ curr_operating_rate = inst->clk_data.operating_rate >> 16;
mutex_lock(&core->lock);
max_freq = msm_vidc_max_freq(core);
@@ -614,51 +637,35 @@
freq_left = max_freq - freq;
- list_for_each_entry(temp, &core->instances, list) {
-
- if (!temp ||
- temp->state < MSM_VIDC_START_DONE ||
- temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
- continue;
-
- mbs_per_second = msm_comm_get_inst_load_per_core(temp,
+ mbs_per_second = msm_comm_get_inst_load_per_core(inst,
LOAD_CALC_NO_QUIRKS);
- cycles = temp->clk_data.entry->vpp_cycles;
- if (temp->session_type == MSM_VIDC_ENCODER)
- cycles = temp->flags & VIDC_LOW_POWER ?
- temp->clk_data.entry->low_power_cycles :
- cycles;
+ cycles = inst->clk_data.entry->vpp_cycles;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ cycles = inst->flags & VIDC_LOW_POWER ?
+ inst->clk_data.entry->low_power_cycles :
+ cycles;
- load = cycles * mbs_per_second;
+ load = cycles * mbs_per_second;
- ops_left = load ? (freq_left / load) : 0;
- /* Convert remaining operating rate to Q16 format */
- ops_left = ops_left << 16;
+ ops_left = load ? (freq_left / load) : 0;
- ctrl = v4l2_ctrl_find(&temp->ctrl_handler,
- V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE);
- if (ctrl) {
- dprintk(VIDC_DBG,
- "%s: Before Range = %lld --> %lld\n",
- ctrl->name, ctrl->minimum, ctrl->maximum);
- dprintk(VIDC_DBG,
- "%s: Before Def value = %lld Cur val = %d\n",
- ctrl->name, ctrl->default_value, ctrl->val);
- v4l2_ctrl_modify_range(ctrl, ctrl->minimum,
- ctrl->val + ops_left, ctrl->step,
- ctrl->default_value);
- dprintk(VIDC_DBG,
- "%s: Updated Range = %lld --> %lld\n",
- ctrl->name, ctrl->minimum, ctrl->maximum);
- dprintk(VIDC_DBG,
- "%s: Updated Def value = %lld Cur val = %d\n",
- ctrl->name, ctrl->default_value, ctrl->val);
- }
+ operating_rate = operating_rate >> 16;
+
+ if ((curr_operating_rate + ops_left) >= operating_rate) {
+ dprintk(VIDC_DBG,
+ "Requestd operating rate is valid %u\n",
+ operating_rate);
+ rc = 0;
+ } else {
+ dprintk(VIDC_DBG,
+ "Current load is high for requested settings. Cannot set operating rate to %u\n",
+ operating_rate);
+ rc = -EINVAL;
}
mutex_unlock(&core->lock);
- return 0;
+ return rc;
}
int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
@@ -980,8 +987,8 @@
return 0;
}
mbs_per_frame = msm_vidc_get_mbs_per_frame(inst);
- if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
- inst->prop.fps >= inst->core->resources.max_hq_fps) {
+ if (mbs_per_frame > inst->core->resources.max_hq_mbs_per_frame ||
+ inst->prop.fps > inst->core->resources.max_hq_fps) {
enable = true;
}
@@ -1025,17 +1032,21 @@
}
static u32 get_core_load(struct msm_vidc_core *core,
- u32 core_id, bool lp_mode)
+ u32 core_id, bool lp_mode, bool real_time)
{
struct msm_vidc_inst *inst = NULL;
u32 current_inst_mbs_per_sec = 0, load = 0;
+ bool real_time_mode = false;
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
u32 cycles, lp_cycles;
+ real_time_mode = inst->flags & VIDC_REALTIME ? true : false;
if (!(inst->clk_data.core_id & core_id))
continue;
+ if (real_time_mode != real_time)
+ continue;
if (inst->session_type == MSM_VIDC_DECODER) {
cycles = lp_cycles = inst->clk_data.entry->vpp_cycles;
} else if (inst->session_type == MSM_VIDC_ENCODER) {
@@ -1080,10 +1091,10 @@
max_freq = msm_vidc_max_freq(inst->core);
inst->clk_data.core_id = 0;
- core0_load = get_core_load(core, VIDC_CORE_ID_1, false);
- core1_load = get_core_load(core, VIDC_CORE_ID_2, false);
- core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true);
- core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true);
+ core0_load = get_core_load(core, VIDC_CORE_ID_1, false, true);
+ core1_load = get_core_load(core, VIDC_CORE_ID_2, false, true);
+ core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true, true);
+ core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true, true);
min_load = min(core0_load, core1_load);
min_core_id = core0_load < core1_load ?
@@ -1102,9 +1113,9 @@
current_inst_lp_load = msm_comm_get_inst_load(inst,
LOAD_CALC_NO_QUIRKS) * lp_cycles;
- dprintk(VIDC_DBG, "Core 0 Load = %d Core 1 Load = %d\n",
+ dprintk(VIDC_DBG, "Core 0 RT Load = %d Core 1 RT Load = %d\n",
core0_load, core1_load);
- dprintk(VIDC_DBG, "Core 0 LP Load = %d Core 1 LP Load = %d\n",
+ dprintk(VIDC_DBG, "Core 0 RT LP Load = %d Core 1 RT LP Load = %d\n",
core0_lp_load, core1_lp_load);
dprintk(VIDC_DBG, "Max Load = %lu\n", max_freq);
dprintk(VIDC_DBG, "Current Load = %d Current LP Load = %d\n",
@@ -1184,7 +1195,38 @@
rc = msm_comm_scale_clocks_and_bus(inst);
+ msm_print_core_status(core, VIDC_CORE_ID_1);
+ msm_print_core_status(core, VIDC_CORE_ID_2);
+
return rc;
}
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id)
+{
+ struct msm_vidc_inst *inst = NULL;
+ dprintk(VIDC_PROF, "Instances running on core %u", core_id);
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+
+ if ((inst->clk_data.core_id != core_id) &&
+ (inst->clk_data.core_id != VIDC_CORE_ID_3))
+ continue;
+
+ dprintk(VIDC_PROF,
+ "inst %pK (%4ux%4u) to (%4ux%4u) %3u %s %s %s %s %lu\n",
+ inst,
+ inst->prop.width[OUTPUT_PORT],
+ inst->prop.height[OUTPUT_PORT],
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ inst->prop.fps,
+ inst->session_type == MSM_VIDC_ENCODER ? "ENC" : "DEC",
+ inst->clk_data.work_mode == VIDC_WORK_MODE_1 ?
+ "WORK_MODE_1" : "WORK_MODE_2",
+ inst->flags & VIDC_LOW_POWER ? "LP" : "HQ",
+ inst->flags & VIDC_REALTIME ? "RealTime" : "NonRTime",
+ inst->clk_data.min_freq);
+ }
+ mutex_unlock(&core->lock);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 707f034..142d63f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -22,7 +22,8 @@
#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
void msm_clock_data_reset(struct msm_vidc_inst *inst);
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+ u32 operating_rate);
int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type);
int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
@@ -31,6 +32,7 @@
void msm_comm_free_freq_table(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst);
int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
u32 device_addr);
void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index f841eb8..2beb90c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -560,6 +560,19 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP:
+ switch (value) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE:
+ return HAL_FLIP_NONE;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI:
+ return HAL_FLIP_HORIZONTAL;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT:
+ return HAL_FLIP_VERTICAL;
+ case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH:
+ return HAL_FLIP_BOTH;
+ default:
+ goto unknown_value;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
switch (value) {
case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
@@ -1437,6 +1450,9 @@
V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
&inst->capability.bframe);
}
+ msm_vidc_comm_update_ctrl(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ &inst->capability.frame_rate);
}
static void handle_session_init_done(enum hal_command_response cmd, void *data)
@@ -2180,7 +2196,8 @@
"%s: Send sys error for inst %pK\n", __func__, inst);
change_inst_state(inst, MSM_VIDC_CORE_INVALID);
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- msm_comm_print_inst_info(inst);
+ if (!core->trigger_ssr)
+ msm_comm_print_inst_info(inst);
}
dprintk(VIDC_DBG, "Calling core_release\n");
rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
@@ -2272,6 +2289,8 @@
mutex_lock(&inst->bufq[port].lock);
found = false;
list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->state != VB2_BUF_STATE_ACTIVE)
+ continue;
if (msm_comm_compare_vb2_planes(inst, mbuf, vb)) {
found = true;
break;
@@ -5306,8 +5325,7 @@
LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
if (inst->state == MSM_VIDC_OPEN_DONE) {
- max_load_adj = inst->core->resources.max_load +
- inst->capability.mbs_per_frame.max;
+ max_load_adj = inst->core->resources.max_load;
num_mbs_per_sec = msm_comm_get_load(inst->core,
MSM_VIDC_DECODER, quirks);
num_mbs_per_sec += msm_comm_get_load(inst->core,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index a0f7d2e..37645fe 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -195,12 +195,33 @@
int low_power_cycles;
};
+enum efuse_purpose {
+ SKU_VERSION = 0,
+};
+
+enum sku_version {
+ SKU_VERSION_0 = 0,
+ SKU_VERSION_1,
+ SKU_VERSION_2,
+};
+
+struct msm_vidc_efuse_data {
+ u32 start_address;
+ u32 size;
+ u32 mask;
+ u32 shift;
+ enum efuse_purpose purpose;
+};
+
struct msm_vidc_platform_data {
struct msm_vidc_common_data *common_data;
unsigned int common_data_length;
struct msm_vidc_codec_data *codec_data;
unsigned int codec_data_length;
struct msm_vidc_csc_coeff csc_data;
+ struct msm_vidc_efuse_data *efuse_data;
+ unsigned int efuse_data_length;
+ unsigned int sku_version;
};
struct msm_vidc_format {
@@ -218,7 +239,7 @@
int num_cores;
struct dentry *debugfs_root;
int thermal_level;
- u32 platform_version;
+ u32 sku_version;
};
struct msm_video_device {
@@ -286,6 +307,7 @@
u32 opb_fourcc;
enum hal_work_mode work_mode;
bool low_latency_mode;
+ bool turbo_mode;
};
struct profile_data {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 0fe09e2..a82b598 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -24,6 +24,7 @@
#include <linux/version.h>
#include <linux/io.h>
#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
#define CODEC_ENTRY(n, p, vsp, vpp, lp) \
@@ -35,6 +36,15 @@
.low_power_cycles = lp \
}
+#define EFUSE_ENTRY(sa, s, m, sh, p) \
+{ \
+ .start_address = sa, \
+ .size = s, \
+ .mask = m, \
+ .shift = sh, \
+ .purpose = p \
+}
+
static struct msm_vidc_codec_data default_codec_data[] = {
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 125, 675, 320),
@@ -44,7 +54,18 @@
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
- CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540),
+ CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200),
+};
+
+static struct msm_vidc_codec_data sdm670_codec_data[] = {
+ CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
+ CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
@@ -98,7 +119,7 @@
},
{
.key = "qcom,max-hw-load",
- .value = 2563200,
+ .value = 3110400, /* 4096x2160@90 */
},
{
.key = "qcom,max-hq-mbs-per-frame",
@@ -130,6 +151,95 @@
},
};
+static struct msm_vidc_common_data sdm670_common_data_v0[] = {
+ {
+ .key = "qcom,never-unload-fw",
+ .value = 1,
+ },
+ {
+ .key = "qcom,sw-power-collapse",
+ .value = 1,
+ },
+ {
+ .key = "qcom,max-secure-instances",
+ .value = 5,
+ },
+ {
+ .key = "qcom,max-hw-load",
+ .value = 1944000,
+ },
+ {
+ .key = "qcom,max-hq-mbs-per-frame",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-hq-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,max-b-frame-size",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-b-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,power-collapse-delay",
+ .value = 500,
+ },
+ {
+ .key = "qcom,hw-resp-timeout",
+ .value = 250,
+ },
+};
+
+static struct msm_vidc_common_data sdm670_common_data_v1[] = {
+ {
+ .key = "qcom,never-unload-fw",
+ .value = 1,
+ },
+ {
+ .key = "qcom,sw-power-collapse",
+ .value = 1,
+ },
+ {
+ .key = "qcom,max-secure-instances",
+ .value = 5,
+ },
+ {
+ .key = "qcom,max-hw-load",
+ .value = 1216800,
+ },
+ {
+ .key = "qcom,max-hq-mbs-per-frame",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-hq-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,max-b-frame-size",
+ .value = 8160,
+ },
+ {
+ .key = "qcom,max-b-frames-per-sec",
+ .value = 60,
+ },
+ {
+ .key = "qcom,power-collapse-delay",
+ .value = 500,
+ },
+ {
+ .key = "qcom,hw-resp-timeout",
+ .value = 250,
+ },
+};
+
+static struct msm_vidc_efuse_data sdm670_efuse_data[] = {
+ EFUSE_ENTRY(0x007801A0, 4, 0x00008000, 0x0f, SKU_VERSION),
+};
static struct msm_vidc_platform_data default_data = {
.codec_data = default_codec_data,
@@ -139,6 +249,9 @@
.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = NULL,
+ .efuse_data_length = 0,
+ .sku_version = 0,
};
static struct msm_vidc_platform_data sdm845_data = {
@@ -149,6 +262,22 @@
.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = NULL,
+ .efuse_data_length = 0,
+ .sku_version = 0,
+};
+
+static struct msm_vidc_platform_data sdm670_data = {
+ .codec_data = sdm670_codec_data,
+ .codec_data_length = ARRAY_SIZE(sdm670_codec_data),
+ .common_data = sdm670_common_data_v0,
+ .common_data_length = ARRAY_SIZE(sdm670_common_data_v0),
+ .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+ .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+ .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
+ .efuse_data = sdm670_efuse_data,
+ .efuse_data_length = ARRAY_SIZE(sdm670_efuse_data),
+ .sku_version = 0,
};
static const struct of_device_id msm_vidc_dt_match[] = {
@@ -156,15 +285,62 @@
.compatible = "qcom,sdm845-vidc",
.data = &sdm845_data,
},
- {},
+ {
+ .compatible = "qcom,sdm670-vidc",
+ .data = &sdm670_data,
+ },
};
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+static int msm_vidc_read_efuse(
+ struct msm_vidc_platform_data *data, struct device *dev)
+{
+ void __iomem *base;
+ uint32_t i;
+ struct msm_vidc_efuse_data *efuse_data = data->efuse_data;
+ uint32_t efuse_data_count = data->efuse_data_length;
+
+ for (i = 0; i < efuse_data_count; i++) {
+
+ switch ((efuse_data[i]).purpose) {
+
+ case SKU_VERSION:
+ base = devm_ioremap(dev, (efuse_data[i]).start_address,
+ (efuse_data[i]).size);
+ if (!base) {
+ dprintk(VIDC_ERR,
+ "failed efuse ioremap: res->start %#x, size %d\n",
+ (efuse_data[i]).start_address,
+ (efuse_data[i]).size);
+ return -EINVAL;
+ } else {
+ u32 efuse = 0;
+
+ efuse = readl_relaxed(base);
+ data->sku_version =
+ (efuse & (efuse_data[i]).mask) >>
+ (efuse_data[i]).shift;
+ dprintk(VIDC_DBG,
+ "efuse 0x%x, platform version 0x%x\n",
+ efuse, data->sku_version);
+
+ devm_iounmap(dev, base);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
void *vidc_get_drv_data(struct device *dev)
{
struct msm_vidc_platform_data *driver_data = NULL;
const struct of_device_id *match;
+ int rc = 0;
if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) {
driver_data = &default_data;
@@ -176,6 +352,21 @@
if (match)
driver_data = (struct msm_vidc_platform_data *)match->data;
+ if (!of_find_property(dev->of_node, "sku-index", NULL) ||
+ !driver_data) {
+ goto exit;
+ } else if (!strcmp(match->compatible, "qcom,sdm670-vidc")) {
+ rc = msm_vidc_read_efuse(driver_data, dev);
+ if (rc)
+ goto exit;
+
+ if (driver_data->sku_version == SKU_VERSION_1) {
+ driver_data->common_data = sdm670_common_data_v1;
+ driver_data->common_data_length =
+ ARRAY_SIZE(sdm670_common_data_v1);
+ }
+ }
+
exit:
return driver_data;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index f343939..a0214a2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -73,12 +73,6 @@
res->clock_freq_tbl.clk_prof_entries = NULL;
}
-static inline void msm_vidc_free_platform_version_table(
- struct msm_vidc_platform_resources *res)
-{
- res->pf_ver_tbl = NULL;
-}
-
static inline void msm_vidc_free_reg_table(
struct msm_vidc_platform_resources *res)
{
@@ -133,7 +127,6 @@
{
msm_vidc_free_clock_table(res);
msm_vidc_free_regulator_table(res);
- msm_vidc_free_platform_version_table(res);
msm_vidc_free_allowed_clocks_table(res);
msm_vidc_free_reg_table(res);
msm_vidc_free_qdss_addr_table(res);
@@ -344,33 +337,6 @@
}
EXPORT_SYMBOL(msm_vidc_load_u32_table);
-static int msm_vidc_load_platform_version_table(
- struct msm_vidc_platform_resources *res)
-{
- int rc = 0;
- struct platform_device *pdev = res->pdev;
-
- if (!of_find_property(pdev->dev.of_node,
- "qcom,platform-version", NULL)) {
- dprintk(VIDC_DBG, "qcom,platform-version not found\n");
- return 0;
- }
-
- rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
- "qcom,platform-version",
- sizeof(*res->pf_ver_tbl),
- (u32 **)&res->pf_ver_tbl,
- NULL);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s: failed to read platform version table\n",
- __func__);
- return rc;
- }
-
- return 0;
-}
-
/* A comparator to compare loads (needed later on) */
static int cmp(const void *a, const void *b)
{
@@ -712,6 +678,29 @@
return rc;
}
+static int msm_decide_dt_node(
+ struct msm_vidc_platform_resources *res) {
+ struct platform_device *pdev = res->pdev;
+ int rc = 0;
+ u32 sku_index = 0;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "sku-index",
+ &sku_index);
+ if (rc) {
+ dprintk(VIDC_DBG, "'sku_index' not found in node\n");
+ return 0;
+ }
+
+ if (sku_index != res->sku_version) {
+ dprintk(VIDC_DBG,
+ "Failed to parser dt: sku_index %d res->sku_version - %d\n",
+ sku_index, res->sku_version);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int find_key_value(struct msm_vidc_platform_data *platform_data,
const char *key)
{
@@ -743,6 +732,8 @@
res->codec_data_count = platform_data->codec_data_length;
res->codec_data = platform_data->codec_data;
+ res->sku_version = platform_data->sku_version;
+
res->fw_name = "venus";
dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
@@ -805,6 +796,11 @@
return -ENOENT;
}
+ rc = msm_decide_dt_node(res);
+ if (rc)
+ return rc;
+
+
INIT_LIST_HEAD(&res->context_banks);
res->firmware_base = (phys_addr_t)firmware_base;
@@ -816,10 +812,6 @@
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res->irq = kres ? kres->start : -1;
- rc = msm_vidc_load_platform_version_table(res);
- if (rc)
- dprintk(VIDC_ERR, "Failed to load pf version table: %d\n", rc);
-
rc = msm_vidc_load_subcache_info(res);
if (rc)
dprintk(VIDC_WARN, "Failed to load subcache info: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8309fce..99b4e30 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -21,11 +21,6 @@
#define MAX_BUFFER_TYPES 32
-struct platform_version_table {
- u32 version_mask;
- u32 version_shift;
-};
-
struct dcvs_table {
u32 load;
u32 load_low;
@@ -153,7 +148,7 @@
phys_addr_t register_base;
uint32_t register_size;
uint32_t irq;
- struct platform_version_table *pf_ver_tbl;
+ uint32_t sku_version;
struct allowed_clock_rates_table *allowed_clks_tbl;
u32 allowed_clks_tbl_size;
struct clock_freq_table clock_freq_tbl;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 738828d..53df90f5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -660,6 +660,7 @@
HAL_FLIP_NONE,
HAL_FLIP_HORIZONTAL,
HAL_FLIP_VERTICAL,
+ HAL_FLIP_BOTH,
HAL_UNUSED_FLIP = 0x10000000,
};
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index c3277308..b49f80c 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -254,7 +254,7 @@
return 0;
case LIRC_GET_REC_RESOLUTION:
- val = dev->rx_resolution;
+ val = dev->rx_resolution / 1000;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cada3c1..e3f4c39 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -791,6 +791,13 @@
Per UID based io statistics exported to /proc/uid_io
Per UID based procstat control in /proc/uid_procstat
+config UID_SYS_STATS_DEBUG
+ bool "Per-TASK statistics"
+ depends on UID_SYS_STATS
+ default n
+ help
+ Per TASK based io statistics exported to /proc/uid_io
+
config MEMORY_STATE_TIME
tristate "Memory freq/bandwidth time statistics"
depends on PROFILING
diff --git a/drivers/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c
index 3c11de0..690b28b 100644
--- a/drivers/misc/qpnp-misc.c
+++ b/drivers/misc/qpnp-misc.c
@@ -135,7 +135,7 @@
struct qpnp_misc_dev *mdev = NULL;
struct qpnp_misc_dev *mdev_found = NULL;
int rc;
- u8 temp;
+ u8 temp = 0;
if (IS_ERR_OR_NULL(node)) {
pr_err("Invalid device node pointer\n");
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 8bf4c57..7d69dd5 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/profile.h>
#include <linux/rtmutex.h>
@@ -53,6 +54,15 @@
#define UID_STATE_DEAD_TASKS 4
#define UID_STATE_SIZE 5
+#define MAX_TASK_COMM_LEN 256
+
+struct task_entry {
+ char comm[MAX_TASK_COMM_LEN];
+ pid_t pid;
+ struct io_stats io[UID_STATE_SIZE];
+ struct hlist_node hash;
+};
+
struct uid_entry {
uid_t uid;
cputime_t utime;
@@ -62,8 +72,231 @@
int state;
struct io_stats io[UID_STATE_SIZE];
struct hlist_node hash;
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+ DECLARE_HASHTABLE(task_entries, UID_HASH_BITS);
+#endif
};
+static u64 compute_write_bytes(struct task_struct *task)
+{
+ if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
+ return 0;
+
+ return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
+}
+
+static void compute_io_bucket_stats(struct io_stats *io_bucket,
+ struct io_stats *io_curr,
+ struct io_stats *io_last,
+ struct io_stats *io_dead)
+{
+ /* tasks could switch to another uid group, but its io_last in the
+ * previous uid group could still be positive.
+ * therefore before each update, do an overflow check first
+ */
+ int64_t delta;
+
+ delta = io_curr->read_bytes + io_dead->read_bytes -
+ io_last->read_bytes;
+ io_bucket->read_bytes += delta > 0 ? delta : 0;
+ delta = io_curr->write_bytes + io_dead->write_bytes -
+ io_last->write_bytes;
+ io_bucket->write_bytes += delta > 0 ? delta : 0;
+ delta = io_curr->rchar + io_dead->rchar - io_last->rchar;
+ io_bucket->rchar += delta > 0 ? delta : 0;
+ delta = io_curr->wchar + io_dead->wchar - io_last->wchar;
+ io_bucket->wchar += delta > 0 ? delta : 0;
+ delta = io_curr->fsync + io_dead->fsync - io_last->fsync;
+ io_bucket->fsync += delta > 0 ? delta : 0;
+
+ io_last->read_bytes = io_curr->read_bytes;
+ io_last->write_bytes = io_curr->write_bytes;
+ io_last->rchar = io_curr->rchar;
+ io_last->wchar = io_curr->wchar;
+ io_last->fsync = io_curr->fsync;
+
+ memset(io_dead, 0, sizeof(struct io_stats));
+}
+
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+static void get_full_task_comm(struct task_entry *task_entry,
+ struct task_struct *task)
+{
+ int i = 0, offset = 0, len = 0;
+ /* save one byte for terminating null character */
+ int unused_len = MAX_TASK_COMM_LEN - TASK_COMM_LEN - 1;
+ char buf[unused_len];
+ struct mm_struct *mm = task->mm;
+
+ /* fill the first TASK_COMM_LEN bytes with thread name */
+ get_task_comm(task_entry->comm, task);
+ i = strlen(task_entry->comm);
+ while (i < TASK_COMM_LEN)
+ task_entry->comm[i++] = ' ';
+
+ /* next the executable file name */
+ if (mm) {
+ down_read(&mm->mmap_sem);
+ if (mm->exe_file) {
+ char *pathname = d_path(&mm->exe_file->f_path, buf,
+ unused_len);
+
+ if (!IS_ERR(pathname)) {
+ len = strlcpy(task_entry->comm + i, pathname,
+ unused_len);
+ i += len;
+ task_entry->comm[i++] = ' ';
+ unused_len--;
+ }
+ }
+ up_read(&mm->mmap_sem);
+ }
+ unused_len -= len;
+
+ /* fill the rest with command line argument
+ * replace each null or new line character
+ * between args in argv with whitespace */
+ len = get_cmdline(task, buf, unused_len);
+ while (offset < len) {
+ if (buf[offset] != '\0' && buf[offset] != '\n')
+ task_entry->comm[i++] = buf[offset];
+ else
+ task_entry->comm[i++] = ' ';
+ offset++;
+ }
+
+ /* get rid of trailing whitespaces in case when arg is memset to
+ * zero before being reset in userspace
+ */
+ while (task_entry->comm[i-1] == ' ')
+ i--;
+ task_entry->comm[i] = '\0';
+}
+
+static struct task_entry *find_task_entry(struct uid_entry *uid_entry,
+ struct task_struct *task)
+{
+ struct task_entry *task_entry;
+
+ hash_for_each_possible(uid_entry->task_entries, task_entry, hash,
+ task->pid) {
+ if (task->pid == task_entry->pid) {
+ /* if thread name changed, update the entire command */
+ int len = strnchr(task_entry->comm, ' ', TASK_COMM_LEN)
+ - task_entry->comm;
+
+ if (strncmp(task_entry->comm, task->comm, len))
+ get_full_task_comm(task_entry, task);
+ return task_entry;
+ }
+ }
+ return NULL;
+}
+
+static struct task_entry *find_or_register_task(struct uid_entry *uid_entry,
+ struct task_struct *task)
+{
+ struct task_entry *task_entry;
+ pid_t pid = task->pid;
+
+ task_entry = find_task_entry(uid_entry, task);
+ if (task_entry)
+ return task_entry;
+
+ task_entry = kzalloc(sizeof(struct task_entry), GFP_ATOMIC);
+ if (!task_entry)
+ return NULL;
+
+ get_full_task_comm(task_entry, task);
+
+ task_entry->pid = pid;
+ hash_add(uid_entry->task_entries, &task_entry->hash, (unsigned int)pid);
+
+ return task_entry;
+}
+
+static void remove_uid_tasks(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+ struct hlist_node *tmp_task;
+
+ hash_for_each_safe(uid_entry->task_entries, bkt_task,
+ tmp_task, task_entry, hash) {
+ hash_del(&task_entry->hash);
+ kfree(task_entry);
+ }
+}
+
+static void set_io_uid_tasks_zero(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ memset(&task_entry->io[UID_STATE_TOTAL_CURR], 0,
+ sizeof(struct io_stats));
+ }
+}
+
+static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
+ struct task_struct *task, int slot)
+{
+ struct task_entry *task_entry = find_or_register_task(uid_entry, task);
+ struct io_stats *task_io_slot = &task_entry->io[slot];
+
+ task_io_slot->read_bytes += task->ioac.read_bytes;
+ task_io_slot->write_bytes += compute_write_bytes(task);
+ task_io_slot->rchar += task->ioac.rchar;
+ task_io_slot->wchar += task->ioac.wchar;
+ task_io_slot->fsync += task->ioac.syscfs;
+}
+
+static void compute_io_uid_tasks(struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ compute_io_bucket_stats(&task_entry->io[uid_entry->state],
+ &task_entry->io[UID_STATE_TOTAL_CURR],
+ &task_entry->io[UID_STATE_TOTAL_LAST],
+ &task_entry->io[UID_STATE_DEAD_TASKS]);
+ }
+}
+
+static void show_io_uid_tasks(struct seq_file *m, struct uid_entry *uid_entry)
+{
+ struct task_entry *task_entry;
+ unsigned long bkt_task;
+
+ hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
+ /* Separated by comma because space exists in task comm */
+ seq_printf(m, "task,%s,%lu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
+ task_entry->comm,
+ (unsigned long)task_entry->pid,
+ task_entry->io[UID_STATE_FOREGROUND].rchar,
+ task_entry->io[UID_STATE_FOREGROUND].wchar,
+ task_entry->io[UID_STATE_FOREGROUND].read_bytes,
+ task_entry->io[UID_STATE_FOREGROUND].write_bytes,
+ task_entry->io[UID_STATE_BACKGROUND].rchar,
+ task_entry->io[UID_STATE_BACKGROUND].wchar,
+ task_entry->io[UID_STATE_BACKGROUND].read_bytes,
+ task_entry->io[UID_STATE_BACKGROUND].write_bytes,
+ task_entry->io[UID_STATE_FOREGROUND].fsync,
+ task_entry->io[UID_STATE_BACKGROUND].fsync);
+ }
+}
+#else
+static void remove_uid_tasks(struct uid_entry *uid_entry) {};
+static void set_io_uid_tasks_zero(struct uid_entry *uid_entry) {};
+static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
+ struct task_struct *task, int slot) {};
+static void compute_io_uid_tasks(struct uid_entry *uid_entry) {};
+static void show_io_uid_tasks(struct seq_file *m,
+ struct uid_entry *uid_entry) {}
+#endif
+
static struct uid_entry *find_uid_entry(uid_t uid)
{
struct uid_entry *uid_entry;
@@ -87,7 +320,9 @@
return NULL;
uid_entry->uid = uid;
-
+#ifdef CONFIG_UID_SYS_STATS_DEBUG
+ hash_init(uid_entry->task_entries);
+#endif
hash_add(hash_table, &uid_entry->hash, uid);
return uid_entry;
@@ -193,6 +428,7 @@
hash_for_each_possible_safe(hash_table, uid_entry, tmp,
hash, (uid_t)uid_start) {
if (uid_start == uid_entry->uid) {
+ remove_uid_tasks(uid_entry);
hash_del(&uid_entry->hash);
kfree(uid_entry);
}
@@ -209,13 +445,6 @@
.write = uid_remove_write,
};
-static u64 compute_write_bytes(struct task_struct *task)
-{
- if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
- return 0;
-
- return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
-}
static void add_uid_io_stats(struct uid_entry *uid_entry,
struct task_struct *task, int slot)
@@ -227,28 +456,8 @@
io_slot->rchar += task->ioac.rchar;
io_slot->wchar += task->ioac.wchar;
io_slot->fsync += task->ioac.syscfs;
-}
-static void compute_uid_io_bucket_stats(struct io_stats *io_bucket,
- struct io_stats *io_curr,
- struct io_stats *io_last,
- struct io_stats *io_dead)
-{
- io_bucket->read_bytes += io_curr->read_bytes + io_dead->read_bytes -
- io_last->read_bytes;
- io_bucket->write_bytes += io_curr->write_bytes + io_dead->write_bytes -
- io_last->write_bytes;
- io_bucket->rchar += io_curr->rchar + io_dead->rchar - io_last->rchar;
- io_bucket->wchar += io_curr->wchar + io_dead->wchar - io_last->wchar;
- io_bucket->fsync += io_curr->fsync + io_dead->fsync - io_last->fsync;
-
- io_last->read_bytes = io_curr->read_bytes;
- io_last->write_bytes = io_curr->write_bytes;
- io_last->rchar = io_curr->rchar;
- io_last->wchar = io_curr->wchar;
- io_last->fsync = io_curr->fsync;
-
- memset(io_dead, 0, sizeof(struct io_stats));
+ add_uid_tasks_io_stats(uid_entry, task, slot);
}
static void update_io_stats_all_locked(void)
@@ -259,9 +468,11 @@
unsigned long bkt;
uid_t uid;
- hash_for_each(hash_table, bkt, uid_entry, hash)
+ hash_for_each(hash_table, bkt, uid_entry, hash) {
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
sizeof(struct io_stats));
+ set_io_uid_tasks_zero(uid_entry);
+ }
rcu_read_lock();
do_each_thread(temp, task) {
@@ -275,10 +486,11 @@
rcu_read_unlock();
hash_for_each(hash_table, bkt, uid_entry, hash) {
- compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
+ compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
&uid_entry->io[UID_STATE_TOTAL_CURR],
&uid_entry->io[UID_STATE_TOTAL_LAST],
&uid_entry->io[UID_STATE_DEAD_TASKS]);
+ compute_io_uid_tasks(uid_entry);
}
}
@@ -289,6 +501,7 @@
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
sizeof(struct io_stats));
+ set_io_uid_tasks_zero(uid_entry);
rcu_read_lock();
do_each_thread(temp, task) {
@@ -298,12 +511,14 @@
} while_each_thread(temp, task);
rcu_read_unlock();
- compute_uid_io_bucket_stats(&uid_entry->io[uid_entry->state],
+ compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
&uid_entry->io[UID_STATE_TOTAL_CURR],
&uid_entry->io[UID_STATE_TOTAL_LAST],
&uid_entry->io[UID_STATE_DEAD_TASKS]);
+ compute_io_uid_tasks(uid_entry);
}
+
static int uid_io_show(struct seq_file *m, void *v)
{
struct uid_entry *uid_entry;
@@ -315,21 +530,22 @@
hash_for_each(hash_table, bkt, uid_entry, hash) {
seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
- uid_entry->uid,
- uid_entry->io[UID_STATE_FOREGROUND].rchar,
- uid_entry->io[UID_STATE_FOREGROUND].wchar,
- uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
- uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
- uid_entry->io[UID_STATE_BACKGROUND].rchar,
- uid_entry->io[UID_STATE_BACKGROUND].wchar,
- uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
- uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
- uid_entry->io[UID_STATE_FOREGROUND].fsync,
- uid_entry->io[UID_STATE_BACKGROUND].fsync);
+ uid_entry->uid,
+ uid_entry->io[UID_STATE_FOREGROUND].rchar,
+ uid_entry->io[UID_STATE_FOREGROUND].wchar,
+ uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
+ uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
+ uid_entry->io[UID_STATE_BACKGROUND].rchar,
+ uid_entry->io[UID_STATE_BACKGROUND].wchar,
+ uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
+ uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
+ uid_entry->io[UID_STATE_FOREGROUND].fsync,
+ uid_entry->io[UID_STATE_BACKGROUND].fsync);
+
+ show_io_uid_tasks(m, uid_entry);
}
rt_mutex_unlock(&uid_lock);
-
return 0;
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index a531cb4..a378b8c 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -403,6 +403,7 @@
return ret;
mmc_card_set_present(card);
+ device_enable_async_suspend(&card->dev);
return 0;
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 978dd9a..727b301 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3407,6 +3407,13 @@
pm_wakeup_event(mmc_dev(host), 5000);
host->detect_change = 1;
+ /*
+ * Change in cd_gpio state, so make sure detection part is
+ * not overided because of manual resume.
+ */
+ if (cd_irq && mmc_bus_manual_resume(host))
+ host->ignore_bus_resume_flags = true;
+
mmc_schedule_delayed_work(&host->detect, delay);
}
@@ -4387,6 +4394,8 @@
host->bus_ops->detect(host);
host->detect_change = 0;
+ if (host->ignore_bus_resume_flags)
+ host->ignore_bus_resume_flags = false;
/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
@@ -4643,7 +4652,8 @@
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
- if (mmc_bus_manual_resume(host)) {
+ if (mmc_bus_manual_resume(host) &&
+ !host->ignore_bus_resume_flags) {
spin_unlock_irqrestore(&host->lock, flags);
break;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 127ab0f..64c8743 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -482,19 +482,17 @@
*/
int mmc_of_parse(struct mmc_host *host)
{
- struct device_node *np;
+ struct device *dev = host->parent;
u32 bus_width;
int ret;
bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false;
- if (!host->parent || !host->parent->of_node)
+ if (!dev || !dev_fwnode(dev))
return 0;
- np = host->parent->of_node;
-
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
- if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
+ if (device_property_read_u32(dev, "bus-width", &bus_width) < 0) {
dev_dbg(host->parent,
"\"bus-width\" property is missing, assuming 1 bit.\n");
bus_width = 1;
@@ -516,7 +514,7 @@
}
/* f_max is obtained from the optional "max-frequency" property */
- of_property_read_u32(np, "max-frequency", &host->f_max);
+ device_property_read_u32(dev, "max-frequency", &host->f_max);
/*
* Configure CD and WP pins. They are both by default active low to
@@ -531,12 +529,12 @@
*/
/* Parse Card Detection */
- if (of_property_read_bool(np, "non-removable")) {
+ if (device_property_read_bool(dev, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else {
- cd_cap_invert = of_property_read_bool(np, "cd-inverted");
+ cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
- if (of_property_read_bool(np, "broken-cd"))
+ if (device_property_read_bool(dev, "broken-cd"))
host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
@@ -562,7 +560,7 @@
}
/* Parse Write Protection */
- ro_cap_invert = of_property_read_bool(np, "wp-inverted");
+ ro_cap_invert = device_property_read_bool(dev, "wp-inverted");
ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
if (!ret)
@@ -570,62 +568,62 @@
else if (ret != -ENOENT && ret != -ENOSYS)
return ret;
- if (of_property_read_bool(np, "disable-wp"))
+ if (device_property_read_bool(dev, "disable-wp"))
host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
/* See the comment on CD inversion above */
if (ro_cap_invert ^ ro_gpio_invert)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
- if (of_property_read_bool(np, "cap-sd-highspeed"))
+ if (device_property_read_bool(dev, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED;
- if (of_property_read_bool(np, "cap-mmc-highspeed"))
+ if (device_property_read_bool(dev, "cap-mmc-highspeed"))
host->caps |= MMC_CAP_MMC_HIGHSPEED;
- if (of_property_read_bool(np, "sd-uhs-sdr12"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr12"))
host->caps |= MMC_CAP_UHS_SDR12;
- if (of_property_read_bool(np, "sd-uhs-sdr25"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr25"))
host->caps |= MMC_CAP_UHS_SDR25;
- if (of_property_read_bool(np, "sd-uhs-sdr50"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr50"))
host->caps |= MMC_CAP_UHS_SDR50;
- if (of_property_read_bool(np, "sd-uhs-sdr104"))
+ if (device_property_read_bool(dev, "sd-uhs-sdr104"))
host->caps |= MMC_CAP_UHS_SDR104;
- if (of_property_read_bool(np, "sd-uhs-ddr50"))
+ if (device_property_read_bool(dev, "sd-uhs-ddr50"))
host->caps |= MMC_CAP_UHS_DDR50;
- if (of_property_read_bool(np, "cap-power-off-card"))
+ if (device_property_read_bool(dev, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD;
- if (of_property_read_bool(np, "cap-mmc-hw-reset"))
+ if (device_property_read_bool(dev, "cap-mmc-hw-reset"))
host->caps |= MMC_CAP_HW_RESET;
- if (of_property_read_bool(np, "cap-sdio-irq"))
+ if (device_property_read_bool(dev, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ;
- if (of_property_read_bool(np, "full-pwr-cycle"))
+ if (device_property_read_bool(dev, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
- if (of_property_read_bool(np, "keep-power-in-suspend"))
+ if (device_property_read_bool(dev, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER;
- if (of_property_read_bool(np, "wakeup-source") ||
- of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
+ if (device_property_read_bool(dev, "wakeup-source") ||
+ device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
- if (of_property_read_bool(np, "mmc-ddr-1_8v"))
+ if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR;
- if (of_property_read_bool(np, "mmc-ddr-1_2v"))
+ if (device_property_read_bool(dev, "mmc-ddr-1_2v"))
host->caps |= MMC_CAP_1_2V_DDR;
- if (of_property_read_bool(np, "mmc-hs200-1_8v"))
+ if (device_property_read_bool(dev, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
- if (of_property_read_bool(np, "mmc-hs200-1_2v"))
+ if (device_property_read_bool(dev, "mmc-hs200-1_2v"))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-1_8v"))
+ if (device_property_read_bool(dev, "mmc-hs400-1_8v"))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-1_2v"))
+ if (device_property_read_bool(dev, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
- if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+ if (device_property_read_bool(dev, "mmc-hs400-enhanced-strobe"))
host->caps2 |= MMC_CAP2_HS400_ES;
- if (of_property_read_bool(np, "no-sdio"))
+ if (device_property_read_bool(dev, "no-sdio"))
host->caps2 |= MMC_CAP2_NO_SDIO;
- if (of_property_read_bool(np, "no-sd"))
+ if (device_property_read_bool(dev, "no-sd"))
host->caps2 |= MMC_CAP2_NO_SD;
- if (of_property_read_bool(np, "no-mmc"))
+ if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
- host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
+ host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {
dev_err(host->parent,
"device tree specified broken value for DSR: 0x%x, ignoring\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 409718b..36295f5 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1357,10 +1357,6 @@
int err;
u8 val;
- /* Reduce frequency to HS */
- max_dtr = card->ext_csd.hs_max_dtr;
- mmc_set_clock(host, max_dtr);
-
/* Switch HS400 to HS DDR */
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
@@ -1371,6 +1367,10 @@
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+ /* Reduce frequency to HS */
+ max_dtr = card->ext_csd.hs_max_dtr;
+ mmc_set_clock(host, max_dtr);
+
err = mmc_switch_status(card, false);
if (err)
goto out_err;
@@ -1416,7 +1416,7 @@
static int mmc_select_hs400es(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- int err = 0;
+ int err = -EINVAL;
u8 val;
if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
@@ -2148,7 +2148,7 @@
err = mmc_select_hs400(card);
if (err)
goto free_card;
- } else {
+ } else if (!mmc_card_hs400es(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (err > 0 && mmc_card_hs(card)) {
@@ -2159,11 +2159,11 @@
}
card->clk_scaling_lowest = host->f_min;
- if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS400) ||
- (card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS200))
+ if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
+ (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200))
card->clk_scaling_highest = card->ext_csd.hs200_max_dtr;
- else if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS) ||
- (card->mmc_avail_type | EXT_CSD_CARD_TYPE_DDR_52))
+ else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ||
+ (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
card->clk_scaling_highest = card->ext_csd.hs_max_dtr;
else
card->clk_scaling_highest = card->csd.max_dtr;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 650f658..d591ded 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1275,7 +1275,10 @@
if (!err) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_suspended(&host->card->dev);
- }
+ /* if suspend fails, force mmc_detect_change during resume */
+ } else if (mmc_bus_manual_resume(host))
+ host->ignore_bus_resume_flags = true;
+
MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err);
return err;
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 7c3638c..82ff1a5 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -145,6 +145,29 @@
mb();
}
+static int cmdq_clear_task_poll(struct cmdq_host *cq_host, unsigned int tag)
+{
+ int retries = 100;
+
+ cmdq_clear_set_irqs(cq_host, CQIS_TCL, 0);
+ cmdq_writel(cq_host, 1<<tag, CQTCLR);
+ while (retries) {
+ /*
+ * Task Clear register and doorbell,
+ * both should indicate that task is cleared
+ */
+ if ((cmdq_readl(cq_host, CQTCLR) & 1<<tag) ||
+ (cmdq_readl(cq_host, CQTDBR) & 1<<tag)) {
+ udelay(5);
+ retries--;
+ continue;
+ } else
+ break;
+ }
+
+ cmdq_clear_set_irqs(cq_host, 0, CQIS_TCL);
+ return retries ? 0 : -ETIMEDOUT;
+}
#define DRV_NAME "cmdq-host"
@@ -345,6 +368,7 @@
{
int err = 0;
u32 cqcfg;
+ u32 cqcap = 0;
bool dcmd_enable;
struct cmdq_host *cq_host = mmc_cmdq_private(mmc);
@@ -373,6 +397,18 @@
cqcfg = ((cq_host->caps & CMDQ_TASK_DESC_SZ_128 ? CQ_TASK_DESC_SZ : 0) |
(dcmd_enable ? CQ_DCMD : 0));
+ cqcap = cmdq_readl(cq_host, CQCAP);
+ if (cqcap & CQCAP_CS) {
+ /*
+ * In case host controller supports cryptographic operations
+ * then, it uses 128bit task descriptor. Upper 64 bits of task
+ * descriptor would be used to pass crypto specific informaton.
+ */
+ cq_host->caps |= CMDQ_CAP_CRYPTO_SUPPORT |
+ CMDQ_TASK_DESC_SZ_128;
+ cqcfg |= CQ_ICE_ENABLE;
+ }
+
cmdq_writel(cq_host, cqcfg, CQCFG);
/* enable CQ_HOST */
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCFG) | CQ_ENABLE,
@@ -688,6 +724,30 @@
upper_32_bits(*task_desc));
}
+static inline
+void cmdq_prep_crypto_desc(struct cmdq_host *cq_host, u64 *task_desc,
+ u64 ice_ctx)
+{
+ u64 *ice_desc = NULL;
+
+ if (cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) {
+ /*
+ * Get the address of ice context for the given task descriptor.
+ * ice context is present in the upper 64bits of task descriptor
+ * ice_conext_base_address = task_desc + 8-bytes
+ */
+ ice_desc = (__le64 *)((u8 *)task_desc +
+ CQ_TASK_DESC_TASK_PARAMS_SIZE);
+ memset(ice_desc, 0, CQ_TASK_DESC_ICE_PARAMS_SIZE);
+
+ /*
+ * Assign upper 64bits data of task descritor with ice context
+ */
+ if (ice_ctx)
+ *ice_desc = cpu_to_le64(ice_ctx);
+ }
+}
+
static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -711,6 +771,7 @@
u32 tag = mrq->cmdq_req->tag;
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
struct sdhci_host *host = mmc_priv(mmc);
+ u64 ice_ctx = 0;
if (!cq_host->enabled) {
pr_err("%s: CMDQ host not enabled yet !!!\n",
@@ -730,7 +791,7 @@
}
if (cq_host->ops->crypto_cfg) {
- err = cq_host->ops->crypto_cfg(mmc, mrq, tag);
+ err = cq_host->ops->crypto_cfg(mmc, mrq, tag, &ice_ctx);
if (err) {
pr_err("%s: failed to configure crypto: err %d tag %d\n",
mmc_hostname(mmc), err, tag);
@@ -743,6 +804,9 @@
cmdq_prep_task_desc(mrq, &data, 1,
(mrq->cmdq_req->cmdq_req_flags & QBR));
*task_desc = cpu_to_le64(data);
+
+ cmdq_prep_crypto_desc(cq_host, task_desc, ice_ctx);
+
cmdq_log_task_desc_history(cq_host, *task_desc, false);
err = cmdq_prep_tran_desc(mrq, cq_host, tag);
@@ -787,7 +851,8 @@
CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG);
cmdq_runtime_pm_put(cq_host);
- if (cq_host->ops->crypto_cfg_reset)
+ if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) &&
+ cq_host->ops->crypto_cfg_reset)
cq_host->ops->crypto_cfg_reset(mmc, tag);
mrq->done(mrq);
}
@@ -801,6 +866,8 @@
struct mmc_request *mrq;
int ret;
u32 dbr_set = 0;
+ u32 dev_pend_set = 0;
+ int stat_err = 0;
status = cmdq_readl(cq_host, CQIS);
@@ -809,7 +876,9 @@
MMC_TRACE(mmc, "%s: CQIS: 0x%x err: %d\n",
__func__, status, err);
- if (err || (status & CQIS_RED)) {
+ stat_err = status & (CQIS_RED | CQIS_GCE | CQIS_ICCE);
+
+ if (err || stat_err) {
err_info = cmdq_readl(cq_host, CQTERRI);
pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n",
mmc_hostname(mmc), err, status, err_info);
@@ -912,7 +981,7 @@
* CQE detected a response error from device
* In most cases, this would require a reset.
*/
- if (status & CQIS_RED) {
+ if (stat_err & CQIS_RED) {
/*
* will check if the RED error is due to a bkops
* exception once the queue is empty
@@ -931,6 +1000,62 @@
mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA);
}
+ /*
+ * Generic Crypto error detected by CQE.
+ * Its a fatal, would require cmdq reset.
+ */
+ if (stat_err & CQIS_GCE) {
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ pr_err("%s: Crypto generic error while processing task %lu!",
+ mmc_hostname(mmc), tag);
+ MMC_TRACE(mmc, "%s: GCE error detected with tag %lu\n",
+ __func__, tag);
+ }
+ /*
+ * Invalid crypto config error detected by CQE, clear the task.
+ * Task can be cleared only when CQE is halt state.
+ */
+ if (stat_err & CQIS_ICCE) {
+ /*
+ * Invalid Crypto Config Error is detected at the
+ * beginning of the transfer before the actual execution
+ * started. So just clear the task in CQE. No need to
+ * clear in device. Only the task which caused ICCE has
+ * to be cleared. Other tasks can be continue processing
+ * The first task which is about to be prepared would
+ * cause ICCE Error.
+ */
+ dbr_set = cmdq_readl(cq_host, CQTDBR);
+ dev_pend_set = cmdq_readl(cq_host, CQDPT);
+ if (dbr_set ^ dev_pend_set)
+ tag = ffs(dbr_set ^ dev_pend_set) - 1;
+ mrq = get_req_by_tag(cq_host, tag);
+ pr_err("%s: Crypto config error while processing task %lu!",
+ mmc_hostname(mmc), tag);
+ MMC_TRACE(mmc, "%s: ICCE error with tag %lu\n",
+ __func__, tag);
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ else if (mrq->cmd)
+ mrq->cmd->error = -EIO;
+ /*
+ * If CQE is halted and tag is valid then clear the task
+ * then un-halt CQE and set flag to skip error recovery.
+ * If any of the condtions is not met thene it will
+ * enter into default error recovery path.
+ */
+ if (!ret && (dbr_set ^ dev_pend_set)) {
+ ret = cmdq_clear_task_poll(cq_host, tag);
+ if (ret) {
+ pr_err("%s: %s: task[%lu] clear failed ret=%d\n",
+ mmc_hostname(mmc),
+ __func__, tag, ret);
+ } else if (!cmdq_halt_poll(mmc, false)) {
+ mrq->cmdq_req->skip_err_handling = true;
+ }
+ }
+ }
cmdq_finish_data(mmc, tag);
} else {
cmdq_writel(cq_host, status, CQIS);
@@ -1001,6 +1126,7 @@
cq_host->ops->clear_set_irqs(mmc, true);
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
CQCTL);
+ mmc_host_clr_halt(mmc);
return 0;
}
diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h
index 8e9f765..551a7c5 100644
--- a/drivers/mmc/host/cmdq_hci.h
+++ b/drivers/mmc/host/cmdq_hci.h
@@ -18,11 +18,13 @@
#define CQVER 0x00
/* capabilities */
#define CQCAP 0x04
+#define CQCAP_CS (1 << 28)
/* configuration */
#define CQCFG 0x08
#define CQ_DCMD 0x00001000
#define CQ_TASK_DESC_SZ 0x00000100
#define CQ_ENABLE 0x00000001
+#define CQ_ICE_ENABLE 0x00000002
/* control */
#define CQCTL 0x0C
@@ -35,6 +37,8 @@
#define CQIS_TCC (1 << 1)
#define CQIS_RED (1 << 2)
#define CQIS_TCL (1 << 3)
+#define CQIS_GCE (1 << 4)
+#define CQIS_ICCE (1 << 5)
/* interrupt status enable */
#define CQISTE 0x14
@@ -110,7 +114,7 @@
/* command response argument */
#define CQCRA 0x5C
-#define CQ_INT_ALL 0xF
+#define CQ_INT_ALL 0x3F
#define CQIC_DEFAULT_ICCTH 31
#define CQIC_DEFAULT_ICTOVAL 1
@@ -144,6 +148,9 @@
#define CQ_VENDOR_CFG 0x100
#define CMDQ_SEND_STATUS_TRIGGER (1 << 31)
+#define CQ_TASK_DESC_TASK_PARAMS_SIZE 8
+#define CQ_TASK_DESC_ICE_PARAMS_SIZE 8
+
struct task_history {
u64 task;
bool is_dcmd;
@@ -161,6 +168,7 @@
u32 dcmd_slot;
u32 caps;
#define CMDQ_TASK_DESC_SZ_128 0x1
+#define CMDQ_CAP_CRYPTO_SUPPORT 0x2
u32 quirks;
#define CMDQ_QUIRK_SHORT_TXFR_DESC_SZ 0x1
@@ -209,7 +217,7 @@
int (*reset)(struct mmc_host *mmc);
void (*post_cqe_halt)(struct mmc_host *mmc);
int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq,
- u32 slot);
+ u32 slot, u64 *ice_ctx);
void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot);
};
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index df478ae..f81f417 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2610,8 +2610,8 @@
host->slot[id] = slot;
mmc->ops = &dw_mci_ops;
- if (of_property_read_u32_array(host->dev->of_node,
- "clock-freq-min-max", freq, 2)) {
+ if (device_property_read_u32_array(host->dev, "clock-freq-min-max",
+ freq, 2)) {
mmc->f_min = DW_MCI_FREQ_MIN;
mmc->f_max = DW_MCI_FREQ_MAX;
} else {
@@ -2709,7 +2709,6 @@
{
int addr_config;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
/*
* Check tansfer mode from HCON[17:16]
@@ -2770,8 +2769,9 @@
dev_info(host->dev, "Using internal DMA controller.\n");
} else {
/* TRANS_MODE_EDMAC: check dma bindings again */
- if ((of_property_count_strings(np, "dma-names") < 0) ||
- (!of_find_property(np, "dmas", NULL))) {
+ if ((device_property_read_string_array(dev, "dma-names",
+ NULL, 0) < 0) ||
+ !device_property_present(dev, "dmas")) {
goto no_dma;
}
host->dma_ops = &dw_mci_edmac_ops;
@@ -2931,7 +2931,6 @@
{
struct dw_mci_board *pdata;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int ret;
u32 clock_frequency;
@@ -2948,15 +2947,16 @@
}
/* find out number of slots supported */
- of_property_read_u32(np, "num-slots", &pdata->num_slots);
+ device_property_read_u32(dev, "num-slots", &pdata->num_slots);
- if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+ if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
dev_info(dev,
"fifo-depth property not found, using value of FIFOTH register as default\n");
- of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+ device_property_read_u32(dev, "card-detect-delay",
+ &pdata->detect_delay_ms);
- if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
+ if (!device_property_read_u32(dev, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
if (drv_data && drv_data->parse_dt) {
diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c
index d624b48..29eaff4 100644
--- a/drivers/mmc/host/sdhci-msm-ice.c
+++ b/drivers/mmc/host/sdhci-msm-ice.c
@@ -276,6 +276,58 @@
mb();
}
+static inline
+void sdhci_msm_ice_hci_update_cmdq_cfg(u64 dun, unsigned int bypass,
+ short key_index, u64 *ice_ctx)
+{
+ /*
+ * The naming convention got changed between ICE2.0 and ICE3.0
+ * registers fields. Below is the equivalent names for
+ * ICE3.0 Vs ICE2.0:
+ * Data Unit Number(DUN) == Logical Base address(LBA)
+ * Crypto Configuration index (CCI) == Key Index
+ * Crypto Enable (CE) == !BYPASS
+ */
+ if (ice_ctx)
+ *ice_ctx = DATA_UNIT_NUM(dun) |
+ CRYPTO_CONFIG_INDEX(key_index) |
+ CRYPTO_ENABLE(!bypass);
+}
+
+static
+void sdhci_msm_ice_hci_update_noncq_cfg(struct sdhci_host *host,
+ u64 dun, unsigned int bypass, short key_index)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned int crypto_params = 0;
+ /*
+ * The naming convention got changed between ICE2.0 and ICE3.0
+ * registers fields. Below is the equivalent names for
+ * ICE3.0 Vs ICE2.0:
+ * Data Unit Number(DUN) == Logical Base address(LBA)
+ * Crypto Configuration index (CCI) == Key Index
+ * Crypto Enable (CE) == !BYPASS
+ */
+ /* Configure ICE bypass mode */
+ crypto_params |=
+ (!bypass & MASK_SDHCI_MSM_ICE_HCI_PARAM_CE)
+ << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE;
+ /* Configure Crypto Configure Index (CCI) */
+ crypto_params |= (key_index &
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI)
+ << OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI;
+
+ writel_relaxed((crypto_params & 0xFFFFFFFF),
+ msm_host->cryptoio + ICE_NONCQ_CRYPTO_PARAMS);
+
+ /* Update DUN */
+ writel_relaxed((dun & 0xFFFFFFFF),
+ msm_host->cryptoio + ICE_NONCQ_CRYPTO_DUN);
+ /* Ensure ICE registers are configured before issuing SDHCI request */
+ mb();
+}
+
int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
u32 slot)
{
@@ -308,7 +360,57 @@
slot, bypass, key_index);
}
- sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ if (msm_host->ice_hci_support) {
+ /* For ICE HCI / ICE3.0 */
+ sdhci_msm_ice_hci_update_noncq_cfg(host, lba, bypass,
+ key_index);
+ } else {
+ /* For ICE versions earlier to ICE3.0 */
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ }
+ return 0;
+}
+
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int err = 0;
+ short key_index;
+ sector_t lba = 0;
+ unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
+ struct request *req;
+
+ if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
+ pr_err("%s: ice is in invalid state %d\n",
+ mmc_hostname(host->mmc), msm_host->ice.state);
+ return -EINVAL;
+ }
+
+ WARN_ON(!mrq);
+ if (!mrq)
+ return -EINVAL;
+ req = mrq->req;
+ if (req) {
+ lba = req->__sector;
+ err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index);
+ if (err)
+ return err;
+ pr_debug("%s: %s: slot %d bypass %d key_index %d\n",
+ mmc_hostname(host->mmc),
+ (rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
+ slot, bypass, key_index);
+ }
+
+ if (msm_host->ice_hci_support) {
+ /* For ICE HCI / ICE3.0 */
+ sdhci_msm_ice_hci_update_cmdq_cfg(lba, bypass, key_index,
+ ice_ctx);
+ } else {
+ /* For ICE versions earlier to ICE3.0 */
+ sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+ }
return 0;
}
diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h
index 23922cf..1afd1a9 100644
--- a/drivers/mmc/host/sdhci-msm-ice.h
+++ b/drivers/mmc/host/sdhci-msm-ice.h
@@ -42,6 +42,8 @@
#define ICE_HCI_SUPPORT (1 << 28)
#define ICE_CQ_CONFIG 0x08
#define CRYPTO_GENERAL_ENABLE (1 << 1)
+#define ICE_NONCQ_CRYPTO_PARAMS 0x70
+#define ICE_NONCQ_CRYPTO_DUN 0x74
/* ICE3.0 register which got added hc reg space */
#define HC_VENDOR_SPECIFIC_FUNC4 0x260
@@ -52,8 +54,10 @@
/* SDHCI MSM ICE CTRL Info register offset */
enum {
OFFSET_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0,
- OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1,
- OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x6,
+ OFFSET_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 1,
+ OFFSET_SDHCI_MSM_ICE_CTRL_INFO_CDU = 6,
+ OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0,
+ OFFSET_SDHCI_MSM_ICE_HCI_PARAM_CE = 8,
};
/* SDHCI MSM ICE CTRL Info register masks */
@@ -61,6 +65,8 @@
MASK_SDHCI_MSM_ICE_CTRL_INFO_BYPASS = 0x1,
MASK_SDHCI_MSM_ICE_CTRL_INFO_KEY_INDEX = 0x1F,
MASK_SDHCI_MSM_ICE_CTRL_INFO_CDU = 0x7,
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CE = 0x1,
+ MASK_SDHCI_MSM_ICE_HCI_PARAM_CCI = 0xff
};
/* SDHCI MSM ICE encryption/decryption bypass state */
@@ -99,6 +105,8 @@
void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot);
int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
u32 slot);
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
int sdhci_msm_ice_reset(struct sdhci_host *host);
int sdhci_msm_ice_resume(struct sdhci_host *host);
int sdhci_msm_ice_suspend(struct sdhci_host *host);
@@ -130,6 +138,11 @@
{
return 0;
}
+static inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+ return 0;
+}
inline int sdhci_msm_ice_reset(struct sdhci_host *host)
{
return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 1e25b31..d93de2e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -146,6 +146,7 @@
#define CORE_START_CDC_TRAFFIC (1 << 6)
#define CORE_PWRSAVE_DLL (1 << 3)
+#define CORE_FIFO_ALT_EN (1 << 10)
#define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13)
#define CORE_DDR_CAL_EN (1 << 0)
@@ -1143,6 +1144,7 @@
bool drv_type_changed = false;
struct mmc_card *card = host->mmc->card;
int sts_retry;
+ u8 last_good_phase = 0;
/*
* Tuning is required for SDR104, HS200 and HS400 cards and
@@ -1228,6 +1230,22 @@
mmc_wait_for_req(mmc, &mrq);
if (card && (cmd.error || data.error)) {
+ /*
+ * Set the dll to last known good phase while sending
+ * status command to ensure that status command won't
+ * fail due to bad phase.
+ */
+ if (tuned_phase_cnt)
+ last_good_phase =
+ tuned_phases[tuned_phase_cnt-1];
+ else if (msm_host->saved_tuning_phase !=
+ INVALID_TUNING_PHASE)
+ last_good_phase = msm_host->saved_tuning_phase;
+
+ rc = msm_config_cm_dll_phase(host, last_good_phase);
+ if (rc)
+ goto kfree;
+
sts_cmd.opcode = MMC_SEND_STATUS;
sts_cmd.arg = card->rca << 16;
sts_cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -4097,6 +4115,8 @@
static struct sdhci_ops sdhci_msm_ops = {
.crypto_engine_cfg = sdhci_msm_ice_cfg,
+ .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg,
+ .crypto_cfg_reset = sdhci_msm_ice_cfg_reset,
.crypto_engine_reset = sdhci_msm_ice_reset,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.check_power_status = sdhci_msm_check_power_status,
@@ -4196,7 +4216,7 @@
* starts coming.
*/
if ((major == 1) && ((minor == 0x42) || (minor == 0x46) ||
- (minor == 0x49)))
+ (minor == 0x49) || (minor >= 0x6b)))
msm_host->use_14lpp_dll = true;
/* Fake 3.0V support for SDIO devices which requires such voltage */
@@ -4221,8 +4241,10 @@
/* keep track of the value in SDHCI_CAPABILITIES */
msm_host->caps_0 = caps;
- if ((major == 1) && (minor >= 0x6b))
+ if ((major == 1) && (minor >= 0x6b)) {
msm_host->ice_hci_support = true;
+ host->cdr_support = true;
+ }
}
#ifdef CONFIG_MMC_CQ_HCI
@@ -4289,6 +4311,7 @@
struct resource *tlmm_memres = NULL;
void __iomem *tlmm_mem;
unsigned long flags;
+ bool force_probe;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -4352,8 +4375,13 @@
goto pltfm_free;
}
+ /* Read property to determine if the probe is forced */
+ force_probe = of_find_property(pdev->dev.of_node,
+ "qcom,force-sdhc1-probe", NULL);
+
/* skip the probe if eMMC isn't a boot device */
- if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)) {
+ if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)
+ && !force_probe) {
ret = -ENODEV;
goto pltfm_free;
}
@@ -4518,6 +4546,14 @@
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
+ /*
+ * Ensure SDHCI FIFO is enabled by disabling alternative FIFO
+ */
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3) &
+ ~CORE_FIFO_ALT_EN), host->ioaddr +
+ msm_host_offset->CORE_VENDOR_SPEC3);
+
if (!msm_host->mci_removed) {
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
@@ -4914,8 +4950,6 @@
if (msm_host->msm_bus_vote.client_handle)
sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
}
- trace_sdhci_msm_runtime_suspend(mmc_hostname(host->mmc), 0,
- ktime_to_us(ktime_sub(ktime_get(), start)));
if (host->is_crypto_en) {
ret = sdhci_msm_ice_suspend(host);
@@ -4923,6 +4957,8 @@
pr_err("%s: failed to suspend crypto engine %d\n",
mmc_hostname(host->mmc), ret);
}
+ trace_sdhci_msm_runtime_suspend(mmc_hostname(host->mmc), 0,
+ ktime_to_us(ktime_sub(ktime_get(), start)));
return 0;
}
@@ -5050,7 +5086,7 @@
}
static const struct dev_pm_ops sdhci_msm_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
NULL)
.suspend_noirq = sdhci_msm_suspend_noirq,
@@ -5074,6 +5110,7 @@
.driver = {
.name = "sdhci_msm",
.owner = THIS_MODULE,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_msm_dt_match,
.pm = SDHCI_MSM_PMOPS,
},
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index a8b430f..83b84ff 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -31,6 +31,7 @@
#define SDMMC_MC1R 0x204
#define SDMMC_MC1R_DDR BIT(3)
+#define SDMMC_MC1R_FCD BIT(7)
#define SDMMC_CACR 0x230
#define SDMMC_CACR_CAPWREN BIT(0)
#define SDMMC_CACR_KEY (0x46 << 8)
@@ -43,6 +44,15 @@
struct clk *mainck;
};
+static void sdhci_at91_set_force_card_detect(struct sdhci_host *host)
+{
+ u8 mc1r;
+
+ mc1r = readb(host->ioaddr + SDMMC_MC1R);
+ mc1r |= SDMMC_MC1R_FCD;
+ writeb(mc1r, host->ioaddr + SDMMC_MC1R);
+}
+
static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
@@ -112,10 +122,18 @@
sdhci_set_uhs_signaling(host, timing);
}
+static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
+{
+ sdhci_reset(host, mask);
+
+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ sdhci_at91_set_force_card_detect(host);
+}
+
static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
.set_clock = sdhci_at91_set_clock,
.set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
+ .reset = sdhci_at91_reset,
.set_uhs_signaling = sdhci_at91_set_uhs_signaling,
.set_power = sdhci_at91_set_power,
};
@@ -322,6 +340,21 @@
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
+ /*
+ * If the device attached to the MMC bus is not removable, it is safer
+ * to set the Force Card Detect bit. People often don't connect the
+ * card detect signal and use this pin for another purpose. If the card
+ * detect pin is not muxed to SDHCI controller, a default value is
+ * used. This value can be different from a SoC revision to another
+ * one. Problems come when this default value is not card present. To
+ * avoid this case, if the device is non removable then the card
+ * detection procedure using the SDMCC_CD signal is bypassed.
+ * This bit is reset when a software reset for all command is performed
+ * so we need to implement our own reset function to set back this bit.
+ */
+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ sdhci_at91_set_force_card_detect(host);
+
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 68e49bb..7f13f07 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3088,12 +3088,6 @@
* above in sdhci_cmd_irq().
*/
if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
- if (intmask & SDHCI_INT_DATA_TIMEOUT) {
- host->data_cmd = NULL;
- data_cmd->error = -ETIMEDOUT;
- sdhci_finish_mrq(host, data_cmd->mrq);
- return;
- }
if (intmask & SDHCI_INT_DATA_END) {
host->data_cmd = NULL;
/*
@@ -3108,8 +3102,21 @@
return;
}
if (host->quirks2 &
- SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD)
+ SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) {
+ pr_err_ratelimited("%s: %s: ignoring interrupt: 0x%08x due to DATATOUT_FOR_R1B quirk\n",
+ mmc_hostname(host->mmc),
+ __func__, intmask);
+ MMC_TRACE(host->mmc,
+ "%s: Quirk ignoring intr: 0x%08x\n",
+ __func__, intmask);
return;
+ }
+ if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+ host->data_cmd = NULL;
+ data_cmd->error = -ETIMEDOUT;
+ sdhci_finish_mrq(host, data_cmd->mrq);
+ return;
+ }
}
/*
@@ -3689,7 +3696,7 @@
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
- if (host->ops->toggle_cdr)
+ if (host->ops->toggle_cdr && !host->cdr_support)
host->ops->toggle_cdr(host, false);
}
@@ -3768,14 +3775,35 @@
sdhci_writel(host, SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
}
static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
- struct mmc_request *mrq, u32 slot)
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
{
struct sdhci_host *host = mmc_priv(mmc);
+ int err = 0;
if (!host->is_crypto_en)
return 0;
- return sdhci_crypto_cfg(host, mrq, slot);
+ if (host->crypto_reset_reqd && host->ops->crypto_engine_reset) {
+ err = host->ops->crypto_engine_reset(host);
+ if (err) {
+ pr_err("%s: crypto reset failed\n",
+ mmc_hostname(host->mmc));
+ goto out;
+ }
+ host->crypto_reset_reqd = false;
+ }
+
+ if (host->ops->crypto_engine_cmdq_cfg) {
+ err = host->ops->crypto_engine_cmdq_cfg(host, mrq,
+ slot, ice_ctx);
+ if (err) {
+ pr_err("%s: failed to configure crypto\n",
+ mmc_hostname(host->mmc));
+ goto out;
+ }
+ }
+out:
+ return err;
}
static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot)
@@ -3835,7 +3863,7 @@
}
static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc,
- struct mmc_request *mrq, u32 slot)
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
{
return 0;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 04e806c..a463e45 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -518,7 +518,7 @@
* Some controllers may use PIO mode to workaround HW issues in ADMA for
* eMMC tuning commands.
*/
-#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 23)
+#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 29)
int irq; /* Device IRQ */
@@ -569,6 +569,7 @@
bool bus_on; /* Bus power prevents runtime suspend */
bool preset_enabled; /* Preset is enabled */
bool pending_reset; /* Cmd/data reset is pending */
+ bool cdr_support;
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_request *mrq; /* Current request */
@@ -670,6 +671,8 @@
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*crypto_engine_cfg)(struct sdhci_host *host,
struct mmc_request *mrq, u32 slot);
+ int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host,
+ struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
int (*crypto_engine_reset)(struct sdhci_host *host);
void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot);
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index f222f8a..31a6ee3 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -64,8 +64,14 @@
if (!section) {
oobregion->offset = 0;
- oobregion->length = 4;
+ if (mtd->oobsize == 16)
+ oobregion->length = 4;
+ else
+ oobregion->length = 3;
} else {
+ if (mtd->oobsize == 8)
+ return -ERANGE;
+
oobregion->offset = 6;
oobregion->length = ecc->total - 4;
}
@@ -1081,7 +1087,9 @@
* Ensure the timing mode has been changed on the chip side
* before changing timings on the controller side.
*/
- if (chip->onfi_version) {
+ if (chip->onfi_version &&
+ (le16_to_cpu(chip->onfi_params.opt_cmd) &
+ ONFI_OPT_CMD_SET_GET_FEATURES)) {
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 947adda..3ec573c 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1558,6 +1558,7 @@
.dev_name = "BCM53125",
.vlans = 4096,
.enabled_ports = 0xff,
+ .arl_entries = 4,
.cpu_port = B53_CPU_PORT,
.vta_regs = B53_VTA_REGS,
.duplex_reg = B53_DUPLEX_STAT_GE,
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
index e078d8d..29d29af 100644
--- a/drivers/net/ethernet/aurora/nb8800.c
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -609,7 +609,7 @@
mac_mode |= HALF_DUPLEX;
if (gigabit) {
- if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (phy_interface_is_rgmii(dev->phydev))
mac_mode |= RGMII_MODE;
mac_mode |= GMAC_MODE;
@@ -1277,11 +1277,10 @@
break;
case PHY_INTERFACE_MODE_RGMII:
- pad_mode = PAD_MODE_RGMII;
- break;
-
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
- pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+ pad_mode = PAD_MODE_RGMII;
break;
default:
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index a927a73..edae2dc 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -8720,11 +8720,14 @@
tg3_mem_rx_release(tp);
tg3_mem_tx_release(tp);
+ /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
+ tg3_full_lock(tp, 0);
if (tp->hw_stats) {
dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
tp->hw_stats, tp->stats_mapping);
tp->hw_stats = NULL;
}
+ tg3_full_unlock(tp);
}
/*
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 5d48458..bcbb80f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -724,16 +724,21 @@
* header, the HW adds it. To address that, we are subtracting the pseudo
* header checksum from the checksum value provided by the HW.
*/
-static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
- struct iphdr *iph)
+static int get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
+ struct iphdr *iph)
{
__u16 length_for_csum = 0;
__wsum csum_pseudo_header = 0;
+ __u8 ipproto = iph->protocol;
+
+ if (unlikely(ipproto == IPPROTO_SCTP))
+ return -1;
length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2));
csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr,
- length_for_csum, iph->protocol, 0);
+ length_for_csum, ipproto, 0);
skb->csum = csum_sub(hw_checksum, csum_pseudo_header);
+ return 0;
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -744,17 +749,20 @@
static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
struct ipv6hdr *ipv6h)
{
+ __u8 nexthdr = ipv6h->nexthdr;
__wsum csum_pseudo_hdr = 0;
- if (unlikely(ipv6h->nexthdr == IPPROTO_FRAGMENT ||
- ipv6h->nexthdr == IPPROTO_HOPOPTS))
+ if (unlikely(nexthdr == IPPROTO_FRAGMENT ||
+ nexthdr == IPPROTO_HOPOPTS ||
+ nexthdr == IPPROTO_SCTP))
return -1;
- hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(ipv6h->nexthdr));
+ hw_checksum = csum_add(hw_checksum, (__force __wsum)htons(nexthdr));
csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len);
- csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr));
+ csum_pseudo_hdr = csum_add(csum_pseudo_hdr,
+ (__force __wsum)htons(nexthdr));
skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr);
skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0));
@@ -777,11 +785,10 @@
}
if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4))
- get_fixed_ipv4_csum(hw_checksum, skb, hdr);
+ return get_fixed_ipv4_csum(hw_checksum, skb, hdr);
#if IS_ENABLED(CONFIG_IPV6)
- else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
- if (unlikely(get_fixed_ipv6_csum(hw_checksum, skb, hdr)))
- return -1;
+ if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
+ return get_fixed_ipv6_csum(hw_checksum, skb, hdr);
#endif
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 551786f..ba652d8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -430,7 +430,7 @@
/* Virtual PCI function needs to determine UAR page size from
* firmware. Only master PCI function can set the uar page size
*/
- if (enable_4k_uar)
+ if (enable_4k_uar || !dev->persist->num_vfs)
dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
else
dev->uar_page_shift = PAGE_SHIFT;
@@ -2269,7 +2269,7 @@
dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
- if (enable_4k_uar) {
+ if (enable_4k_uar || !dev->persist->num_vfs) {
init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
PAGE_SHIFT - DEFAULT_UAR_PAGE_SHIFT;
init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index cb45390..f7fabec 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -770,6 +770,10 @@
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
}
+static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg);
+static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev,
+ struct mlx5_cmd_msg *msg);
+
static void cmd_work_handler(struct work_struct *work)
{
struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work);
@@ -779,16 +783,27 @@
struct mlx5_cmd_layout *lay;
struct semaphore *sem;
unsigned long flags;
+ int alloc_ret;
sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
down(sem);
if (!ent->page_queue) {
- ent->idx = alloc_ent(cmd);
- if (ent->idx < 0) {
+ alloc_ret = alloc_ent(cmd);
+ if (alloc_ret < 0) {
+ if (ent->callback) {
+ ent->callback(-EAGAIN, ent->context);
+ mlx5_free_cmd_msg(dev, ent->out);
+ free_msg(dev, ent->in);
+ free_cmd(ent);
+ } else {
+ ent->ret = -EAGAIN;
+ complete(&ent->done);
+ }
mlx5_core_err(dev, "failed to allocate command entry\n");
up(sem);
return;
}
+ ent->idx = alloc_ret;
} else {
ent->idx = cmd->max_reg_cmds;
spin_lock_irqsave(&cmd->alloc_lock, flags);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
index 13dc388..1612ec0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
@@ -62,12 +62,14 @@
struct delayed_work *dwork = to_delayed_work(work);
struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
overflow_work);
+ struct mlx5e_priv *priv = container_of(tstamp, struct mlx5e_priv, tstamp);
unsigned long flags;
write_lock_irqsave(&tstamp->lock, flags);
timecounter_read(&tstamp->clock);
write_unlock_irqrestore(&tstamp->lock, flags);
- schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
+ queue_delayed_work(priv->wq, &tstamp->overflow_work,
+ msecs_to_jiffies(tstamp->overflow_period * 1000));
}
int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
@@ -263,7 +265,7 @@
INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
if (tstamp->overflow_period)
- schedule_delayed_work(&tstamp->overflow_work, 0);
+ queue_delayed_work(priv->wq, &tstamp->overflow_work, 0);
else
mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
index e034dbc..cf070fc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -276,7 +276,7 @@
static bool outer_header_zero(u32 *match_criteria)
{
- int size = MLX5_ST_SZ_BYTES(fte_match_param);
+ int size = MLX5_FLD_SZ_BYTES(fte_match_param, outer_headers);
char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria,
outer_headers);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 6ffd5d2..52a3810 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -651,9 +651,14 @@
int vport;
int err;
+ /* disable PF RoCE so missed packets don't go through RoCE steering */
+ mlx5_dev_list_lock();
+ mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
err = esw_create_offloads_fdb_table(esw, nvports);
if (err)
- return err;
+ goto create_fdb_err;
err = esw_create_offloads_table(esw);
if (err)
@@ -673,11 +678,6 @@
goto err_reps;
}
- /* disable PF RoCE so missed packets don't go through RoCE steering */
- mlx5_dev_list_lock();
- mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
return 0;
err_reps:
@@ -694,6 +694,13 @@
create_ft_err:
esw_destroy_offloads_fdb_table(esw);
+
+create_fdb_err:
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
@@ -701,11 +708,6 @@
{
int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
- /* enable back PF RoCE */
- mlx5_dev_list_lock();
- mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
mlx5_eswitch_disable_sriov(esw);
err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
if (err) {
@@ -715,6 +717,11 @@
esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
}
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
index b5d5519..0ca4623 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
@@ -157,22 +157,17 @@
static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
u8 *port1, u8 *port2)
{
- if (tracker->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) {
- if (tracker->netdev_state[0].tx_enabled) {
- *port1 = 1;
- *port2 = 1;
- } else {
- *port1 = 2;
- *port2 = 2;
- }
- } else {
- *port1 = 1;
- *port2 = 2;
- if (!tracker->netdev_state[0].link_up)
- *port1 = 2;
- else if (!tracker->netdev_state[1].link_up)
- *port2 = 1;
+ *port1 = 1;
+ *port2 = 2;
+ if (!tracker->netdev_state[0].tx_enabled ||
+ !tracker->netdev_state[0].link_up) {
+ *port1 = 2;
+ return;
}
+
+ if (!tracker->netdev_state[1].tx_enabled ||
+ !tracker->netdev_state[1].link_up)
+ *port2 = 1;
}
static void mlx5_activate_lag(struct mlx5_lag *ldev,
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index aee3fd2..4ca82bd 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -871,8 +871,7 @@
return NETDEV_TX_OK;
err_unmap:
- --f;
- while (f >= 0) {
+ while (--f >= 0) {
frag = &skb_shinfo(skb)->frags[f];
dma_unmap_page(&nn->pdev->dev,
tx_ring->txbufs[wr_idx].dma_addr,
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 12be259..2140ded 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -574,6 +574,7 @@
.rpadir_value = 2 << 16,
.no_trimd = 1,
.no_ade = 1,
+ .hw_crc = 1,
.tsu = 1,
.select_mii = 1,
.shift_rd0 = 1,
@@ -802,7 +803,7 @@
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
@@ -832,7 +833,7 @@
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index bca6a1e..e1bb802 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -141,9 +141,19 @@
static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
{
struct usb_device *dev = mcs->usbdev;
- int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
- MCS_RD_RTYPE, 0, reg, val, 2,
- msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+ void *dmabuf;
+ int ret;
+
+ dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, reg, dmabuf, 2,
+ msecs_to_jiffies(MCS_CTRL_TIMEOUT));
+
+ memcpy(val, dmabuf, sizeof(__u16));
+ kfree(dmabuf);
return ret;
}
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 4cad955..01cf094 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -29,6 +29,7 @@
#define MII_DP83867_MICR 0x12
#define MII_DP83867_ISR 0x13
#define DP83867_CTRL 0x1f
+#define DP83867_CFG3 0x1e
/* Extended Registers */
#define DP83867_RGMIICTL 0x0032
@@ -90,6 +91,8 @@
micr_status |=
(MII_DP83867_MICR_AN_ERR_INT_EN |
MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+ MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
+ MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
@@ -190,6 +193,13 @@
DP83867_DEVADDR, delay);
}
+ /* Enable Interrupt output INT_OE in CFG3 register */
+ if (phy_interrupt_is_valid(phydev)) {
+ val = phy_read(phydev, DP83867_CFG3);
+ val |= BIT(7);
+ phy_write(phydev, DP83867_CFG3, val);
+ }
+
return 0;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index edd30eb..775a6e1 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -674,6 +674,9 @@
if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
phydev->state = PHY_UP;
mutex_unlock(&phydev->lock);
+
+ /* Now we can run the state machine synchronously */
+ phy_state_machine(&phydev->state_queue.work);
}
/**
@@ -1060,6 +1063,15 @@
if (old_link != phydev->link)
phydev->state = PHY_CHANGELINK;
}
+ /*
+ * Failsafe: check that nobody set phydev->link=0 between two
+ * poll cycles, otherwise we won't leave RUNNING state as long
+ * as link remains down.
+ */
+ if (!phydev->link && phydev->state == PHY_RUNNING) {
+ phydev->state = PHY_CHANGELINK;
+ phydev_err(phydev, "no link in PHY_RUNNING\n");
+ }
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9e7b783..bf02f8e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1714,6 +1714,8 @@
{
struct phy_device *phydev = to_phy_device(dev);
+ cancel_delayed_work_sync(&phydev->state_queue);
+
mutex_lock(&phydev->lock);
phydev->state = PHY_DOWN;
mutex_unlock(&phydev->lock);
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 5489c0e..96fa0e6 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -119,6 +119,7 @@
int n_channels; /* how many channels are attached 54 */
spinlock_t rlock; /* lock for receive side 58 */
spinlock_t wlock; /* lock for transmit side 5c */
+ int *xmit_recursion __percpu; /* xmit recursion detect */
int mru; /* max receive unit 60 */
unsigned int flags; /* control bits 64 */
unsigned int xstate; /* transmit state bits 68 */
@@ -1024,6 +1025,7 @@
struct ppp *ppp = netdev_priv(dev);
int indx;
int err;
+ int cpu;
ppp->dev = dev;
ppp->ppp_net = src_net;
@@ -1038,6 +1040,15 @@
INIT_LIST_HEAD(&ppp->channels);
spin_lock_init(&ppp->rlock);
spin_lock_init(&ppp->wlock);
+
+ ppp->xmit_recursion = alloc_percpu(int);
+ if (!ppp->xmit_recursion) {
+ err = -ENOMEM;
+ goto err1;
+ }
+ for_each_possible_cpu(cpu)
+ (*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0;
+
#ifdef CONFIG_PPP_MULTILINK
ppp->minseq = -1;
skb_queue_head_init(&ppp->mrq);
@@ -1049,11 +1060,15 @@
err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
if (err < 0)
- return err;
+ goto err2;
conf->file->private_data = &ppp->file;
return 0;
+err2:
+ free_percpu(ppp->xmit_recursion);
+err1:
+ return err;
}
static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
@@ -1399,18 +1414,16 @@
ppp_xmit_unlock(ppp);
}
-static DEFINE_PER_CPU(int, ppp_xmit_recursion);
-
static void ppp_xmit_process(struct ppp *ppp)
{
local_bh_disable();
- if (unlikely(__this_cpu_read(ppp_xmit_recursion)))
+ if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
goto err;
- __this_cpu_inc(ppp_xmit_recursion);
+ (*this_cpu_ptr(ppp->xmit_recursion))++;
__ppp_xmit_process(ppp);
- __this_cpu_dec(ppp_xmit_recursion);
+ (*this_cpu_ptr(ppp->xmit_recursion))--;
local_bh_enable();
@@ -1901,23 +1914,23 @@
spin_unlock_bh(&pch->downl);
/* see if there is anything from the attached unit to be sent */
if (skb_queue_empty(&pch->file.xq)) {
- read_lock_bh(&pch->upl);
ppp = pch->ppp;
if (ppp)
__ppp_xmit_process(ppp);
- read_unlock_bh(&pch->upl);
}
}
static void ppp_channel_push(struct channel *pch)
{
- local_bh_disable();
-
- __this_cpu_inc(ppp_xmit_recursion);
- __ppp_channel_push(pch);
- __this_cpu_dec(ppp_xmit_recursion);
-
- local_bh_enable();
+ read_lock_bh(&pch->upl);
+ if (pch->ppp) {
+ (*this_cpu_ptr(pch->ppp->xmit_recursion))++;
+ __ppp_channel_push(pch);
+ (*this_cpu_ptr(pch->ppp->xmit_recursion))--;
+ } else {
+ __ppp_channel_push(pch);
+ }
+ read_unlock_bh(&pch->upl);
}
/*
@@ -3056,6 +3069,7 @@
#endif /* CONFIG_PPP_FILTER */
kfree_skb(ppp->xmit_pending);
+ free_percpu(ppp->xmit_recursion);
free_netdev(ppp->dev);
}
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 2f260c6..49a27dc 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -876,6 +876,7 @@
{QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */
{QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */
{QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */
+ {QMI_FIXED_INTF(0x2001, 0x7e35, 4)}, /* D-Link DWM-222 */
{QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */
{QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */
{QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b7fe0af..63754ee 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -807,9 +807,15 @@
WLAN_STATUS_SUCCESS, GFP_KERNEL);
cfg80211_put_bss(ar->wiphy, bss);
} else if (vif->sme_state == SME_CONNECTED) {
+ struct cfg80211_roam_info roam_info = {
+ .bss = bss,
+ .req_ie = assoc_req_ie,
+ .req_ie_len = assoc_req_len,
+ .resp_ie = assoc_resp_ie,
+ .resp_ie_len = assoc_resp_len,
+ };
/* inform roam event to cfg80211 */
- cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
- assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+ cfg80211_roamed(vif->ndev, &roam_info, GFP_KERNEL);
}
}
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 0e66348..2ab6c59 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -60,3 +60,15 @@
---help---
Say Y here to enable wil6210 driver support for MSM
platform specific features
+
+config WIL6210_DEBUGFS
+ bool "wil6210 debugfs support"
+ depends on WIL6210
+ depends on DEBUG_FS
+ default y
+ ---help---
+ Say Y here to enable wil6210 debugfs support, using the
+ kernel debugfs infrastructure. Select this
+ option if you are interested in debugging the driver.
+
+ If unsure, say Y to make it easier to debug problems.
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 4874c5b..94df1de 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -4,7 +4,7 @@
wil6210-y += netdev.o
wil6210-y += cfg80211.o
wil6210-y += pcie_bus.o
-wil6210-y += debugfs.o
+wil6210-$(CONFIG_WIL6210_DEBUGFS) += debugfs.o
wil6210-y += sysfs.o
wil6210-y += wmi.o
wil6210-y += interrupt.o
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 7a0b226..9552d2a 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -454,6 +454,34 @@
return rc;
}
+static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+ wil_dbg_misc(wil, "start_p2p_device: entered\n");
+ wil->p2p.p2p_dev_started = 1;
+ return 0;
+}
+
+static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil_p2p_info *p2p = &wil->p2p;
+
+ if (!p2p->p2p_dev_started)
+ return;
+
+ wil_dbg_misc(wil, "stop_p2p_device: entered\n");
+ mutex_lock(&wil->mutex);
+ mutex_lock(&wil->p2p_wdev_mutex);
+ wil_p2p_stop_radio_operations(wil);
+ p2p->p2p_dev_started = 0;
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->mutex);
+}
+
static struct wireless_dev *
wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
unsigned char name_assign_type,
@@ -502,6 +530,7 @@
return -EINVAL;
}
+ wil_cfg80211_stop_p2p_device(wiphy, wdev);
wil_p2p_wdev_free(wil);
return 0;
@@ -886,7 +915,7 @@
wil->bss = bss;
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
- jiffies + msecs_to_jiffies(2000));
+ jiffies + msecs_to_jiffies(5000));
} else {
clear_bit(wil_status_fwconnecting, wil->status);
}
@@ -1736,34 +1765,6 @@
return 0;
}
-static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
- struct wireless_dev *wdev)
-{
- struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-
- wil_dbg_misc(wil, "start_p2p_device: entered\n");
- wil->p2p.p2p_dev_started = 1;
- return 0;
-}
-
-static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
- struct wireless_dev *wdev)
-{
- struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- struct wil_p2p_info *p2p = &wil->p2p;
-
- if (!p2p->p2p_dev_started)
- return;
-
- wil_dbg_misc(wil, "stop_p2p_device: entered\n");
- mutex_lock(&wil->mutex);
- mutex_lock(&wil->p2p_wdev_mutex);
- wil_p2p_stop_radio_operations(wil);
- p2p->p2p_dev_started = 0;
- mutex_unlock(&wil->p2p_wdev_mutex);
- mutex_unlock(&wil->mutex);
-}
-
static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
struct net_device *dev,
bool enabled, int timeout)
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index e01acac..7a33792 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -124,24 +124,19 @@
return 0;
}
-static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
- size_t size)
-{
- wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
-
- return 0;
-}
-
static int
-fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
- size_t size)
+fw_handle_comment(struct wil6210_priv *wil, const void *data,
+ size_t size)
{
const struct wil_fw_record_capabilities *rec = data;
size_t capa_size;
if (size < sizeof(*rec) ||
- le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
+ le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
+ data, size, true);
return 0;
+ }
capa_size = size - offsetof(struct wil_fw_record_capabilities,
capabilities);
@@ -422,7 +417,7 @@
int (*parse_handler)(struct wil6210_priv *wil, const void *data,
size_t size);
} wil_fw_handlers[] = {
- {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
+ {wil_fw_type_comment, fw_handle_comment, fw_handle_comment},
{wil_fw_type_data, fw_handle_data, fw_ignore_section},
{wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
/* wil_fw_type_action */
@@ -517,7 +512,7 @@
rc = request_firmware(&fw, name, wil_to_dev(wil));
if (rc) {
- wil_err_fw(wil, "Failed to load firmware %s\n", name);
+ wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc);
return rc;
}
wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index cad8a95c4..59def4f 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -244,7 +244,7 @@
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (unlikely(!isr)) {
- wil_err(wil, "spurious IRQ: RX\n");
+ wil_err_ratelimited(wil, "spurious IRQ: RX\n");
return IRQ_NONE;
}
@@ -269,11 +269,12 @@
need_unmask = false;
napi_schedule(&wil->napi_rx);
} else {
- wil_err(wil,
+ wil_err_ratelimited(
+ wil,
"Got Rx interrupt while stopping interface\n");
}
} else {
- wil_err(wil, "Got Rx interrupt while in reset\n");
+ wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n");
}
}
@@ -302,7 +303,7 @@
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (unlikely(!isr)) {
- wil_err(wil, "spurious IRQ: TX\n");
+ wil_err_ratelimited(wil, "spurious IRQ: TX\n");
return IRQ_NONE;
}
@@ -318,12 +319,13 @@
need_unmask = false;
napi_schedule(&wil->napi_tx);
} else {
- wil_err(wil, "Got Tx interrupt while in reset\n");
+ wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n");
}
}
if (unlikely(isr))
- wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
+ wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n",
+ isr);
/* Tx IRQ will be enabled when NAPI processing finished */
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index d90fe1c..c4faa2c 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -765,6 +765,8 @@
u8 retry_short;
int rc;
+ wil_refresh_fw_capabilities(wil);
+
rc = wmi_get_mgmt_retry(wil, &retry_short);
if (!rc) {
wiphy->retry_short = retry_short;
@@ -772,6 +774,25 @@
}
}
+void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
+{
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+
+ wil->keep_radio_on_during_sleep =
+ wil->platform_ops.keep_radio_on_during_sleep &&
+ wil->platform_ops.keep_radio_on_during_sleep(
+ wil->platform_handle) &&
+ test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
+
+ wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
+ wil->keep_radio_on_during_sleep);
+
+ if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ else
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+}
+
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
le32_to_cpus(&r->base);
@@ -934,6 +955,29 @@
return rc;
}
+static void wil_pre_fw_config(struct wil6210_priv *wil)
+{
+ /* Mark FW as loaded from host */
+ wil_s(wil, RGF_USER_USAGE_6, 1);
+
+ /* clear any interrupts which on-card-firmware
+ * may have set
+ */
+ wil6210_clear_irq(wil);
+ /* CAF_ICR - clear and mask */
+ /* it is W1C, clear by writing back same value */
+ wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
+ wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
+ /* clear PAL_UNIT_ICR (potential D0->D3 leftover) */
+ wil_s(wil, RGF_PAL_UNIT_ICR + offsetof(struct RGF_ICR, ICR), 0);
+
+ if (wil->fw_calib_result > 0) {
+ __le32 val = cpu_to_le32(wil->fw_calib_result |
+ (CALIB_RESULT_SIGNATURE << 8));
+ wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
+ }
+}
+
/*
* We reset all the structures, and we reset the UMAC.
* After calling this routine, you're expected to reload
@@ -1031,24 +1075,7 @@
if (rc)
return rc;
- /* Mark FW as loaded from host */
- wil_s(wil, RGF_USER_USAGE_6, 1);
-
- /* clear any interrupts which on-card-firmware
- * may have set
- */
- wil6210_clear_irq(wil);
- /* CAF_ICR - clear and mask */
- /* it is W1C, clear by writing back same value */
- wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
- wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
-
- if (wil->fw_calib_result > 0) {
- __le32 val = cpu_to_le32(wil->fw_calib_result |
- (CALIB_RESULT_SIGNATURE << 8));
- wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
- }
-
+ wil_pre_fw_config(wil);
wil_release_cpu(wil);
}
@@ -1074,14 +1101,14 @@
return rc;
}
+ wil_collect_fw_info(wil);
+
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
wil_ps_update(wil, wil->ps_profile);
if (wil->tt_data_set)
wmi_set_tt_cfg(wil, &wil->tt_data);
- wil_collect_fw_info(wil);
-
if (wil->platform_ops.notify) {
rc = wil->platform_ops.notify(wil->platform_handle,
WIL_PLATFORM_EVT_FW_RDY);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 42a5235..5432b31 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -84,9 +84,7 @@
/* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, wil->wil_fw_name, false);
-
- if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
- wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wil_refresh_fw_capabilities(wil);
}
void wil_disable_irq(struct wil6210_priv *wil)
@@ -289,15 +287,6 @@
wil_set_capabilities(wil);
wil6210_clear_irq(wil);
- wil->keep_radio_on_during_sleep =
- wil->platform_ops.keep_radio_on_during_sleep &&
- wil->platform_ops.keep_radio_on_during_sleep(
- wil->platform_handle) &&
- test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities);
-
- wil_info(wil, "keep_radio_on_during_sleep (%d)\n",
- wil->keep_radio_on_during_sleep);
-
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b4ca4e3..1c13b0b 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -272,6 +272,7 @@
#define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
#define RGF_HP_CTRL (0x88265c)
+#define RGF_PAL_UNIT_ICR (0x88266c) /* struct RGF_ICR */
#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
/* MAC timer, usec, for packet lifetime */
@@ -869,6 +870,7 @@
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
int __wil_down(struct wil6210_priv *wil);
+void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
void wil_set_ethtoolops(struct net_device *ndev);
@@ -951,8 +953,13 @@
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
+#if defined(CONFIG_WIL6210_DEBUGFS)
int wil6210_debugfs_init(struct wil6210_priv *wil);
void wil6210_debugfs_remove(struct wil6210_priv *wil);
+#else
+static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; }
+static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
+#endif
int wil6210_sysfs_init(struct wil6210_priv *wil);
void wil6210_sysfs_remove(struct wil6210_priv *wil);
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 1b426d7..5263ee7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -36,6 +36,11 @@
#define WMI_PROX_RANGE_NUM (3)
#define WMI_MAX_LOSS_DMG_BEACONS (20)
#define MAX_NUM_OF_SECTORS (128)
+#define WMI_SCHED_MAX_ALLOCS_PER_CMD (4)
+#define WMI_RF_DTYPE_LENGTH (3)
+#define WMI_RF_ETYPE_LENGTH (3)
+#define WMI_RF_RX2TX_LENGTH (3)
+#define WMI_RF_ETYPE_VAL_PER_RANGE (5)
/* Mailbox interface
* used for commands and events
@@ -52,15 +57,20 @@
* the host
*/
enum wmi_fw_capability {
- WMI_FW_CAPABILITY_FTM = 0,
- WMI_FW_CAPABILITY_PS_CONFIG = 1,
- WMI_FW_CAPABILITY_RF_SECTORS = 2,
- WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3,
- WMI_FW_CAPABILITY_DISABLE_AP_SME = 4,
- WMI_FW_CAPABILITY_WMI_ONLY = 5,
- WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7,
- WMI_FW_CAPABILITY_D3_SUSPEND = 8,
- WMI_FW_CAPABILITY_RSSI_REPORTING = 12,
+ WMI_FW_CAPABILITY_FTM = 0,
+ WMI_FW_CAPABILITY_PS_CONFIG = 1,
+ WMI_FW_CAPABILITY_RF_SECTORS = 2,
+ WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3,
+ WMI_FW_CAPABILITY_DISABLE_AP_SME = 4,
+ WMI_FW_CAPABILITY_WMI_ONLY = 5,
+ WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7,
+ WMI_FW_CAPABILITY_D3_SUSPEND = 8,
+ WMI_FW_CAPABILITY_LONG_RANGE = 9,
+ WMI_FW_CAPABILITY_FIXED_SCHEDULING = 10,
+ WMI_FW_CAPABILITY_MULTI_DIRECTED_OMNIS = 11,
+ WMI_FW_CAPABILITY_RSSI_REPORTING = 12,
+ WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13,
+ WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14,
WMI_FW_CAPABILITY_MAX,
};
@@ -80,6 +90,7 @@
WMI_START_SCAN_CMDID = 0x07,
WMI_SET_BSS_FILTER_CMDID = 0x09,
WMI_SET_PROBED_SSID_CMDID = 0x0A,
+ /* deprecated */
WMI_SET_LISTEN_INT_CMDID = 0x0B,
WMI_BCON_CTRL_CMDID = 0x0F,
WMI_ADD_CIPHER_KEY_CMDID = 0x16,
@@ -94,26 +105,28 @@
WMI_ECHO_CMDID = 0x803,
WMI_DEEP_ECHO_CMDID = 0x804,
WMI_CONFIG_MAC_CMDID = 0x805,
+ /* deprecated */
WMI_CONFIG_PHY_DEBUG_CMDID = 0x806,
WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808,
WMI_PHY_GET_STATISTICS_CMDID = 0x809,
+ /* deprecated */
WMI_FS_TUNE_CMDID = 0x80A,
+ /* deprecated */
WMI_CORR_MEASURE_CMDID = 0x80B,
WMI_READ_RSSI_CMDID = 0x80C,
WMI_TEMP_SENSE_CMDID = 0x80E,
WMI_DC_CALIB_CMDID = 0x80F,
+ /* deprecated */
WMI_SEND_TONE_CMDID = 0x810,
+ /* deprecated */
WMI_IQ_TX_CALIB_CMDID = 0x811,
+ /* deprecated */
WMI_IQ_RX_CALIB_CMDID = 0x812,
- WMI_SET_UCODE_IDLE_CMDID = 0x813,
WMI_SET_WORK_MODE_CMDID = 0x815,
WMI_LO_LEAKAGE_CALIB_CMDID = 0x816,
- WMI_MARLON_R_READ_CMDID = 0x818,
- WMI_MARLON_R_WRITE_CMDID = 0x819,
- WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A,
- MAC_IO_STATIC_PARAMS_CMDID = 0x81B,
- MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C,
+ WMI_LO_POWER_CALIB_FROM_OTP_CMDID = 0x817,
WMI_SILENT_RSSI_CALIB_CMDID = 0x81D,
+ /* deprecated */
WMI_RF_RX_TEST_CMDID = 0x81E,
WMI_CFG_RX_CHAIN_CMDID = 0x820,
WMI_VRING_CFG_CMDID = 0x821,
@@ -127,11 +140,6 @@
WMI_SET_PCP_CHANNEL_CMDID = 0x829,
WMI_GET_PCP_CHANNEL_CMDID = 0x82A,
WMI_SW_TX_REQ_CMDID = 0x82B,
- WMI_READ_MAC_RXQ_CMDID = 0x830,
- WMI_READ_MAC_TXQ_CMDID = 0x831,
- WMI_WRITE_MAC_RXQ_CMDID = 0x832,
- WMI_WRITE_MAC_TXQ_CMDID = 0x833,
- WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834,
WMI_MLME_PUSH_CMDID = 0x835,
WMI_BEAMFORMING_MGMT_CMDID = 0x836,
WMI_BF_TXSS_MGMT_CMDID = 0x837,
@@ -145,9 +153,13 @@
WMI_MAINTAIN_RESUME_CMDID = 0x851,
WMI_RS_MGMT_CMDID = 0x852,
WMI_RF_MGMT_CMDID = 0x853,
- WMI_OTP_READ_CMDID = 0x856,
- WMI_OTP_WRITE_CMDID = 0x857,
+ WMI_RF_XPM_READ_CMDID = 0x856,
+ WMI_RF_XPM_WRITE_CMDID = 0x857,
WMI_LED_CFG_CMDID = 0x858,
+ WMI_SET_CONNECT_SNR_THR_CMDID = 0x85B,
+ WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID = 0x85C,
+ WMI_RF_PWR_ON_DELAY_CMDID = 0x85D,
+ WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID = 0x85E,
/* Performance monitoring commands */
WMI_BF_CTRL_CMDID = 0x862,
WMI_NOTIFY_REQ_CMDID = 0x863,
@@ -155,7 +167,6 @@
WMI_GET_RF_STATUS_CMDID = 0x866,
WMI_GET_BASEBAND_TYPE_CMDID = 0x867,
WMI_UNIT_TEST_CMDID = 0x900,
- WMI_HICCUP_CMDID = 0x901,
WMI_FLASH_READ_CMDID = 0x902,
WMI_FLASH_WRITE_CMDID = 0x903,
/* Power management */
@@ -175,16 +186,6 @@
WMI_GET_PCP_FACTOR_CMDID = 0x91B,
/* Power Save Configuration Commands */
WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C,
- /* Not supported yet */
- WMI_PS_DEV_CFG_CMDID = 0x91D,
- /* Not supported yet */
- WMI_PS_DEV_CFG_READ_CMDID = 0x91E,
- /* Per MAC Power Save Configuration commands
- * Not supported yet
- */
- WMI_PS_MID_CFG_CMDID = 0x91F,
- /* Not supported yet */
- WMI_PS_MID_CFG_READ_CMDID = 0x920,
WMI_RS_CFG_CMDID = 0x921,
WMI_GET_DETAILED_RS_RES_CMDID = 0x922,
WMI_AOA_MEAS_CMDID = 0x923,
@@ -195,13 +196,16 @@
WMI_DEL_STA_CMDID = 0x936,
WMI_SET_THERMAL_THROTTLING_CFG_CMDID = 0x940,
WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941,
+ /* Read Power Save profile type */
+ WMI_PS_DEV_PROFILE_CFG_READ_CMDID = 0x942,
WMI_TOF_SESSION_START_CMDID = 0x991,
WMI_TOF_GET_CAPABILITIES_CMDID = 0x992,
WMI_TOF_SET_LCR_CMDID = 0x993,
WMI_TOF_SET_LCI_CMDID = 0x994,
- WMI_TOF_CHANNEL_INFO_CMDID = 0x995,
+ WMI_TOF_CFG_RESPONDER_CMDID = 0x996,
WMI_TOF_SET_TX_RX_OFFSET_CMDID = 0x997,
WMI_TOF_GET_TX_RX_OFFSET_CMDID = 0x998,
+ WMI_TOF_CHANNEL_INFO_CMDID = 0x999,
WMI_GET_RF_SECTOR_PARAMS_CMDID = 0x9A0,
WMI_SET_RF_SECTOR_PARAMS_CMDID = 0x9A1,
WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A2,
@@ -210,12 +214,20 @@
WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5,
WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6,
WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7,
+ WMI_SCHEDULING_SCHEME_CMDID = 0xA01,
+ WMI_FIXED_SCHEDULING_CONFIG_CMDID = 0xA02,
+ WMI_ENABLE_FIXED_SCHEDULING_CMDID = 0xA03,
+ WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID = 0xA04,
+ WMI_SET_LONG_RANGE_CONFIG_CMDID = 0xA05,
WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
WMI_ABORT_SCAN_CMDID = 0xF007,
WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
+ /* deprecated */
WMI_GET_PMK_CMDID = 0xF048,
WMI_SET_PASSPHRASE_CMDID = 0xF049,
+ /* deprecated */
WMI_SEND_ASSOC_RES_CMDID = 0xF04A,
+ /* deprecated */
WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B,
WMI_MAC_ADDR_REQ_CMDID = 0xF04D,
WMI_FW_VER_CMDID = 0xF04E,
@@ -441,11 +453,6 @@
__le32 rf_mgmt_type;
} __packed;
-/* WMI_RF_RX_TEST_CMDID */
-struct wmi_rf_rx_test_cmd {
- __le32 sector;
-} __packed;
-
/* WMI_CORR_MEASURE_CMDID */
struct wmi_corr_measure_cmd {
__le32 freq_mhz;
@@ -658,6 +665,20 @@
struct wmi_bcast_vring_cfg vring_cfg;
} __packed;
+/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */
+struct wmi_lo_power_calib_from_otp_cmd {
+ /* index to read from OTP. zero based */
+ u8 index;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */
+struct wmi_lo_power_calib_from_otp_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
/* WMI_VRING_BA_EN_CMDID */
struct wmi_vring_ba_en_cmd {
u8 ringid;
@@ -693,6 +714,24 @@
WMI_SNIFFER_ON = 0x01,
};
+/* WMI_SILENT_RSSI_TABLE */
+enum wmi_silent_rssi_table {
+ RF_TEMPERATURE_CALIB_DEFAULT_DB = 0x00,
+ RF_TEMPERATURE_CALIB_HIGH_POWER_DB = 0x01,
+};
+
+/* WMI_SILENT_RSSI_STATUS */
+enum wmi_silent_rssi_status {
+ SILENT_RSSI_SUCCESS = 0x00,
+ SILENT_RSSI_FAILURE = 0x01,
+};
+
+/* WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID */
+struct wmi_set_active_silent_rssi_table_cmd {
+ /* enum wmi_silent_rssi_table */
+ __le32 table;
+} __packed;
+
enum wmi_sniffer_cfg_phy_info_mode {
WMI_SNIFFER_PHY_INFO_DISABLED = 0x00,
WMI_SNIFFER_PHY_INFO_ENABLED = 0x01,
@@ -836,18 +875,85 @@
__le32 value;
} __packed;
-/* WMI_OTP_READ_CMDID */
-struct wmi_otp_read_cmd {
- __le32 addr;
- __le32 size;
- __le32 values;
+/* WMI_RF_PWR_ON_DELAY_CMDID
+ * set FW time parameters used through RF resetting
+ * RF reset consists of bringing its power down for a period of time, then
+ * bringing the power up
+ * Returned event: WMI_RF_PWR_ON_DELAY_RSP_EVENTID
+ */
+struct wmi_rf_pwr_on_delay_cmd {
+ /* time in usec the FW waits after bringing the RF PWR down,
+ * set 0 for default
+ */
+ __le16 down_delay_usec;
+ /* time in usec the FW waits after bringing the RF PWR up,
+ * set 0 for default
+ */
+ __le16 up_delay_usec;
} __packed;
-/* WMI_OTP_WRITE_CMDID */
-struct wmi_otp_write_cmd {
- __le32 addr;
- __le32 size;
- __le32 values;
+/* \WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID
+ * This API controls the Tx and Rx gain over temperature.
+ * It controls the Tx D-type, Rx D-type and Rx E-type amplifiers.
+ * It also controls the Tx gain index, by controlling the Rx to Tx gain index
+ * offset.
+ * The control is divided by 3 temperature values to 4 temperature ranges.
+ * Each parameter uses its own temperature values.
+ * Returned event: WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID
+ */
+struct wmi_set_high_power_table_params_cmd {
+ /* Temperature range for Tx D-type parameters */
+ u8 tx_dtype_temp[WMI_RF_DTYPE_LENGTH];
+ u8 reserved0;
+ /* Tx D-type values to be used for each temperature range */
+ __le32 tx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1];
+ /* Temperature range for Rx D-type parameters */
+ u8 rx_dtype_temp[WMI_RF_DTYPE_LENGTH];
+ u8 reserved1;
+ /* Rx D-type values to be used for each temperature range */
+ __le32 rx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1];
+ /* Temperature range for Rx E-type parameters */
+ u8 rx_etype_temp[WMI_RF_ETYPE_LENGTH];
+ u8 reserved2;
+ /* Rx E-type values to be used for each temperature range.
+ * The last 4 values of any range are the first 4 values of the next
+ * range and so on
+ */
+ __le32 rx_etype_conf[WMI_RF_ETYPE_VAL_PER_RANGE + WMI_RF_ETYPE_LENGTH];
+ /* Temperature range for rx_2_tx_offs parameters */
+ u8 rx_2_tx_temp[WMI_RF_RX2TX_LENGTH];
+ u8 reserved3;
+ /* Rx to Tx gain index offset */
+ s8 rx_2_tx_offs[WMI_RF_RX2TX_LENGTH + 1];
+} __packed;
+
+/* CMD: WMI_RF_XPM_READ_CMDID */
+struct wmi_rf_xpm_read_cmd {
+ u8 rf_id;
+ u8 reserved[3];
+ /* XPM bit start address in range [0,8191]bits - rounded by FW to
+ * multiple of 8bits
+ */
+ __le32 xpm_bit_address;
+ __le32 num_bytes;
+} __packed;
+
+/* CMD: WMI_RF_XPM_WRITE_CMDID */
+struct wmi_rf_xpm_write_cmd {
+ u8 rf_id;
+ u8 reserved0[3];
+ /* XPM bit start address in range [0,8191]bits - rounded by FW to
+ * multiple of 8bits
+ */
+ __le32 xpm_bit_address;
+ __le32 num_bytes;
+ /* boolean flag indicating whether FW should verify the write
+ * operation
+ */
+ u8 verify;
+ u8 reserved1[3];
+ /* actual size=num_bytes */
+ u8 data_bytes[0];
} __packed;
/* WMI_TEMP_SENSE_CMDID
@@ -990,19 +1096,26 @@
*/
__le16 burst_period;
u8 dst_mac[WMI_MAC_LEN];
- __le16 reserved;
+ u8 reserved;
+ u8 num_burst_per_aoa_meas;
} __packed;
/* WMI_TOF_SESSION_START_CMDID */
struct wmi_tof_session_start_cmd {
__le32 session_id;
- u8 num_of_aoa_measures;
+ u8 reserved1;
u8 aoa_type;
__le16 num_of_dest;
u8 reserved[4];
struct wmi_ftm_dest_info ftm_dest_info[0];
} __packed;
+/* WMI_TOF_CFG_RESPONDER_CMDID */
+struct wmi_tof_cfg_responder_cmd {
+ u8 enable;
+ u8 reserved[3];
+} __packed;
+
enum wmi_tof_channel_info_report_type {
WMI_TOF_CHANNEL_INFO_TYPE_CIR = 0x1,
WMI_TOF_CHANNEL_INFO_TYPE_RSSI = 0x2,
@@ -1023,7 +1136,99 @@
__le32 tx_offset;
/* RX delay offset */
__le32 rx_offset;
- __le32 reserved[2];
+ /* Mask to define which RFs to configure. 0 means all RFs */
+ __le32 rf_mask;
+ /* Offset to strongest tap of CIR */
+ __le32 precursor;
+} __packed;
+
+/* WMI_TOF_GET_TX_RX_OFFSET_CMDID */
+struct wmi_tof_get_tx_rx_offset_cmd {
+ /* rf index to read offsets from */
+ u8 rf_index;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */
+struct wmi_map_mcs_to_schd_params {
+ u8 mcs;
+ /* time in usec from start slot to start tx flow - default 15 */
+ u8 time_in_usec_before_initiate_tx;
+ /* RD enable - if yes consider RD according to STA mcs */
+ u8 rd_enabled;
+ u8 reserved;
+ /* time in usec from start slot to stop vring */
+ __le16 time_in_usec_to_stop_vring;
+ /* timeout to force flush from start of slot */
+ __le16 flush_to_in_usec;
+ /* per mcs the mac buffer limit size in bytes */
+ __le32 mac_buff_size_in_bytes;
+} __packed;
+
+/* WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID */
+struct wmi_fixed_scheduling_config_complete_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+#define WMI_NUM_MCS (13)
+
+/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */
+struct wmi_fixed_scheduling_config_cmd {
+ /* defaults in the SAS table */
+ struct wmi_map_mcs_to_schd_params mcs_to_schd_params_map[WMI_NUM_MCS];
+ /* default 150 uSec */
+ __le16 max_sta_rd_ppdu_duration_in_usec;
+ /* default 300 uSec */
+ __le16 max_sta_grant_ppdu_duration_in_usec;
+ /* default 1000 uSec */
+ __le16 assoc_slot_duration_in_usec;
+ /* default 360 uSec */
+ __le16 virtual_slot_duration_in_usec;
+ /* each this field value slots start with grant frame to the station
+ * - default 2
+ */
+ u8 number_of_ap_slots_for_initiate_grant;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_ENABLE_FIXED_SCHEDULING_CMDID */
+struct wmi_enable_fixed_scheduling_cmd {
+ __le32 reserved;
+} __packed;
+
+/* WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID */
+struct wmi_enable_fixed_scheduling_complete_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID */
+struct wmi_set_multi_directed_omnis_config_cmd {
+ /* number of directed omnis at destination AP */
+ u8 dest_ap_num_directed_omnis;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID */
+struct wmi_set_multi_directed_omnis_config_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_SET_LONG_RANGE_CONFIG_CMDID */
+struct wmi_set_long_range_config_cmd {
+ __le32 reserved;
+} __packed;
+
+/* WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID */
+struct wmi_set_long_range_config_complete_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
} __packed;
/* WMI Events
@@ -1039,19 +1244,22 @@
WMI_FW_READY_EVENTID = 0x1801,
WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200,
WMI_ECHO_RSP_EVENTID = 0x1803,
+ /* deprecated */
WMI_FS_TUNE_DONE_EVENTID = 0x180A,
+ /* deprecated */
WMI_CORR_MEASURE_EVENTID = 0x180B,
WMI_READ_RSSI_EVENTID = 0x180C,
WMI_TEMP_SENSE_DONE_EVENTID = 0x180E,
WMI_DC_CALIB_DONE_EVENTID = 0x180F,
+ /* deprecated */
WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811,
+ /* deprecated */
WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812,
WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815,
WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816,
- WMI_MARLON_R_READ_DONE_EVENTID = 0x1818,
- WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819,
- WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181A,
+ WMI_LO_POWER_CALIB_FROM_OTP_EVENTID = 0x1817,
WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181D,
+ /* deprecated */
WMI_RF_RX_TEST_DONE_EVENTID = 0x181E,
WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820,
WMI_VRING_CFG_DONE_EVENTID = 0x1821,
@@ -1062,11 +1270,6 @@
WMI_GET_SSID_EVENTID = 0x1828,
WMI_GET_PCP_CHANNEL_EVENTID = 0x182A,
WMI_SW_TX_COMPLETE_EVENTID = 0x182B,
- WMI_READ_MAC_RXQ_EVENTID = 0x1830,
- WMI_READ_MAC_TXQ_EVENTID = 0x1831,
- WMI_WRITE_MAC_RXQ_EVENTID = 0x1832,
- WMI_WRITE_MAC_TXQ_EVENTID = 0x1833,
- WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834,
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
@@ -1077,8 +1280,12 @@
WMI_TX_MGMT_PACKET_EVENTID = 0x1841,
WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID = 0x1842,
WMI_LINK_MAINTAIN_CFG_READ_DONE_EVENTID = 0x1843,
- WMI_OTP_READ_RESULT_EVENTID = 0x1856,
+ WMI_RF_XPM_READ_RESULT_EVENTID = 0x1856,
+ WMI_RF_XPM_WRITE_RESULT_EVENTID = 0x1857,
WMI_LED_CFG_DONE_EVENTID = 0x1858,
+ WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID = 0x185C,
+ WMI_RF_PWR_ON_DELAY_RSP_EVENTID = 0x185D,
+ WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID = 0x185E,
/* Performance monitoring events */
WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
WMI_WBE_LINK_DOWN_EVENTID = 0x1861,
@@ -1107,14 +1314,6 @@
WMI_PCP_FACTOR_EVENTID = 0x191A,
/* Power Save Configuration Events */
WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C,
- /* Not supported yet */
- WMI_PS_DEV_CFG_EVENTID = 0x191D,
- /* Not supported yet */
- WMI_PS_DEV_CFG_READ_EVENTID = 0x191E,
- /* Not supported yet */
- WMI_PS_MID_CFG_EVENTID = 0x191F,
- /* Not supported yet */
- WMI_PS_MID_CFG_READ_EVENTID = 0x1920,
WMI_RS_CFG_DONE_EVENTID = 0x1921,
WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922,
WMI_AOA_MEAS_EVENTID = 0x1923,
@@ -1123,14 +1322,17 @@
WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931,
WMI_SET_THERMAL_THROTTLING_CFG_EVENTID = 0x1940,
WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941,
+ /* return the Power Save profile */
+ WMI_PS_DEV_PROFILE_CFG_READ_EVENTID = 0x1942,
WMI_TOF_SESSION_END_EVENTID = 0x1991,
WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992,
WMI_TOF_SET_LCR_EVENTID = 0x1993,
WMI_TOF_SET_LCI_EVENTID = 0x1994,
WMI_TOF_FTM_PER_DEST_RES_EVENTID = 0x1995,
- WMI_TOF_CHANNEL_INFO_EVENTID = 0x1996,
+ WMI_TOF_CFG_RESPONDER_EVENTID = 0x1996,
WMI_TOF_SET_TX_RX_OFFSET_EVENTID = 0x1997,
WMI_TOF_GET_TX_RX_OFFSET_EVENTID = 0x1998,
+ WMI_TOF_CHANNEL_INFO_EVENTID = 0x1999,
WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A0,
WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A1,
WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A2,
@@ -1139,12 +1341,18 @@
WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5,
WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6,
WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7,
+ WMI_SCHEDULING_SCHEME_EVENTID = 0x1A01,
+ WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID = 0x1A02,
+ WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID = 0x1A03,
+ WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID = 0x1A04,
+ WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID = 0x1A05,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
WMI_MAC_ADDR_RESP_EVENTID = 0x9003,
WMI_FW_VER_EVENTID = 0x9004,
WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID = 0x9005,
+ WMI_COMMAND_NOT_SUPPORTED_EVENTID = 0xFFFF,
};
/* Events data structures */
@@ -1201,7 +1409,7 @@
__le32 bl_minor;
__le32 bl_subminor;
__le32 bl_build;
- /* The number of entries in the FW capabilies array */
+ /* The number of entries in the FW capabilities array */
u8 fw_capabilities_len;
u8 reserved[3];
/* FW capabilities info
@@ -1246,7 +1454,9 @@
__le32 board_file_platform_type;
/* board file version */
__le32 board_file_version;
- __le32 reserved[2];
+ /* enabled XIFs bit vector */
+ __le32 enabled_xif_vector;
+ __le32 reserved;
} __packed;
/* WMI_GET_BASEBAND_TYPE_EVENTID */
@@ -1300,6 +1510,7 @@
/* enum wmi_phy_capability */
u8 phy_capability;
u8 numof_additional_mids;
+ /* rfc read calibration result. 5..15 */
u8 rfc_read_calib_result;
u8 reserved[3];
} __packed;
@@ -1580,7 +1791,7 @@
u8 reserved[3];
} __packed;
-/* WMI_CORR_MEASURE_EVENTID */
+/* WMI_CORR_MEASURE_EVENTID - deprecated */
struct wmi_corr_measure_event {
/* signed */
__le32 i;
@@ -1612,25 +1823,29 @@
__le16 stype;
__le16 status;
__le32 len;
- /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */
+ /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */
u8 qid;
- /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */
+ /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */
u8 mid;
u8 cid;
/* From Radio MNGR */
u8 channel;
} __packed;
-/* wmi_otp_read_write_cmd */
-struct wmi_otp_read_write_cmd {
- __le32 addr;
- __le32 size;
- u8 values[0];
+/* EVENT: WMI_RF_XPM_READ_RESULT_EVENTID */
+struct wmi_rf_xpm_read_result_event {
+ /* enum wmi_fw_status_e - success=0 or fail=1 */
+ u8 status;
+ u8 reserved[3];
+ /* requested num_bytes of data */
+ u8 data_bytes[0];
} __packed;
-/* WMI_OTP_READ_RESULT_EVENTID */
-struct wmi_otp_read_result_event {
- u8 payload[0];
+/* EVENT: WMI_RF_XPM_WRITE_RESULT_EVENTID */
+struct wmi_rf_xpm_write_result_event {
+ /* enum wmi_fw_status_e - success=0 or fail=1 */
+ u8 status;
+ u8 reserved[3];
} __packed;
/* WMI_TX_MGMT_PACKET_EVENTID */
@@ -1649,6 +1864,20 @@
__le32 echoed_value;
} __packed;
+/* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */
+struct wmi_rf_pwr_on_delay_rsp_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID */
+struct wmi_set_high_power_table_params_event {
+ /* wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
/* WMI_TEMP_SENSE_DONE_EVENTID
*
* Measure MAC and radio temperatures
@@ -1726,14 +1955,22 @@
u8 reserved;
} __packed;
+/* \WMI_SET_CONNECT_SNR_THR_CMDID */
+struct wmi_set_connect_snr_thr_cmd {
+ u8 enable;
+ u8 reserved;
+ /* 1/4 Db units */
+ __le16 omni_snr_thr;
+ /* 1/4 Db units */
+ __le16 direct_snr_thr;
+} __packed;
+
/* WMI_LED_CFG_DONE_EVENTID */
struct wmi_led_cfg_done_event {
/* led config status */
__le32 status;
} __packed;
-#define WMI_NUM_MCS (13)
-
/* Rate search parameters configuration per connection */
struct wmi_rs_cfg {
/* The maximal allowed PER for each MCS
@@ -1758,6 +1995,98 @@
__le32 mcs_en_vec;
} __packed;
+/* Slot types */
+enum wmi_sched_scheme_slot_type {
+ WMI_SCHED_SLOT_SP = 0x0,
+ WMI_SCHED_SLOT_CBAP = 0x1,
+ WMI_SCHED_SLOT_IDLE = 0x2,
+ WMI_SCHED_SLOT_ANNOUNCE_NO_ACK = 0x3,
+ WMI_SCHED_SLOT_DISCOVERY = 0x4,
+};
+
+enum wmi_sched_scheme_slot_flags {
+ WMI_SCHED_SCHEME_SLOT_PERIODIC = 0x1,
+};
+
+struct wmi_sched_scheme_slot {
+ /* in microsecond */
+ __le32 tbtt_offset;
+ /* wmi_sched_scheme_slot_flags */
+ u8 flags;
+ /* wmi_sched_scheme_slot_type */
+ u8 type;
+ /* in microsecond */
+ __le16 duration;
+ /* frame_exchange_sequence_duration */
+ __le16 tx_op;
+ /* time in microseconds between two consecutive slots
+ * relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+ */
+ __le16 period;
+ /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+ * number of times to repeat allocation
+ */
+ u8 num_of_blocks;
+ /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+ * every idle_period allocation will be idle
+ */
+ u8 idle_period;
+ u8 src_aid;
+ u8 dest_aid;
+ __le32 reserved;
+} __packed;
+
+enum wmi_sched_scheme_flags {
+ /* should not be set when clearing scheduling scheme */
+ WMI_SCHED_SCHEME_ENABLE = 0x01,
+ WMI_SCHED_PROTECTED_SP = 0x02,
+ /* should be set only on first WMI fragment of scheme */
+ WMI_SCHED_FIRST = 0x04,
+ /* should be set only on last WMI fragment of scheme */
+ WMI_SCHED_LAST = 0x08,
+ WMI_SCHED_IMMEDIATE_START = 0x10,
+};
+
+enum wmi_sched_scheme_advertisment {
+ /* ESE is not advertised at all, STA has to be configured with WMI
+ * also
+ */
+ WMI_ADVERTISE_ESE_DISABLED = 0x0,
+ WMI_ADVERTISE_ESE_IN_BEACON = 0x1,
+ WMI_ADVERTISE_ESE_IN_ANNOUNCE_FRAME = 0x2,
+};
+
+/* WMI_SCHEDULING_SCHEME_CMD */
+struct wmi_scheduling_scheme_cmd {
+ u8 serial_num;
+ /* wmi_sched_scheme_advertisment */
+ u8 ese_advertisment;
+ /* wmi_sched_scheme_flags */
+ __le16 flags;
+ u8 num_allocs;
+ u8 reserved[3];
+ __le64 start_tbtt;
+ /* allocations list */
+ struct wmi_sched_scheme_slot allocs[WMI_SCHED_MAX_ALLOCS_PER_CMD];
+} __packed;
+
+enum wmi_sched_scheme_failure_type {
+ WMI_SCHED_SCHEME_FAILURE_NO_ERROR = 0x00,
+ WMI_SCHED_SCHEME_FAILURE_OLD_START_TSF_ERR = 0x01,
+};
+
+/* WMI_SCHEDULING_SCHEME_EVENTID */
+struct wmi_scheduling_scheme_event {
+ /* wmi_fw_status_e */
+ u8 status;
+ /* serial number given in command */
+ u8 serial_num;
+ /* wmi_sched_scheme_failure_type */
+ u8 failure_type;
+ /* alignment to 32b */
+ u8 reserved[1];
+} __packed;
+
/* WMI_RS_CFG_CMDID */
struct wmi_rs_cfg_cmd {
/* connection id */
@@ -1975,6 +2304,19 @@
WMI_PS_PROFILE_TYPE_LOW_LATENCY_PS = 0x03,
};
+/* WMI_PS_DEV_PROFILE_CFG_READ_CMDID */
+struct wmi_ps_dev_profile_cfg_read_cmd {
+ /* reserved */
+ __le32 reserved;
+} __packed;
+
+/* WMI_PS_DEV_PROFILE_CFG_READ_EVENTID */
+struct wmi_ps_dev_profile_cfg_read_event {
+ /* wmi_ps_profile_type_e */
+ u8 ps_profile;
+ u8 reserved[3];
+} __packed;
+
/* WMI_PS_DEV_PROFILE_CFG_CMDID
*
* Power save profile to be used by the device
@@ -2023,157 +2365,6 @@
WMI_PS_D3_RESP_POLICY_APPROVED = 0x02,
};
-/* Device common power save configurations */
-struct wmi_ps_dev_cfg {
- /* lowest level of PS allowed while unassociated, enum wmi_ps_level_e
- */
- u8 ps_unassoc_min_level;
- /* lowest deep sleep clock level while nonassoc, enum
- * wmi_ps_deep_sleep_clk_level_e
- */
- u8 ps_unassoc_deep_sleep_min_level;
- /* lowest level of PS allowed while associated, enum wmi_ps_level_e */
- u8 ps_assoc_min_level;
- /* lowest deep sleep clock level while assoc, enum
- * wmi_ps_deep_sleep_clk_level_e
- */
- u8 ps_assoc_deep_sleep_min_level;
- /* enum wmi_ps_deep_sleep_clk_level_e */
- u8 ps_assoc_low_latency_ds_min_level;
- /* enum wmi_ps_d3_resp_policy_e */
- u8 ps_D3_response_policy;
- /* BOOL */
- u8 ps_D3_pm_pme_enabled;
- /* BOOL */
- u8 ps_halp_enable;
- u8 ps_deep_sleep_enter_thresh_msec;
- /* BOOL */
- u8 ps_voltage_scaling_en;
-} __packed;
-
-/* WMI_PS_DEV_CFG_CMDID
- *
- * Configure common Power Save parameters of the device and all MIDs.
- *
- * Returned event:
- * - WMI_PS_DEV_CFG_EVENTID
- */
-struct wmi_ps_dev_cfg_cmd {
- /* Device Power Save configuration to be applied */
- struct wmi_ps_dev_cfg ps_dev_cfg;
- /* alignment to 32b */
- u8 reserved[2];
-} __packed;
-
-/* WMI_PS_DEV_CFG_EVENTID */
-struct wmi_ps_dev_cfg_event {
- /* wmi_ps_cfg_cmd_status_e */
- __le32 status;
-} __packed;
-
-/* WMI_PS_DEV_CFG_READ_CMDID
- *
- * request to retrieve device Power Save configuration
- * (WMI_PS_DEV_CFG_CMD params)
- *
- * Returned event:
- * - WMI_PS_DEV_CFG_READ_EVENTID
- */
-struct wmi_ps_dev_cfg_read_cmd {
- __le32 reserved;
-} __packed;
-
-/* WMI_PS_DEV_CFG_READ_EVENTID */
-struct wmi_ps_dev_cfg_read_event {
- /* wmi_ps_cfg_cmd_status_e */
- __le32 status;
- /* Retrieved device Power Save configuration (WMI_PS_DEV_CFG_CMD
- * params)
- */
- struct wmi_ps_dev_cfg dev_ps_cfg;
- /* alignment to 32b */
- u8 reserved[2];
-} __packed;
-
-/* Per Mac Power Save configurations */
-struct wmi_ps_mid_cfg {
- /* Low power RX in BTI is enabled, BOOL */
- u8 beacon_lprx_enable;
- /* Sync to sector ID enabled, BOOL */
- u8 beacon_sync_to_sectorId_enable;
- /* Low power RX in DTI is enabled, BOOL */
- u8 frame_exchange_lprx_enable;
- /* Sleep Cycle while in scheduled PS, 1-31 */
- u8 scheduled_sleep_cycle_pow2;
- /* Stay Awake for k BIs every (sleep_cycle - k) BIs, 1-31 */
- u8 scheduled_num_of_awake_bis;
- u8 am_to_traffic_load_thresh_mbp;
- u8 traffic_to_am_load_thresh_mbps;
- u8 traffic_to_am_num_of_no_traffic_bis;
- /* BOOL */
- u8 continuous_traffic_psm;
- __le16 no_traffic_to_min_usec;
- __le16 no_traffic_to_max_usec;
- __le16 snoozing_sleep_interval_milisec;
- u8 max_no_data_awake_events;
- /* Trigger WEB after k failed beacons */
- u8 num_of_failed_beacons_rx_to_trigger_web;
- /* Trigger BF after k failed beacons */
- u8 num_of_failed_beacons_rx_to_trigger_bf;
- /* Trigger SOB after k successful beacons */
- u8 num_of_successful_beacons_rx_to_trigger_sob;
-} __packed;
-
-/* WMI_PS_MID_CFG_CMDID
- *
- * Configure Power Save parameters of a specific MID.
- * These parameters are relevant for the specific BSS this MID belongs to.
- *
- * Returned event:
- * - WMI_PS_MID_CFG_EVENTID
- */
-struct wmi_ps_mid_cfg_cmd {
- /* MAC ID */
- u8 mid;
- /* mid PS configuration to be applied */
- struct wmi_ps_mid_cfg ps_mid_cfg;
-} __packed;
-
-/* WMI_PS_MID_CFG_EVENTID */
-struct wmi_ps_mid_cfg_event {
- /* MAC ID */
- u8 mid;
- /* alignment to 32b */
- u8 reserved[3];
- /* wmi_ps_cfg_cmd_status_e */
- __le32 status;
-} __packed;
-
-/* WMI_PS_MID_CFG_READ_CMDID
- *
- * request to retrieve Power Save configuration of mid
- * (WMI_PS_MID_CFG_CMD params)
- *
- * Returned event:
- * - WMI_PS_MID_CFG_READ_EVENTID
- */
-struct wmi_ps_mid_cfg_read_cmd {
- /* MAC ID */
- u8 mid;
- /* alignment to 32b */
- u8 reserved[3];
-} __packed;
-
-/* WMI_PS_MID_CFG_READ_EVENTID */
-struct wmi_ps_mid_cfg_read_event {
- /* MAC ID */
- u8 mid;
- /* Retrieved MID Power Save configuration(WMI_PS_MID_CFG_CMD params) */
- struct wmi_ps_mid_cfg mid_ps_cfg;
- /* wmi_ps_cfg_cmd_status_e */
- __le32 status;
-} __packed;
-
#define WMI_AOA_MAX_DATA_SIZE (128)
enum wmi_aoa_meas_status {
@@ -2264,6 +2455,20 @@
u8 reserved[3];
} __packed;
+/* WMI_TOF_SET_LCI_EVENTID */
+struct wmi_tof_set_lci_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_TOF_SET_LCR_EVENTID */
+struct wmi_tof_set_lcr_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
/* Responder FTM Results */
struct wmi_responder_ftm_res {
u8 t1[6];
@@ -2317,10 +2522,19 @@
__le32 tsf_sync;
/* actual received ftm per burst */
u8 actual_ftm_per_burst;
- u8 reserved0[7];
+ /* Measurments are from RFs, defined by the mask */
+ __le32 meas_rf_mask;
+ u8 reserved0[3];
struct wmi_responder_ftm_res responder_ftm_res[0];
} __packed;
+/* WMI_TOF_CFG_RESPONDER_EVENTID */
+struct wmi_tof_cfg_responder_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
enum wmi_tof_channel_info_type {
WMI_TOF_CHANNEL_INFO_AOA = 0x00,
WMI_TOF_CHANNEL_INFO_LCI = 0x01,
@@ -2357,12 +2571,15 @@
struct wmi_tof_get_tx_rx_offset_event {
/* enum wmi_fw_status */
u8 status;
- u8 reserved1[3];
+ /* RF index used to read the offsets */
+ u8 rf_index;
+ u8 reserved1[2];
/* TX delay offset */
__le32 tx_offset;
/* RX delay offset */
__le32 rx_offset;
- __le32 reserved2[2];
+ /* Offset to strongest tap of CIR */
+ __le32 precursor;
} __packed;
/* Result status codes for WMI commands */
@@ -2625,4 +2842,23 @@
u8 reserved[3];
} __packed;
+/* WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID */
+struct wmi_set_silent_rssi_table_done_event {
+ /* enum wmi_silent_rssi_status */
+ __le32 status;
+ /* enum wmi_silent_rssi_table */
+ __le32 table;
+} __packed;
+
+/* \WMI_COMMAND_NOT_SUPPORTED_EVENTID */
+struct wmi_command_not_supported_event {
+ /* device id */
+ u8 mid;
+ u8 reserved0;
+ __le16 command_id;
+ /* for UT command only, otherwise reserved */
+ __le16 command_subtype;
+ __le16 reserved1;
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b85398c..261a0da 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5419,6 +5419,7 @@
struct ieee80211_supported_band *band;
struct brcmf_bss_info_le *bi;
struct brcmu_chan ch;
+ struct cfg80211_roam_info roam_info = {};
u32 freq;
s32 err = 0;
u8 *buf;
@@ -5457,9 +5458,15 @@
done:
kfree(buf);
- cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+
+ roam_info.channel = notify_channel;
+ roam_info.bssid = profile->bssid;
+ roam_info.req_ie = conn_info->req_ie;
+ roam_info.req_ie_len = conn_info->req_ie_len;
+ roam_info.resp_ie = conn_info->resp_ie;
+ roam_info.resp_ie_len = conn_info->resp_ie_len;
+
+ cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
brcmf_dbg(CONN, "Report roaming result\n");
set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 8744b9b..8e3c6f4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4161,11 +4161,6 @@
goto fail;
}
- /* allocate scatter-gather table. sg support
- * will be disabled upon allocation failure.
- */
- brcmf_sdiod_sgtable_alloc(bus->sdiodev);
-
/* Query the F2 block size, set roundup accordingly */
bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
bus->roundup = min(max_roundup, bus->blocksize);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
index 4b97371..838946d 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
@@ -1190,11 +1190,11 @@
next_reclaimed;
IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
next_reclaimed);
+ iwlagn_check_ratid_empty(priv, sta_id, tid);
}
iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
- iwlagn_check_ratid_empty(priv, sta_id, tid);
freed = 0;
/* process frames */
diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c
index 257a9ea..4ac6764 100644
--- a/drivers/net/wireless/intersil/p54/fwio.c
+++ b/drivers/net/wireless/intersil/p54/fwio.c
@@ -488,7 +488,7 @@
entry += sizeof(__le16);
chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memset(chan->curve_data, 0, sizeof(chan->curve_data));
memcpy(chan->curve_data, entry,
sizeof(struct p54_pa_curve_data_sample) *
min((u8)8, curve_data->points_per_channel));
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..280196a 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2830,15 +2830,22 @@
}
if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- if (!roamed)
+ if (!roamed) {
cfg80211_connect_result(usbdev->net, bssid, req_ie,
req_ie_len, resp_ie,
resp_ie_len, 0, GFP_KERNEL);
- else
- cfg80211_roamed(usbdev->net,
- get_current_channel(usbdev, NULL),
- bssid, req_ie, req_ie_len,
- resp_ie, resp_ie_len, GFP_KERNEL);
+ } else {
+ struct cfg80211_roam_info roam_info = {
+ .channel = get_current_channel(usbdev, NULL),
+ .bssid = bssid,
+ .req_ie = req_ie,
+ .req_ie_len = req_ie_len,
+ .resp_ie = resp_ie,
+ .resp_ie_len = resp_ie_len,
+ };
+
+ cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL);
+ }
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid,
get_current_channel(usbdev, NULL),
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index bbf7604..1c539c8 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1571,6 +1571,7 @@
wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
+ spin_lock_init(&wl->wl_lock);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 3ce1f7d..cb7365b 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -199,6 +199,7 @@
unsigned long remaining_credit;
struct timer_list credit_timeout;
u64 credit_window_start;
+ bool rate_limited;
/* Statistics */
struct xenvif_stats stats;
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index b009d79..5bfaf55 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -105,7 +105,11 @@
if (work_done < budget) {
napi_complete(napi);
- xenvif_napi_schedule_or_enable_events(queue);
+ /* If the queue is rate-limited, it shall be
+ * rescheduled in the timer callback.
+ */
+ if (likely(!queue->rate_limited))
+ xenvif_napi_schedule_or_enable_events(queue);
}
return work_done;
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 47b4810..d9b5b73 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -179,6 +179,7 @@
max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
queue->remaining_credit = min(max_credit, max_burst);
+ queue->rate_limited = false;
}
void xenvif_tx_credit_callback(unsigned long data)
@@ -685,8 +686,10 @@
msecs_to_jiffies(queue->credit_usec / 1000);
/* Timer could already be pending in rare cases. */
- if (timer_pending(&queue->credit_timeout))
+ if (timer_pending(&queue->credit_timeout)) {
+ queue->rate_limited = true;
return true;
+ }
/* Passed the point where we can replenish credit? */
if (time_after_eq64(now, next_credit)) {
@@ -701,6 +704,7 @@
mod_timer(&queue->credit_timeout,
next_credit);
queue->credit_window_start = next_credit;
+ queue->rate_limited = true;
return true;
}
diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c
index 712936f..fbd26ec 100644
--- a/drivers/nfc/fdp/i2c.c
+++ b/drivers/nfc/fdp/i2c.c
@@ -177,6 +177,16 @@
/* Packet that contains a length */
if (tmp[0] == 0 && tmp[1] == 0) {
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
+ /*
+ * Ensure next_read_size does not exceed sizeof(tmp)
+ * for reading that many bytes during next iteration
+ */
+ if (phy->next_read_size > FDP_NCI_I2C_MAX_PAYLOAD) {
+ dev_dbg(&client->dev, "%s: corrupted packet\n",
+ __func__);
+ phy->next_read_size = 5;
+ goto flush;
+ }
} else {
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
diff --git a/drivers/nfc/st21nfca/dep.c b/drivers/nfc/st21nfca/dep.c
index 798a32b..2062852 100644
--- a/drivers/nfc/st21nfca/dep.c
+++ b/drivers/nfc/st21nfca/dep.c
@@ -217,7 +217,8 @@
atr_req = (struct st21nfca_atr_req *)skb->data;
- if (atr_req->length < sizeof(struct st21nfca_atr_req)) {
+ if (atr_req->length < sizeof(struct st21nfca_atr_req) ||
+ atr_req->length > skb->len) {
r = -EPROTO;
goto exit;
}
diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c
index 3a98563..6e84e12 100644
--- a/drivers/nfc/st21nfca/se.c
+++ b/drivers/nfc/st21nfca/se.c
@@ -320,23 +320,33 @@
* AID 81 5 to 16
* PARAMETERS 82 0 to 255
*/
- if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
+ if (skb->len < NFC_MIN_AID_LENGTH + 2 ||
skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
return -EPROTO;
+ /*
+ * Buffer should have enough space for at least
+ * two tag fields + two length fields + aid_len (skb->data[1])
+ */
+ if (skb->len < skb->data[1] + 4)
+ return -EPROTO;
+
transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
skb->len - 2, GFP_KERNEL);
transaction->aid_len = skb->data[1];
memcpy(transaction->aid, &skb->data[2],
transaction->aid_len);
-
- /* Check next byte is PARAMETERS tag (82) */
- if (skb->data[transaction->aid_len + 2] !=
- NFC_EVT_TRANSACTION_PARAMS_TAG)
- return -EPROTO;
-
transaction->params_len = skb->data[transaction->aid_len + 3];
+
+ /* Check next byte is PARAMETERS tag (82) and the length field */
+ if (skb->data[transaction->aid_len + 2] !=
+ NFC_EVT_TRANSACTION_PARAMS_TAG ||
+ skb->len < transaction->aid_len + transaction->params_len + 4) {
+ devm_kfree(dev, transaction);
+ return -EPROTO;
+ }
+
memcpy(transaction->params, skb->data +
transaction->aid_len + 4, transaction->params_len);
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index c234ee43..24222a5 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -176,14 +176,12 @@
u64 rx_err_ver;
u64 rx_memcpy;
u64 rx_async;
- u64 dma_rx_prep_err;
u64 tx_bytes;
u64 tx_pkts;
u64 tx_ring_full;
u64 tx_err_no_buf;
u64 tx_memcpy;
u64 tx_async;
- u64 dma_tx_prep_err;
};
struct ntb_transport_mw {
@@ -256,8 +254,6 @@
#define QP_TO_MW(nt, qp) ((qp) % nt->mw_count)
#define NTB_QP_DEF_NUM_ENTRIES 100
#define NTB_LINK_DOWN_TIMEOUT 10
-#define DMA_RETRIES 20
-#define DMA_OUT_RESOURCE_TO msecs_to_jiffies(50)
static void ntb_transport_rxc_db(unsigned long data);
static const struct ntb_ctx_ops ntb_transport_ops;
@@ -518,12 +514,6 @@
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"free tx - \t%u\n",
ntb_transport_tx_free_entry(qp));
- out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "DMA tx prep err - \t%llu\n",
- qp->dma_tx_prep_err);
- out_offset += snprintf(buf + out_offset, out_count - out_offset,
- "DMA rx prep err - \t%llu\n",
- qp->dma_rx_prep_err);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"\n");
@@ -625,7 +615,7 @@
if (!mw->virt_addr)
return -ENOMEM;
- if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+ if (mw_num < qp_count % mw_count)
num_qps_mw = qp_count / mw_count + 1;
else
num_qps_mw = qp_count / mw_count;
@@ -770,8 +760,6 @@
qp->tx_err_no_buf = 0;
qp->tx_memcpy = 0;
qp->tx_async = 0;
- qp->dma_tx_prep_err = 0;
- qp->dma_rx_prep_err = 0;
}
static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp)
@@ -933,10 +921,8 @@
ntb_free_mw(nt, i);
/* if there's an actual failure, we should just bail */
- if (rc < 0) {
- ntb_link_disable(ndev);
+ if (rc < 0)
return;
- }
out:
if (ntb_link_is_up(ndev, NULL, NULL) == 1)
@@ -1002,7 +988,7 @@
qp->event_handler = NULL;
ntb_qp_link_down_reset(qp);
- if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count)
+ if (mw_num < qp_count % mw_count)
num_qps_mw = qp_count / mw_count + 1;
else
num_qps_mw = qp_count / mw_count;
@@ -1125,8 +1111,8 @@
qp_count = ilog2(qp_bitmap);
if (max_num_clients && max_num_clients < qp_count)
qp_count = max_num_clients;
- else if (mw_count < qp_count)
- qp_count = mw_count;
+ else if (nt->mw_count < qp_count)
+ qp_count = nt->mw_count;
qp_bitmap &= BIT_ULL(qp_count) - 1;
@@ -1314,7 +1300,6 @@
struct dmaengine_unmap_data *unmap;
dma_cookie_t cookie;
void *buf = entry->buf;
- int retries = 0;
len = entry->len;
device = chan->device;
@@ -1343,22 +1328,11 @@
unmap->from_cnt = 1;
- for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan,
- unmap->addr[1],
- unmap->addr[0], len,
- DMA_PREP_INTERRUPT);
- if (txd)
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(DMA_OUT_RESOURCE_TO);
- }
-
- if (!txd) {
- qp->dma_rx_prep_err++;
+ txd = device->device_prep_dma_memcpy(chan, unmap->addr[1],
+ unmap->addr[0], len,
+ DMA_PREP_INTERRUPT);
+ if (!txd)
goto err_get_unmap;
- }
txd->callback_result = ntb_rx_copy_callback;
txd->callback_param = entry;
@@ -1603,7 +1577,6 @@
struct dmaengine_unmap_data *unmap;
dma_addr_t dest;
dma_cookie_t cookie;
- int retries = 0;
device = chan->device;
dest = qp->tx_mw_phys + qp->tx_max_frame * entry->tx_index;
@@ -1625,21 +1598,10 @@
unmap->to_cnt = 1;
- for (retries = 0; retries < DMA_RETRIES; retries++) {
- txd = device->device_prep_dma_memcpy(chan, dest,
- unmap->addr[0], len,
- DMA_PREP_INTERRUPT);
- if (txd)
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(DMA_OUT_RESOURCE_TO);
- }
-
- if (!txd) {
- qp->dma_tx_prep_err++;
+ txd = device->device_prep_dma_memcpy(chan, dest, unmap->addr[0], len,
+ DMA_PREP_INTERRUPT);
+ if (!txd)
goto err_get_unmap;
- }
txd->callback_result = ntb_tx_copy_callback;
txd->callback_param = entry;
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 5c63b92..ed92c12 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -956,7 +956,7 @@
dino_dev->hba.dev = dev;
dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
- dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */
+ dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
spin_lock_init(&dino_dev->dinosaur_pen);
dino_dev->hba.iommu = ccio_get_iommu(dev);
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
index 9931be6..04d6fd2 100644
--- a/drivers/pinctrl/intel/pinctrl-merrifield.c
+++ b/drivers/pinctrl/intel/pinctrl-merrifield.c
@@ -343,9 +343,9 @@
static const unsigned int mrfld_sdio_pins[] = { 50, 51, 52, 53, 54, 55, 56 };
static const unsigned int mrfld_spi5_pins[] = { 90, 91, 92, 93, 94, 95, 96 };
-static const unsigned int mrfld_uart0_pins[] = { 124, 125, 126, 127 };
-static const unsigned int mrfld_uart1_pins[] = { 128, 129, 130, 131 };
-static const unsigned int mrfld_uart2_pins[] = { 132, 133, 134, 135 };
+static const unsigned int mrfld_uart0_pins[] = { 115, 116, 117, 118 };
+static const unsigned int mrfld_uart1_pins[] = { 119, 120, 121, 122 };
+static const unsigned int mrfld_uart2_pins[] = { 123, 124, 125, 126 };
static const unsigned int mrfld_pwm0_pins[] = { 144 };
static const unsigned int mrfld_pwm1_pins[] = { 145 };
static const unsigned int mrfld_pwm2_pins[] = { 132 };
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index c3928aa..7511723 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -85,6 +85,7 @@
MESON_PIN(GPIODV_15, EE_OFF),
MESON_PIN(GPIODV_16, EE_OFF),
MESON_PIN(GPIODV_17, EE_OFF),
+ MESON_PIN(GPIODV_18, EE_OFF),
MESON_PIN(GPIODV_19, EE_OFF),
MESON_PIN(GPIODV_20, EE_OFF),
MESON_PIN(GPIODV_21, EE_OFF),
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index d32fa2b..e8aee6d 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -195,8 +195,6 @@
spin_unlock_irqrestore(&bank->slock, flags);
- exynos_irq_unmask(irqd);
-
return 0;
}
@@ -217,8 +215,6 @@
shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
- exynos_irq_mask(irqd);
-
spin_lock_irqsave(&bank->slock, flags);
con = readl(d->virt_base + reg_con);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
index 862a096..be5c71d 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun4i-a10.c
@@ -811,6 +811,7 @@
SUNXI_FUNCTION(0x2, "lcd1"), /* D16 */
SUNXI_FUNCTION(0x3, "pata"), /* ATAD12 */
SUNXI_FUNCTION(0x4, "keypad"), /* IN6 */
+ SUNXI_FUNCTION(0x5, "sim"), /* DET */
SUNXI_FUNCTION_IRQ(0x6, 16), /* EINT16 */
SUNXI_FUNCTION(0x7, "csi1")), /* D16 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
index 77a0236..b190904 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
@@ -508,57 +508,71 @@
static const int usb1_muxvals[] = {0, 0};
static const unsigned usb2_pins[] = {50, 51};
static const int usb2_muxvals[] = {0, 0};
-static const unsigned port_range_pins[] = {
+static const unsigned port_range0_pins[] = {
159, 160, 161, 162, 163, 164, 165, 166, /* PORT0x */
0, 1, 2, 3, 4, 5, 6, 7, /* PORT1x */
8, 9, 10, 11, 12, 13, 14, 15, /* PORT2x */
- 16, 17, 18, -1, -1, -1, -1, -1, /* PORT3x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT4x */
- -1, -1, -1, 46, 47, 48, 49, 50, /* PORT5x */
- 51, -1, -1, 54, 55, 56, 57, 58, /* PORT6x */
+ 16, 17, 18, /* PORT30-32 */
+};
+static const int port_range0_muxvals[] = {
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
+ 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
+ 15, 15, 15, /* PORT30-32 */
+};
+static const unsigned port_range1_pins[] = {
+ 46, 47, 48, 49, 50, /* PORT53-57 */
+ 51, /* PORT60 */
+};
+static const int port_range1_muxvals[] = {
+ 15, 15, 15, 15, 15, /* PORT53-57 */
+ 15, /* PORT60 */
+};
+static const unsigned port_range2_pins[] = {
+ 54, 55, 56, 57, 58, /* PORT63-67 */
59, 60, 69, 70, 71, 72, 73, 74, /* PORT7x */
75, 76, 77, 78, 79, 80, 81, 82, /* PORT8x */
83, 84, 85, 86, 87, 88, 89, 90, /* PORT9x */
91, 92, 93, 94, 95, 96, 97, 98, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
- 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
- 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
- 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
- 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
- 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
- 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
- 139, 140, 141, 142, -1, -1, -1, -1, /* PORT22x */
- 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
- 155, 156, 157, 143, 144, 145, 146, 158, /* PORT24x */
};
-static const int port_range_muxvals[] = {
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
- 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
- 15, 15, 15, -1, -1, -1, -1, -1, /* PORT3x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT4x */
- -1, -1, -1, 15, 15, 15, 15, 15, /* PORT5x */
- 15, -1, -1, 15, 15, 15, 15, 15, /* PORT6x */
+static const int port_range2_muxvals[] = {
+ 15, 15, 15, 15, 15, /* PORT63-67 */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
+};
+static const unsigned port_range3_pins[] = {
+ 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
+ 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
+ 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
+};
+static const int port_range3_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
+};
+static const unsigned port_range4_pins[] = {
+ 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
+};
+static const int port_range4_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
+};
+static const unsigned port_range5_pins[] = {
+ 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
+ 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
+ 139, 140, 141, 142, /* PORT220-223 */
+};
+static const int port_range5_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */
- 15, 15, 15, 15, -1, -1, -1, -1, /* PORT22x */
+ 15, 15, 15, 15, /* PORT220-223 */
+};
+static const unsigned port_range6_pins[] = {
+ 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
+ 155, 156, 157, 143, 144, 145, 146, 158, /* PORT24x */
+};
+static const int port_range6_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */
};
@@ -607,147 +621,153 @@
UNIPHIER_PINCTRL_GROUP(usb0),
UNIPHIER_PINCTRL_GROUP(usb1),
UNIPHIER_PINCTRL_GROUP(usb2),
- UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range4),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range5),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range6),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range1, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range1, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range1, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range1, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range1, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range1, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range2, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range2, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range2, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range2, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range2, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range2, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range2, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range2, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range2, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range2, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range2, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range2, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range2, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range2, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range2, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range2, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range2, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range2, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range2, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range2, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range2, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range2, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range2, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range2, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range2, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range2, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range2, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range2, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range2, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range2, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range2, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range2, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range2, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range2, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range2, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range2, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range2, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range3, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range3, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range3, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range3, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range3, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range3, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range3, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range3, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range3, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range3, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range3, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range3, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range3, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range3, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range3, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range3, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range3, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range3, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range3, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range3, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range3, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range3, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range3, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range3, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range4, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range4, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range4, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range4, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range4, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range4, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range4, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range4, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range5, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range5, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range5, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range5, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range5, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range5, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range5, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range5, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range5, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range5, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range5, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range5, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range5, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range5, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range5, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range5, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range5, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range5, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range5, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range5, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range6, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range6, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range6, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range6, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range6, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range6, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range6, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range6, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range6, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range6, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range6, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range6, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range6, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range6, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range6, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range6, 15),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
index 9668633..73b828b 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
@@ -597,7 +597,7 @@
static const int usb2_muxvals[] = {0, 0};
static const unsigned usb3_pins[] = {52, 53};
static const int usb3_muxvals[] = {0, 0};
-static const unsigned port_range_pins[] = {
+static const unsigned port_range0_pins[] = {
168, 169, 170, 171, 172, 173, 174, 175, /* PORT0x */
0, 1, 2, 3, 4, 5, 6, 7, /* PORT1x */
8, 9, 10, 11, 12, 13, 14, 15, /* PORT2x */
@@ -609,23 +609,8 @@
75, 76, 77, 78, 79, 80, 81, 82, /* PORT8x */
83, 84, 85, 86, 87, 88, 89, 90, /* PORT9x */
91, 92, 93, 94, 95, 96, 97, 98, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
- 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
- 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
- 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
- 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
- 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
- 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
- 139, 140, 141, 142, 143, 144, 145, 146, /* PORT22x */
- 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
- 155, 156, 157, 158, 159, 160, 161, 162, /* PORT24x */
- 163, 164, 165, 166, 167, /* PORT25x */
};
-static const int port_range_muxvals[] = {
+static const int port_range0_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */
@@ -637,21 +622,38 @@
15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT11x */
+};
+static const unsigned port_range1_pins[] = {
+ 99, 100, 101, 102, 103, 104, 105, 106, /* PORT12x */
+ 107, 108, 109, 110, 111, 112, 113, 114, /* PORT13x */
+ 115, 116, 117, 118, 119, 120, 121, 122, /* PORT14x */
+};
+static const int port_range1_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT15x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT16x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT17x */
+};
+static const unsigned port_range2_pins[] = {
+ 61, 62, 63, 64, 65, 66, 67, 68, /* PORT18x */
+};
+static const int port_range2_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */
- -1, -1, -1, -1, -1, -1, -1, -1, /* PORT19x */
+};
+static const unsigned port_range3_pins[] = {
+ 123, 124, 125, 126, 127, 128, 129, 130, /* PORT20x */
+ 131, 132, 133, 134, 135, 136, 137, 138, /* PORT21x */
+ 139, 140, 141, 142, 143, 144, 145, 146, /* PORT22x */
+ 147, 148, 149, 150, 151, 152, 153, 154, /* PORT23x */
+ 155, 156, 157, 158, 159, 160, 161, 162, /* PORT24x */
+ 163, 164, 165, 166, 167, /* PORT250-254 */
+};
+static const int port_range3_muxvals[] = {
15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */
15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */
- 15, 15, 15, 15, 15, /* PORT25x */
+ 15, 15, 15, 15, 15, /* PORT250-254 */
};
static const unsigned xirq_pins[] = {
149, 150, 151, 152, 153, 154, 155, 156, /* XIRQ0-7 */
@@ -695,174 +697,177 @@
UNIPHIER_PINCTRL_GROUP(usb1),
UNIPHIER_PINCTRL_GROUP(usb2),
UNIPHIER_PINCTRL_GROUP(usb3),
- UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2),
+ UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq),
UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range, 0),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range, 1),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range, 2),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range, 3),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range, 4),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range, 5),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range, 6),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range, 7),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range, 8),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range, 9),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range, 10),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range, 11),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range, 12),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range, 13),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range, 14),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range, 15),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range, 16),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range, 17),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range, 18),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range, 19),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range, 20),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range, 21),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range, 22),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range, 23),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range, 24),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range, 25),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range, 26),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range, 27),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range, 28),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range, 29),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range, 30),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range, 31),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range, 32),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range, 33),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range, 34),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range, 35),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range, 36),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range, 37),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range, 38),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range, 39),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range, 40),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range, 41),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range, 42),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range, 43),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range, 44),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range, 45),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range, 46),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range, 47),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range, 48),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range, 49),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range, 50),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range, 51),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range, 52),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range, 53),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range, 54),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range, 55),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range, 56),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range, 57),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range, 58),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range, 59),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range, 60),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range, 61),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range, 62),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range, 63),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range, 64),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range, 65),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range, 66),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range, 67),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range, 68),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range, 69),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range, 70),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range, 71),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range, 72),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range, 73),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range, 74),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range, 75),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range, 76),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range, 77),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range, 78),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range, 79),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range, 80),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range, 81),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range, 82),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range, 83),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range, 84),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range, 85),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range, 86),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range, 87),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range, 96),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range, 97),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range, 98),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range, 99),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range, 100),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range, 101),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range, 102),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range, 103),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range, 104),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range, 105),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range, 106),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range, 107),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range, 108),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range, 109),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range, 110),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range, 111),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range, 112),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range, 113),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range, 114),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range, 115),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range, 116),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range, 117),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range, 118),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range, 119),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range, 144),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range, 145),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range, 146),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range, 147),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range, 148),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range, 149),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range, 150),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range, 151),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range, 160),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range, 161),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range, 162),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range, 163),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range, 164),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range, 165),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range, 166),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range, 167),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range, 168),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range, 169),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range, 170),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range, 171),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range, 172),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range, 173),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range, 174),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range, 175),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range, 176),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range, 177),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range, 178),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range, 179),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range, 180),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range, 181),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range, 182),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range, 183),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range, 184),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range, 185),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range, 186),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range, 187),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range, 188),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range, 189),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range, 190),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range, 191),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range, 192),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range, 193),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range, 194),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range, 195),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range, 196),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range, 197),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range, 198),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range, 199),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range, 200),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range, 201),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range, 202),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range, 203),
- UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range, 204),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range2, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range2, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range2, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range2, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range2, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range2, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range2, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range2, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range3, 0),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range3, 1),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range3, 2),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range3, 3),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range3, 4),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range3, 5),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range3, 6),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range3, 7),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range3, 8),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range3, 9),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range3, 10),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range3, 11),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range3, 12),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range3, 13),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range3, 14),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range3, 15),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range3, 16),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range3, 17),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range3, 18),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range3, 19),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range3, 20),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range3, 21),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range3, 22),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range3, 23),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range3, 24),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range3, 25),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range3, 26),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range3, 27),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range3, 28),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range3, 29),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range3, 30),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range3, 31),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range3, 32),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range3, 33),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range3, 34),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range3, 35),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range3, 36),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range3, 37),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range3, 38),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range3, 39),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range3, 40),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range3, 41),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range3, 42),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range3, 43),
+ UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range3, 44),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1),
UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2),
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index f5f783c..c02881b 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -2598,15 +2598,16 @@
if (curr == GSI_CHAN_MODE_CALLBACK &&
mode == GSI_CHAN_MODE_POLL) {
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
+ atomic_set(&ctx->poll_mode, mode);
ctx->stats.callback_to_poll++;
}
if (curr == GSI_CHAN_MODE_POLL &&
mode == GSI_CHAN_MODE_CALLBACK) {
+ atomic_set(&ctx->poll_mode, mode);
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
ctx->stats.poll_to_callback++;
}
- atomic_set(&ctx->poll_mode, mode);
spin_unlock_irqrestore(&gsi_ctx->slock, flags);
return GSI_STATUS_SUCCESS;
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 9c75202..2f272d2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -411,12 +411,15 @@
{
int i, j;
+ /* prevent multi-threads accessing num_q6_rule */
+ mutex_lock(&add_mux_channel_lock);
if (rule_req->filter_spec_list_valid == true) {
num_q6_rule = rule_req->filter_spec_list_len;
IPAWANDBG("Received (%d) install_flt_req\n", num_q6_rule);
} else {
num_q6_rule = 0;
IPAWANERR("got no UL rules from modem\n");
+ mutex_unlock(&add_mux_channel_lock);
return -EINVAL;
}
@@ -610,9 +613,11 @@
num_q6_rule = 0;
memset(ipa_qmi_ctx->q6_ul_filter_rule, 0,
sizeof(ipa_qmi_ctx->q6_ul_filter_rule));
+ mutex_unlock(&add_mux_channel_lock);
return -EINVAL;
success:
+ mutex_unlock(&add_mux_channel_lock);
return 0;
}
@@ -1621,9 +1626,12 @@
/* already got Q6 UL filter rules*/
if (ipa_qmi_ctx &&
ipa_qmi_ctx->modem_cfg_emb_pipe_flt
- == false)
+ == false) {
+ /* protect num_q6_rule */
+ mutex_lock(&add_mux_channel_lock);
rc = wwan_add_ul_flt_rule_to_ipa();
- else
+ mutex_unlock(&add_mux_channel_lock);
+ } else
rc = 0;
egress_set = true;
if (rc)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 02c5991..26d5f5e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2683,6 +2683,21 @@
return 0;
}
+ if (in->client == IPA_CLIENT_APPS_WAN_PROD) {
+ sys->policy = IPA_POLICY_INTR_MODE;
+ sys->use_comm_evt_ring = true;
+ INIT_WORK(&sys->work, ipa3_send_nop_desc);
+
+ /*
+ * enable source notification status for exception packets
+ * (i.e. QMAP commands) to be routed to modem.
+ */
+ sys->ep->status.status_en = true;
+ sys->ep->status.status_ep =
+ ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS);
+ return 0;
+ }
+
if (IPA_CLIENT_IS_MEMCPY_DMA_PROD(in->client)) {
sys->policy = IPA_POLICY_NOINTR_MODE;
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
index 6d82da2..d69d6ae 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
@@ -336,7 +336,7 @@
ipa3_process_interrupts(true);
IPADBG_LOW("Exit\n");
- ipa3_dec_client_disable_clks(&log_info);
+ ipa3_dec_client_disable_clks_no_block(&log_info);
return IRQ_HANDLED;
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b119a69..5095e1f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -423,6 +423,8 @@
{
int i, j;
+ /* prevent multi-threads accessing rmnet_ipa3_ctx->num_q6_rules */
+ mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
if (rule_req->filter_spec_ex_list_valid == true) {
rmnet_ipa3_ctx->num_q6_rules =
rule_req->filter_spec_ex_list_len;
@@ -431,6 +433,8 @@
} else {
rmnet_ipa3_ctx->num_q6_rules = 0;
IPAWANERR("got no UL rules from modem\n");
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return -EINVAL;
}
@@ -633,9 +637,13 @@
rmnet_ipa3_ctx->num_q6_rules = 0;
memset(ipa3_qmi_ctx->q6_ul_filter_rule, 0,
sizeof(ipa3_qmi_ctx->q6_ul_filter_rule));
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return -EINVAL;
success:
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
return 0;
}
@@ -1086,7 +1094,6 @@
int ret = 0;
bool qmap_check;
struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
- struct ipa_tx_meta meta;
if (skb->protocol != htons(ETH_P_MAP)) {
IPAWANDBG_LOW
@@ -1142,17 +1149,11 @@
}
/* IPA_RM checking end */
- if (RMNET_MAP_GET_CD_BIT(skb)) {
- memset(&meta, 0, sizeof(meta));
- meta.pkt_init_dst_ep_valid = true;
- meta.pkt_init_dst_ep_remote = true;
- 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);
- }
-
+ /*
+ * both data packets and command will be routed to
+ * IPA_CLIENT_Q6_WAN_CONS based on status configuration
+ */
+ ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
if (ret) {
ret = NETDEV_TX_BUSY;
goto out;
@@ -1373,9 +1374,7 @@
}
if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION) {
- IPAWANERR("WAN UL Aggregation not supported!!\n");
- WARN_ON(1);
- return -EINVAL;
+ IPAWANDBG("WAN UL Aggregation enabled\n");
ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_QCMAP;
@@ -1429,8 +1428,13 @@
if (rmnet_ipa3_ctx->num_q6_rules != 0) {
/* already got Q6 UL filter rules*/
- if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false)
+ if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false) {
+ /* prevent multi-threads accessing num_q6_rules */
+ mutex_lock(&rmnet_ipa3_ctx->add_mux_channel_lock);
rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
+ mutex_unlock(&rmnet_ipa3_ctx->
+ add_mux_channel_lock);
+ }
if (rc)
IPAWANERR("install UL rules failed\n");
else
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index a013edd..b929d8b 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -261,6 +261,8 @@
POWER_SUPPLY_ATTR(low_power),
POWER_SUPPLY_ATTR(temp_cool),
POWER_SUPPLY_ATTR(temp_warm),
+ POWER_SUPPLY_ATTR(temp_cold),
+ POWER_SUPPLY_ATTR(temp_hot),
POWER_SUPPLY_ATTR(system_temp_level),
POWER_SUPPLY_ATTR(resistance),
POWER_SUPPLY_ATTR(resistance_capacitive),
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index c793ee5..271c523 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -105,7 +105,7 @@
};
/* JEITA */
-enum {
+enum jeita_levels {
JEITA_COLD = 0,
JEITA_COOL,
JEITA_WARM,
@@ -252,6 +252,7 @@
struct fg_dt_props {
bool force_load_profile;
bool hold_soc_while_full;
+ bool linearize_soc;
bool auto_recharge_soc;
int cutoff_volt_mv;
int empty_volt_mv;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 6f615e4..7f220c3 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -576,6 +576,41 @@
return 0;
}
+static int fg_get_jeita_threshold(struct fg_chip *chip,
+ enum jeita_levels level, int *temp_decidegC)
+{
+ int rc;
+ u8 val;
+ u16 reg;
+
+ switch (level) {
+ case JEITA_COLD:
+ reg = BATT_INFO_JEITA_TOO_COLD(chip);
+ break;
+ case JEITA_COOL:
+ reg = BATT_INFO_JEITA_COLD(chip);
+ break;
+ case JEITA_WARM:
+ reg = BATT_INFO_JEITA_HOT(chip);
+ break;
+ case JEITA_HOT:
+ reg = BATT_INFO_JEITA_TOO_HOT(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = fg_read(chip, reg, &val, 1);
+ if (rc < 0) {
+ pr_err("Error in reading jeita level %d, rc=%d\n", level, rc);
+ return rc;
+ }
+
+ /* Resolution is 0.5C. Base is -30C. */
+ *temp_decidegC = (((5 * val) / 10) - 30) * 10;
+ return 0;
+}
+
#define BATT_TEMP_NUMR 1
#define BATT_TEMP_DENR 1
static int fg_get_battery_temp(struct fg_chip *chip, int *val)
@@ -838,7 +873,7 @@
if (rc < 0)
return rc;
- if (chip->delta_soc > 0)
+ if (chip->dt.linearize_soc && chip->delta_soc > 0)
*val = chip->maint_soc;
else
*val = msoc;
@@ -978,12 +1013,6 @@
return 0;
}
-static inline void get_temp_setpoint(int threshold, u8 *val)
-{
- /* Resolution is 0.5C. Base is -30C. */
- *val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
-}
-
static inline void get_batt_temp_delta(int delta, u8 *val)
{
switch (delta) {
@@ -1658,12 +1687,38 @@
return 0;
}
+static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
+{
+ int rc;
+ u8 full_soc[2] = {0xFF, 0xFF};
+
+ /*
+ * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
+ * needs to be updated to reflect the same. Write battery SOC to
+ * FULL_SOC and write a full value to MONOTONIC_SOC.
+ */
+ rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
+ (u8 *)&bsoc, 2, FG_IMA_ATOMIC);
+ if (rc < 0) {
+ pr_err("failed to write full_soc rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
+ full_soc, 2, FG_IMA_ATOMIC);
+ if (rc < 0) {
+ pr_err("failed to write monotonic_soc rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
static int fg_charge_full_update(struct fg_chip *chip)
{
union power_supply_propval prop = {0, };
int rc, msoc, bsoc, recharge_soc, msoc_raw;
- u8 full_soc[2] = {0xFF, 0xFF};
if (!chip->dt.hold_soc_while_full)
return 0;
@@ -1722,24 +1777,24 @@
fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
msoc);
}
- } else if (msoc_raw < recharge_soc && chip->charge_full) {
- chip->delta_soc = FULL_CAPACITY - msoc;
+ } else if (msoc_raw <= recharge_soc && chip->charge_full) {
+ if (chip->dt.linearize_soc) {
+ chip->delta_soc = FULL_CAPACITY - msoc;
- /*
- * We're spreading out the delta SOC over every 10% change
- * in monotonic SOC. We cannot spread more than 9% in the
- * range of 0-100 skipping the first 10%.
- */
- if (chip->delta_soc > 9) {
- chip->delta_soc = 0;
- chip->maint_soc = 0;
- } else {
- chip->maint_soc = FULL_CAPACITY;
- chip->last_msoc = msoc;
+ /*
+ * We're spreading out the delta SOC over every 10%
+ * change in monotonic SOC. We cannot spread more than
+ * 9% in the range of 0-100 skipping the first 10%.
+ */
+ if (chip->delta_soc > 9) {
+ chip->delta_soc = 0;
+ chip->maint_soc = 0;
+ } else {
+ chip->maint_soc = FULL_CAPACITY;
+ chip->last_msoc = msoc;
+ }
}
- chip->charge_full = false;
-
/*
* Raise the recharge voltage so that VBAT_LT_RECHG signal
* will be asserted soon as battery SOC had dropped below
@@ -1752,35 +1807,23 @@
rc);
goto out;
}
+
+ /*
+ * If charge_done is still set, wait for recharging or
+ * discharging to happen.
+ */
+ if (chip->charge_done)
+ goto out;
+
+ rc = fg_configure_full_soc(chip, bsoc);
+ if (rc < 0)
+ goto out;
+
+ chip->charge_full = false;
fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
- } else {
- goto out;
}
- if (!chip->charge_full)
- goto out;
-
- /*
- * During JEITA conditions, charge_full can happen early. FULL_SOC
- * and MONOTONIC_SOC needs to be updated to reflect the same. Write
- * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
- */
- rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
- FG_IMA_ATOMIC);
- if (rc < 0) {
- pr_err("failed to write full_soc rc=%d\n", rc);
- goto out;
- }
-
- rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
- full_soc, 2, FG_IMA_ATOMIC);
- if (rc < 0) {
- pr_err("failed to write monotonic_soc rc=%d\n", rc);
- goto out;
- }
-
- fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
out:
mutex_unlock(&chip->charge_full_lock);
return rc;
@@ -1863,6 +1906,44 @@
return 0;
}
+static int fg_set_jeita_threshold(struct fg_chip *chip,
+ enum jeita_levels level, int temp_decidegC)
+{
+ int rc;
+ u8 val;
+ u16 reg;
+
+ if (temp_decidegC < -300 || temp_decidegC > 970)
+ return -EINVAL;
+
+ /* Resolution is 0.5C. Base is -30C. */
+ val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
+ switch (level) {
+ case JEITA_COLD:
+ reg = BATT_INFO_JEITA_TOO_COLD(chip);
+ break;
+ case JEITA_COOL:
+ reg = BATT_INFO_JEITA_COLD(chip);
+ break;
+ case JEITA_WARM:
+ reg = BATT_INFO_JEITA_HOT(chip);
+ break;
+ case JEITA_HOT:
+ reg = BATT_INFO_JEITA_TOO_HOT(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = fg_write(chip, reg, &val, 1);
+ if (rc < 0) {
+ pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
{
u8 buf[2];
@@ -2862,6 +2943,9 @@
t_predicted_cv, t_predicted = 0;
s64 delta_ms;
+ if (!chip->soc_reporting_ready)
+ return -ENODATA;
+
if (chip->bp.float_volt_uv <= 0) {
pr_err("battery profile is not loaded\n");
return -ENODATA;
@@ -3137,6 +3221,9 @@
{
int rc = 0, msoc;
+ if (!chip->dt.linearize_soc)
+ return 0;
+
mutex_lock(&chip->charge_full_lock);
if (chip->delta_soc <= 0)
goto out;
@@ -3365,6 +3452,9 @@
case POWER_SUPPLY_PROP_CAPACITY:
rc = fg_get_prop_capacity(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_CAPACITY_RAW:
+ rc = fg_get_msoc_raw(chip, &pval->intval);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
if (chip->battery_missing)
pval->intval = 3700000;
@@ -3377,6 +3467,34 @@
case POWER_SUPPLY_PROP_TEMP:
rc = fg_get_battery_temp(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_cold, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_cool, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_warm, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_HOT_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_hot, rc=%d\n", rc);
+ return rc;
+ }
+ break;
case POWER_SUPPLY_PROP_RESISTANCE:
rc = fg_get_battery_resistance(chip, &pval->intval);
break;
@@ -3500,6 +3618,48 @@
return -EINVAL;
}
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (chip->cl.active) {
+ pr_warn("Capacity learning active!\n");
+ return 0;
+ }
+ if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
+ pr_err("charge_full is out of bounds\n");
+ return -EINVAL;
+ }
+ chip->cl.learned_cc_uah = pval->intval;
+ rc = fg_save_learned_cap_to_sram(chip);
+ if (rc < 0)
+ pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
+ break;
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_cold, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_cool, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_warm, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_HOT_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_hot, rc=%d\n", rc);
+ return rc;
+ }
+ break;
default:
break;
}
@@ -3515,6 +3675,11 @@
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
case POWER_SUPPLY_PROP_CC_STEP:
case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ case POWER_SUPPLY_PROP_HOT_TEMP:
return 1;
default:
break;
@@ -3555,7 +3720,12 @@
static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_RAW,
POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_COLD_TEMP,
+ POWER_SUPPLY_PROP_COOL_TEMP,
+ POWER_SUPPLY_PROP_WARM_TEMP,
+ POWER_SUPPLY_PROP_HOT_TEMP,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_CURRENT_NOW,
@@ -3734,29 +3904,29 @@
}
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_COLD,
+ chip->dt.jeita_thresholds[JEITA_COLD] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_cold, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_COOL,
+ chip->dt.jeita_thresholds[JEITA_COOL] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_cool, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_WARM,
+ chip->dt.jeita_thresholds[JEITA_WARM] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_warm, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_HOT,
+ chip->dt.jeita_thresholds[JEITA_HOT] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_hot, rc=%d\n", rc);
return rc;
@@ -4680,6 +4850,9 @@
chip->dt.hold_soc_while_full = of_property_read_bool(node,
"qcom,hold-soc-while-full");
+ chip->dt.linearize_soc = of_property_read_bool(node,
+ "qcom,linearize-soc");
+
rc = fg_parse_ki_coefficients(chip);
if (rc < 0)
pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
@@ -4761,6 +4934,13 @@
static void fg_cleanup(struct fg_chip *chip)
{
+ int i;
+
+ for (i = 0; i < FG_IRQ_MAX; i++) {
+ if (fg_irqs[i].irq)
+ devm_free_irq(chip->dev, fg_irqs[i].irq, chip);
+ }
+
power_supply_unreg_notifier(&chip->nb);
debugfs_remove_recursive(chip->dfs_root);
if (chip->awake_votable)
@@ -5002,6 +5182,29 @@
return 0;
}
+static void fg_gen3_shutdown(struct platform_device *pdev)
+{
+ struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
+ int rc, bsoc;
+
+ if (chip->charge_full) {
+ rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
+ if (rc < 0) {
+ pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
+ return;
+ }
+
+ /* We need 2 most significant bytes here */
+ bsoc = (u32)bsoc >> 16;
+
+ rc = fg_configure_full_soc(chip, bsoc);
+ if (rc < 0) {
+ pr_err("Error in configuring full_soc, rc=%d\n", rc);
+ return;
+ }
+ }
+}
+
static const struct of_device_id fg_gen3_match_table[] = {
{.compatible = FG_GEN3_DEV_NAME},
{},
@@ -5016,6 +5219,7 @@
},
.probe = fg_gen3_probe,
.remove = fg_gen3_remove,
+ .shutdown = fg_gen3_shutdown,
};
static int __init fg_gen3_init(void)
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 5304405..6abbaeb 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -795,6 +795,7 @@
*************************/
static enum power_supply_property smb2_dc_props[] = {
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -810,6 +811,9 @@
int rc = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ val->intval = get_effective_result(chg->dc_suspend_votable);
+ break;
case POWER_SUPPLY_PROP_PRESENT:
rc = smblib_get_prop_dc_present(chg, val);
break;
@@ -841,6 +845,10 @@
int rc = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ rc = vote(chg->dc_suspend_votable, WBC_VOTER,
+ (bool)val->intval, 0);
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_set_prop_dc_current_max(chg, val);
break;
@@ -1199,7 +1207,7 @@
* VBUS REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb2_vbus_reg_ops = {
+static struct regulator_ops smb2_vbus_reg_ops = {
.enable = smblib_vbus_regulator_enable,
.disable = smblib_vbus_regulator_disable,
.is_enabled = smblib_vbus_regulator_is_enabled,
@@ -1241,7 +1249,7 @@
* VCONN REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb2_vconn_reg_ops = {
+static struct regulator_ops smb2_vconn_reg_ops = {
.enable = smblib_vconn_regulator_enable,
.disable = smblib_vconn_regulator_disable,
.is_enabled = smblib_vconn_regulator_is_enabled,
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 9b5b592..1b890d5 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -891,7 +891,7 @@
bool override;
/* suspend and return if 25mA or less is requested */
- if (icl_ua < USBIN_25MA)
+ if (icl_ua <= USBIN_25MA)
return smblib_set_usb_suspend(chg, true);
if (icl_ua == INT_MAX)
@@ -1017,7 +1017,7 @@
icl_ua = 0;
}
- suspend = (icl_ua < USBIN_25MA);
+ suspend = (icl_ua <= USBIN_25MA);
if (suspend)
goto suspend;
@@ -4153,7 +4153,7 @@
/* skip suspending input if its already suspended by some other voter */
usb_icl = get_effective_result(chg->usb_icl_votable);
- if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
+ if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
return IRQ_HANDLED;
if (stat & USE_DCIN_BIT)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5251b6f..80f5bca 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -67,6 +67,7 @@
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define OTG_VOTER "OTG_VOTER"
#define FCC_CHANGE_VOTER "FCC_CHANGE_VOTER"
+#define WBC_VOTER "WBC_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index e0c92c6..28c3512 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -111,7 +111,7 @@
debug_mask, __debug_mask, int, 0600
);
-irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
+static irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb138x *chip = irq_data->parent_data;
@@ -730,7 +730,7 @@
* VBUS REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb138x_vbus_reg_ops = {
+static struct regulator_ops smb138x_vbus_reg_ops = {
.enable = smblib_vbus_regulator_enable,
.disable = smblib_vbus_regulator_disable,
.is_enabled = smblib_vbus_regulator_is_enabled,
@@ -772,7 +772,7 @@
* VCONN REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb138x_vconn_reg_ops = {
+static struct regulator_ops smb138x_vconn_reg_ops = {
.enable = smblib_vconn_regulator_enable,
.disable = smblib_vconn_regulator_disable,
.is_enabled = smblib_vconn_regulator_is_enabled,
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 1910100..00602ab 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -66,6 +66,9 @@
{
static const char * const strings[] = RNC_STATES;
+ if (state >= ARRAY_SIZE(strings))
+ return "UNKNOWN";
+
return strings[state];
}
#undef C
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index ad33238..8c4641b 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -243,12 +243,15 @@
struct qla_hw_data *ha = vha->hw;
ssize_t rval = 0;
- if (ha->optrom_state != QLA_SREADING)
- return 0;
-
mutex_lock(&ha->optrom_mutex);
+
+ if (ha->optrom_state != QLA_SREADING)
+ goto out;
+
rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
ha->optrom_region_size);
+
+out:
mutex_unlock(&ha->optrom_mutex);
return rval;
@@ -263,14 +266,19 @@
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
- if (ha->optrom_state != QLA_SWRITING)
+ mutex_lock(&ha->optrom_mutex);
+
+ if (ha->optrom_state != QLA_SWRITING) {
+ mutex_unlock(&ha->optrom_mutex);
return -EINVAL;
- if (off > ha->optrom_region_size)
+ }
+ if (off > ha->optrom_region_size) {
+ mutex_unlock(&ha->optrom_mutex);
return -ERANGE;
+ }
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
- mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
mutex_unlock(&ha->optrom_mutex);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 44c466b..ecc6aad 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -142,6 +142,7 @@
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
rwlock_t rq_list_lock; /* protect access to list in req_arr */
+ struct mutex f_mutex; /* protect against changes in this fd */
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve; /* buffer held for this file descriptor */
@@ -155,6 +156,7 @@
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
char mmap_called; /* 0 -> mmap() never called on this fd */
+ char res_in_use; /* 1 -> 'reserve' array in use */
struct kref f_ref;
struct execute_work ew;
} Sg_fd;
@@ -198,7 +200,6 @@
static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request *sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
static Sg_device *sg_get_dev(int dev);
static void sg_device_destroy(struct kref *kref);
@@ -614,6 +615,7 @@
}
buf += SZ_SG_HEADER;
__get_user(opcode, buf);
+ mutex_lock(&sfp->f_mutex);
if (sfp->next_cmd_len > 0) {
cmd_size = sfp->next_cmd_len;
sfp->next_cmd_len = 0; /* reset so only this write() effected */
@@ -622,6 +624,7 @@
if ((opcode >= 0xc0) && old_hdr.twelve_byte)
cmd_size = 12;
}
+ mutex_unlock(&sfp->f_mutex);
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
"sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
/* Determine buffer size. */
@@ -721,7 +724,7 @@
sg_remove_request(sfp, srp);
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */
}
- if (sg_res_in_use(sfp)) {
+ if (sfp->res_in_use) {
sg_remove_request(sfp, srp);
return -EBUSY; /* reserve buffer already being used */
}
@@ -896,7 +899,7 @@
return result;
if (val) {
sfp->low_dma = 1;
- if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+ if ((0 == sfp->low_dma) && !sfp->res_in_use) {
val = (int) sfp->reserve.bufflen;
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
@@ -971,12 +974,18 @@
return -EINVAL;
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
+ mutex_lock(&sfp->f_mutex);
if (val != sfp->reserve.bufflen) {
- if (sg_res_in_use(sfp) || sfp->mmap_called)
+ if (sfp->mmap_called ||
+ sfp->res_in_use) {
+ mutex_unlock(&sfp->f_mutex);
return -EBUSY;
+ }
+
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
}
+ mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_RESERVED_SIZE:
val = min_t(int, sfp->reserve.bufflen,
@@ -1728,13 +1737,22 @@
md = &map_data;
if (md) {
- if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+ mutex_lock(&sfp->f_mutex);
+ if (dxfer_len <= rsv_schp->bufflen &&
+ !sfp->res_in_use) {
+ sfp->res_in_use = 1;
sg_link_reserve(sfp, srp, dxfer_len);
- else {
+ } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
+ mutex_unlock(&sfp->f_mutex);
+ return -EBUSY;
+ } else {
res = sg_build_indirect(req_schp, sfp, dxfer_len);
- if (res)
+ if (res) {
+ mutex_unlock(&sfp->f_mutex);
return res;
+ }
}
+ mutex_unlock(&sfp->f_mutex);
md->pages = req_schp->pages;
md->page_order = req_schp->page_order;
@@ -2025,6 +2043,8 @@
req_schp->sglist_len = 0;
sfp->save_scat_len = 0;
srp->res_used = 0;
+ /* Called without mutex lock to avoid deadlock */
+ sfp->res_in_use = 0;
}
static Sg_request *
@@ -2136,6 +2156,7 @@
rwlock_init(&sfp->rq_list_lock);
kref_init(&sfp->f_ref);
+ mutex_init(&sfp->f_mutex);
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
@@ -2211,20 +2232,6 @@
schedule_work(&sfp->ew.work);
}
-static int
-sg_res_in_use(Sg_fd * sfp)
-{
- const Sg_request *srp;
- unsigned long iflags;
-
- read_lock_irqsave(&sfp->rq_list_lock, iflags);
- for (srp = sfp->headrp; srp; srp = srp->nextrp)
- if (srp->res_used)
- break;
- read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- return srp ? 1 : 0;
-}
-
#ifdef CONFIG_SCSI_PROC_FS
static int
sg_idr_max_id(int id, void *p, void *data)
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 792ae42..32edd76 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -21,6 +21,7 @@
#define MAX_UFS_QCOM_HOSTS 2
#define MAX_U32 (~(u32)0)
#define MPHY_TX_FSM_STATE 0x41
+#define MPHY_RX_FSM_STATE 0xC1
#define TX_FSM_HIBERN8 0x1
#define HBRN8_POLL_TOUT_MS 100
#define DEFAULT_CLK_RATE_HZ 1000000
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7c5a1bc..f5a6736 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -144,10 +144,11 @@
static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
{
- int ret = 0;
+ int len, ret = 0;
char prop_name[MAX_PROP_SIZE];
struct ufs_vreg *vreg = NULL;
struct device_node *np = dev->of_node;
+ const __be32 *prop;
if (!np) {
dev_err(dev, "%s: non DT initialization\n", __func__);
@@ -186,8 +187,16 @@
vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
} else {
- vreg->min_uV = UFS_VREG_VCC_MIN_UV;
- vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+ prop = of_get_property(np, "vcc-voltage-level", &len);
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_warn(dev, "%s vcc-voltage-level property.\n",
+ prop ? "invalid format" : "no");
+ vreg->min_uV = UFS_VREG_VCC_MIN_UV;
+ vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+ } else {
+ vreg->min_uV = be32_to_cpup(&prop[0]);
+ vreg->max_uV = be32_to_cpup(&prop[1]);
+ }
}
} else if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c132dbc..e1e9402 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -864,6 +864,24 @@
}
}
+static void ufshcd_print_fsm_state(struct ufs_hba *hba)
+{
+ int err = 0, tx_fsm_val = 0, rx_fsm_val = 0;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
+ dev_err(hba->dev, "%s: TX_FSM_STATE = %u, err = %d\n", __func__,
+ tx_fsm_val, err);
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB_SEL(MPHY_RX_FSM_STATE,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+ &rx_fsm_val);
+ dev_err(hba->dev, "%s: RX_FSM_STATE = %u, err = %d\n", __func__,
+ rx_fsm_val, err);
+}
+
static void ufshcd_print_host_state(struct ufs_hba *hba)
{
if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_STATE_EN))
@@ -888,6 +906,7 @@
hba->capabilities, hba->caps);
dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
hba->dev_info.quirks);
+ ufshcd_print_fsm_state(hba);
}
/**
@@ -9689,6 +9708,8 @@
static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
{
+ if (!ufshcd_is_clkscaling_supported(hba))
+ return;
__ufshcd_shutdown_clkscaling(hba);
device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
}
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index 43f255e..6019e4b 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -604,10 +604,11 @@
static unsigned long glink_qos_calc_rate_kBps(size_t pkt_size,
unsigned long interval_us)
{
- unsigned long rate_kBps, rem;
+ unsigned long rem;
+ uint64_t rate_kBps;
rate_kBps = pkt_size * USEC_PER_SEC;
- rem = do_div(rate_kBps, (interval_us * 1024));
+ rem = do_div(rate_kBps, interval_us * 1024);
return rate_kBps;
}
@@ -5454,8 +5455,8 @@
static void glink_scheduler_eval_prio(struct channel_ctx *ctx,
struct glink_core_xprt_ctx *xprt_ctx)
{
- unsigned long token_end_time;
- unsigned long token_consume_time, rem;
+ unsigned long token_end_time, rem;
+ uint64_t token_consume_time;
unsigned long obs_rate_kBps;
if (ctx->initial_priority == 0)
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 209209b..ecf72ca 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -152,6 +152,8 @@
#define ICNSS_QMI_ASSERT() do { } while (0)
#endif
+#define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77
+
enum icnss_debug_quirks {
HW_ALWAYS_ON,
HW_DEBUG_ENABLE,
@@ -740,7 +742,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI vbatt request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
priv->stats.vbatt_resp++;
@@ -1224,7 +1226,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI MSA Mem info request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
@@ -1296,7 +1298,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI MSA ready request rejected: result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.msa_ready_resp++;
@@ -1359,7 +1361,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI indication register request rejected, resut:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.ind_register_resp++;
@@ -1406,7 +1408,9 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI capability request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
+ if (resp.resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED)
+ icnss_pr_err("RF card Not present");
goto out;
}
@@ -1489,7 +1493,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI mode request rejected, mode:%d result:%d error:%d\n",
mode, resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.mode_resp++;
@@ -1539,7 +1543,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI config request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.cfg_resp++;
@@ -1592,7 +1596,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n",
fw_log_mode, resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
penv->stats.ini_resp++;
@@ -1652,7 +1656,7 @@
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI athdiag read request rejected, result:%d error:%d\n",
resp->resp.result, resp->resp.error);
- ret = resp->resp.result;
+ ret = -resp->resp.result;
goto out;
}
@@ -1718,7 +1722,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI athdiag write request rejected, result:%d error:%d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
out:
@@ -1813,7 +1817,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI rejuvenate ack request rejected, result:%d error %d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
priv->stats.rejuvenate_ack_resp++;
@@ -1874,7 +1878,7 @@
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
icnss_pr_err("QMI dynamic feature mask request rejected, result:%d error %d\n",
resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ ret = -resp.resp.result;
goto out;
}
diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c
index 739c053..3863b09 100644
--- a/drivers/soc/qcom/llcc-sdm845.c
+++ b/drivers/soc/qcom/llcc-sdm845.c
@@ -57,23 +57,24 @@
}
static struct llcc_slice_config sdm845_data[] = {
- SCT_ENTRY("cpuss", 1, 1, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 1),
+ SCT_ENTRY("cpuss", 1, 1, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 1),
SCT_ENTRY("vidsc0", 2, 2, 512, 2, 1, 0x0, 0x0F0, 0, 0, 1, 1, 0),
SCT_ENTRY("vidsc1", 3, 3, 512, 2, 1, 0x0, 0x0F0, 0, 0, 1, 1, 0),
- SCT_ENTRY("rotator", 4, 4, 563, 2, 1, 0x0, 0x00F, 2, 0, 1, 1, 0),
- SCT_ENTRY("voice", 5, 5, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("audio", 6, 6, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0x0F0, 0xF0F, 0, 0, 1, 1, 0),
- SCT_ENTRY("modem", 8, 8, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("compute", 10, 10, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("gpuhtw", 11, 11, 512, 1, 1, 0x0, 0xC, 0, 0, 1, 1, 0),
- SCT_ENTRY("gpu", 12, 12, 2560, 1, 0, 0xFF0, 0x3, 0, 0, 1, 1, 0),
- SCT_ENTRY("mmuhwt", 13, 13, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 0, 1),
- SCT_ENTRY("compute_dma", 15, 15, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("display", 16, 16, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("rotator", 4, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0),
+ SCT_ENTRY("voice", 5, 5, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("audio", 6, 6, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0x0FC, 0xF00, 0, 0, 1, 1, 0),
+ SCT_ENTRY("modem", 8, 8, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("compute", 10, 10, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("gpuhtw", 11, 11, 512, 1, 1, 0xC, 0x0, 0, 0, 1, 1, 0),
+ SCT_ENTRY("gpu", 12, 12, 2304, 1, 0, 0xFF0, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("mmuhwt", 13, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1),
+ SCT_ENTRY("compute_dma", 15, 15, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("display", 16, 16, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+ SCT_ENTRY("videofw", 17, 17, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY("modemhp_fix", 20, 20, 1024, 2, 1, 0x0, 0xF00, 0, 0, 1, 1, 0),
SCT_ENTRY("modem_paging", 21, 21, 1024, 0, 1, 0x0, 0xF, 0, 0, 1, 1, 0),
- SCT_ENTRY("audiohw", 22, 22, 1024, 1, 1, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+ SCT_ENTRY("audiohw", 22, 22, 1024, 1, 1, 0xFFC, 0x2, 0, 0, 1, 1, 0),
};
static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index ea01076..077d8cd 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -563,9 +563,6 @@
return ret;
list_for_each_entry_safe(node, node_tmp, clist, link) {
- if (unlikely(node->node_info->defer_qos))
- msm_bus_dev_init_qos(&node->dev, NULL);
-
bcm_clist_add(node);
}
@@ -668,6 +665,12 @@
kfree(cmdlist_active);
kfree(n_active);
+
+ list_for_each_entry_safe(node, node_tmp, clist, link) {
+ if (unlikely(node->node_info->defer_qos))
+ msm_bus_dev_init_qos(&node->dev, NULL);
+ }
+
exit_msm_bus_commit_data:
list_for_each_entry_safe(node, node_tmp, clist, link) {
bcm_clist_clean(node);
@@ -962,6 +965,12 @@
MSM_BUS_DBG("Device = %d", node_dev->node_info->id);
+ if (node_dev->node_info->qos_params.defer_init_qos) {
+ node_dev->node_info->qos_params.defer_init_qos = false;
+ node_dev->node_info->defer_qos = true;
+ goto exit_init_qos;
+ }
+
if (node_dev->ap_owned) {
struct msm_bus_node_device_type *bus_node_info;
@@ -995,6 +1004,7 @@
bus_node_info->fabdev->noc_ops.qos_init(
node_dev,
+ bus_node_info,
bus_node_info->fabdev->qos_base,
bus_node_info->fabdev->base_offset,
bus_node_info->fabdev->qos_off,
@@ -1290,6 +1300,8 @@
pdata_node_info->qos_params.reg_mode.write;
node_info->qos_params.urg_fwd_en =
pdata_node_info->qos_params.urg_fwd_en;
+ node_info->qos_params.defer_init_qos =
+ pdata_node_info->qos_params.defer_init_qos;
node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth;
node_info->agg_params.agg_scheme =
pdata_node_info->agg_params.agg_scheme;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
index 996c719..bdcdf29 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c
@@ -15,10 +15,14 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/msm-bus-board.h>
+#include <linux/msm-bus.h>
+#include <linux/spinlock.h>
#include "msm_bus_core.h"
#include "msm_bus_noc.h"
#include "msm_bus_rpmh.h"
+static DEFINE_SPINLOCK(noc_lock);
+
/* NOC_QOS generic */
#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
#define SAT_SCALE 16 /* 16 bytes minimum for saturation */
@@ -29,6 +33,7 @@
#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
#define MIN_SAT_FIELD 1
#define MIN_BW_FIELD 1
+#define MSM_BUS_FAB_MEM_NOC 6152
#define NOC_QOS_REG_BASE(b, o) ((b) + (o))
@@ -102,6 +107,8 @@
NOC_QOS_SATn_SAT_SHFT = 0x0,
};
+static void __iomem *memnoc_qos_base;
+
static int noc_div(uint64_t *a, uint32_t b)
{
if ((*a > 0) && (*a < b)) {
@@ -169,38 +176,10 @@
wmb();
}
-static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off,
- uint32_t mport, uint32_t qos_delta,
- struct msm_bus_noc_limiter *lim, uint32_t lim_en)
+static void noc_enable_qos_limiter(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t lim_en)
{
uint32_t reg_val, val;
-
- reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
- qos_delta));
-
- writel_relaxed((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))),
- NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
-
- /* Ensure we disable limiter before config*/
- wmb();
-
- reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
- qos_delta));
- val = lim->bw << NOC_QOS_LIMITBW_BWn_SHFT;
- writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) |
- (val & NOC_QOS_LIMITBW_BWn_BMSK)),
- NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
-
- reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
- qos_delta));
- val = lim->sat << NOC_QOS_LIMITBW_SATn_SHFT;
- writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) |
- (val & NOC_QOS_LIMITBW_SATn_BMSK)),
- NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
-
- /* Ensure qos limiter settings in place before possibly enabling */
- wmb();
-
reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport,
qos_delta));
val = lim_en << NOC_QOS_MCTL_LIMIT_ENn_SHFT;
@@ -208,9 +187,50 @@
(val & NOC_QOS_MCTL_LIMIT_ENn_BMSK)),
NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta));
+ /* Ensure we disable/enable limiter before exiting*/
wmb();
}
+static void noc_set_qos_limit_bw(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t bw)
+{
+ uint32_t reg_val, val;
+ reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+ qos_delta));
+ val = bw << NOC_QOS_LIMITBW_BWn_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) |
+ (val & NOC_QOS_LIMITBW_BWn_BMSK)),
+ NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
+
+ /* Ensure we set limiter bw before exiting*/
+ wmb();
+}
+
+static void noc_set_qos_limit_sat(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta, uint32_t sat)
+{
+ uint32_t reg_val, val;
+ reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport,
+ qos_delta));
+ val = sat << NOC_QOS_LIMITBW_SATn_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) |
+ (val & NOC_QOS_LIMITBW_SATn_BMSK)),
+ NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta));
+
+ /* Ensure we set limiter sat before exiting*/
+ wmb();
+}
+
+static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off,
+ uint32_t mport, uint32_t qos_delta,
+ struct msm_bus_noc_limiter *lim, uint32_t lim_en)
+{
+ noc_enable_qos_limiter(base, qos_off, mport, qos_delta, 0);
+ noc_set_qos_limit_bw(base, qos_off, mport, qos_delta, lim->bw);
+ noc_set_qos_limit_sat(base, qos_off, mport, qos_delta, lim->sat);
+ noc_enable_qos_limiter(base, qos_off, mport, qos_delta, lim_en);
+}
+
static void noc_set_qos_regulator(void __iomem *base, uint32_t qos_off,
uint32_t mport, uint32_t qos_delta,
struct msm_bus_noc_regulator *reg,
@@ -317,6 +337,7 @@
}
static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
+ struct msm_bus_node_device_type *fabdev,
void __iomem *qos_base,
uint32_t qos_off, uint32_t qos_delta,
uint32_t qos_freq)
@@ -324,6 +345,7 @@
struct msm_bus_noc_qos_params *qos_params;
int ret = 0;
int i;
+ unsigned long flags;
qos_params = &info->node_info->qos_params;
@@ -333,6 +355,11 @@
goto err_qos_init;
}
+ spin_lock_irqsave(&noc_lock, flags);
+
+ if (fabdev->node_info->id == MSM_BUS_FAB_MEM_NOC)
+ memnoc_qos_base = qos_base;
+
for (i = 0; i < info->node_info->num_qports; i++) {
noc_set_qos_dflt_prio(qos_base, qos_off,
info->node_info->qport[i],
@@ -356,10 +383,87 @@
qos_delta,
qos_params->urg_fwd_en);
}
+ spin_unlock_irqrestore(&noc_lock, flags);
+
err_qos_init:
return ret;
}
+int msm_bus_noc_throttle_wa(bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&noc_lock, flags);
+
+ if (!memnoc_qos_base) {
+ MSM_BUS_ERR("Memnoc QoS Base address not found!");
+ goto noc_throttle_exit;
+ }
+
+ if (enable) {
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0x1B);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0x1B);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0x30);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0x30);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 1);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 1);
+ } else {
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0);
+ noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10,
+ 0x1000, 0);
+ noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11,
+ 0x1000, 0);
+ }
+
+noc_throttle_exit:
+ spin_unlock_irqrestore(&noc_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(msm_bus_noc_throttle_wa);
+
+int msm_bus_noc_priority_wa(bool enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&noc_lock, flags);
+ if (!memnoc_qos_base) {
+ MSM_BUS_ERR("Memnoc QoS Base address not found!");
+ goto noc_priority_exit;
+ }
+
+ if (enable)
+ noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0,
+ 0x1000, 7);
+ else
+ noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0,
+ 0x1000, 6);
+noc_priority_exit:
+ spin_unlock_irqrestore(&noc_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(msm_bus_noc_priority_wa);
+
int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
{
if (!bus_dev)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
index 77cbbf1..32b6adf 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
@@ -241,6 +241,8 @@
node_info->qos_params.urg_fwd_en = of_property_read_bool(dev_node,
"qcom,forwarding");
+ node_info->qos_params.defer_init_qos = of_property_read_bool(dev_node,
+ "qcom,defer-init-qos");
}
static int msm_bus_of_parse_clk_array(struct device_node *dev_node,
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index ad04fef..8929959 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -42,6 +42,7 @@
/* New types introduced for adhoc topology */
struct msm_bus_noc_ops {
int (*qos_init)(struct msm_bus_node_device_type *dev,
+ struct msm_bus_node_device_type *fabdev,
void __iomem *qos_base, uint32_t qos_off,
uint32_t qos_delta, uint32_t qos_freq);
int (*set_bw)(struct msm_bus_node_device_type *dev,
@@ -136,6 +137,7 @@
struct msm_bus_noc_regulator reg;
struct msm_bus_noc_regulator_mode reg_mode;
bool urg_fwd_en;
+ bool defer_init_qos;
};
struct node_util_levels_type {
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
index 03042fa..4cff9f2 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
@@ -410,8 +410,10 @@
{
struct rule_node_info *node_it = NULL;
+ mutex_lock(&msm_bus_rules_lock);
list_for_each_entry(node_it, &node_list, link)
print_rules(node_it);
+ mutex_unlock(&msm_bus_rules_lock);
}
void print_rules_buf(char *buf, int max_buf)
@@ -421,6 +423,7 @@
int i;
int cnt = 0;
+ mutex_lock(&msm_bus_rules_lock);
list_for_each_entry(node_it, &node_list, link) {
cnt += scnprintf(buf + cnt, max_buf - cnt,
"\n Now printing rules for Node %d cur_rule %d\n",
@@ -452,6 +455,7 @@
node_rule->rule_ops.mode);
}
}
+ mutex_unlock(&msm_bus_rules_lock);
}
static int copy_rule(struct bus_rule_type *src, struct rules_def *node_rule,
@@ -716,11 +720,12 @@
{
bool ret = false;
+ mutex_lock(&msm_bus_rules_lock);
if (list_empty(&node_list))
ret = false;
else
ret = true;
-
+ mutex_unlock(&msm_bus_rules_lock);
return ret;
}
diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c
index 519bb611..25099bb 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_link_info link_info;
void *link_state_handle;
bool link_up;
+ bool auto_intent_enabled;
};
/**
@@ -445,9 +447,26 @@
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) {
@@ -456,7 +475,7 @@
}
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 +645,11 @@
}
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;
@@ -914,6 +934,7 @@
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",
@@ -1182,6 +1203,7 @@
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/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index f5aff4f..926016f 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -77,9 +77,6 @@
#define MSS_MAGIC 0XAABADEAD
-#define MSS_PDC_OFFSET 8
-#define MSS_PDC_MASK BIT(MSS_PDC_OFFSET)
-
/* Timeout value for MBA boot when minidump is enabled */
#define MBA_ENCRYPTION_TIMEOUT 3000
enum scm_cmd {
@@ -214,13 +211,14 @@
static void pil_mss_pdc_sync(struct q6v5_data *drv, bool pdc_sync)
{
u32 val = 0;
+ u32 mss_pdc_mask = BIT(drv->mss_pdc_offset);
if (drv->pdc_sync) {
val = readl_relaxed(drv->pdc_sync);
if (pdc_sync)
- val |= MSS_PDC_MASK;
+ val |= mss_pdc_mask;
else
- val &= ~MSS_PDC_MASK;
+ val &= ~mss_pdc_mask;
writel_relaxed(val, drv->pdc_sync);
/* Ensure PDC is written before next write */
wmb();
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 7984dfe..e9d3534 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -293,6 +293,13 @@
if (res) {
q6->pdc_sync = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,mss_pdc_offset", &q6->mss_pdc_offset)) {
+ dev_err(&pdev->dev,
+ "Offset for MSS PDC not specified\n");
+ return -EINVAL;
+ }
+
}
q6->alt_reset = NULL;
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 9b4c811..4961b1f 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -74,6 +74,7 @@
bool restart_reg_sec;
bool override_acc;
int override_acc_1;
+ int mss_pdc_offset;
bool ahb_clk_vote;
bool mx_spike_wa;
};
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 2b1456e..c1eafbd 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -494,7 +494,8 @@
SPI_ENGINE_VERSION_MAJOR(version),
SPI_ENGINE_VERSION_MINOR(version),
SPI_ENGINE_VERSION_PATCH(version));
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put_master;
}
spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 6acb731..de3dc69 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -192,16 +192,26 @@
static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
int bits_per_word)
{
- int pack_words = 0;
+ int pack_words = 1;
bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
u32 word_len = geni_read_reg(mas->base, SE_SPI_WORD_LEN);
+ unsigned long cfg0, cfg1;
+ /*
+ * If bits_per_word isn't a byte aligned value, set the packing to be
+ * 1 SPI word per FIFO word.
+ */
if (!(mas->tx_fifo_width % bits_per_word))
pack_words = mas->tx_fifo_width / bits_per_word;
word_len &= ~WORD_LEN_MSK;
word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
se_config_packing(mas->base, bits_per_word, pack_words, msb_first);
geni_write_reg(word_len, mas->base, SE_SPI_WORD_LEN);
+ se_get_packing_config(bits_per_word, pack_words, msb_first,
+ &cfg0, &cfg1);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: cfg0 %lu cfg1 %lu bpw %d pack_words %d\n", __func__,
+ cfg0, cfg1, bits_per_word, pack_words);
}
static int setup_fifo_params(struct spi_device *spi_slv,
@@ -257,6 +267,12 @@
geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n",
+ __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:clk_sel 0x%x cpol %d cpha %d\n", __func__,
+ clk_sel, cpol, cpha);
/* Ensure message level attributes are written before returning */
mb();
setup_fifo_params_exit:
@@ -316,10 +332,7 @@
flags |= GSI_CS_TOGGLE;
word_len = xfer->bits_per_word - MIN_WORD_LEN;
- if (mas->tx_fifo_width % xfer->bits_per_word)
- pack = 0;
- else
- pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
+ pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
if (ret) {
dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret);
@@ -504,19 +517,26 @@
}
}
+ if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+ rx_len = ((xfer->len << 3) / mas->cur_word_len);
+ } else {
+ int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+ rx_len = (xfer->len / bytes_per_word);
+ }
+
if (xfer->tx_buf && xfer->rx_buf) {
cmd = SPI_FULL_DUPLEX;
tx_nent += 2;
rx_nent++;
- rx_len = ((xfer->len << 3) / mas->cur_word_len);
} else if (xfer->tx_buf) {
cmd = SPI_TX_ONLY;
tx_nent += 2;
+ rx_len = 0;
} else if (xfer->rx_buf) {
cmd = SPI_RX_ONLY;
tx_nent++;
rx_nent++;
- rx_len = ((xfer->len << 3) / mas->cur_word_len);
}
cs |= spi_slv->chip_select;
@@ -844,7 +864,14 @@
spi_tx_cfg &= ~CS_TOGGLE;
if (xfer->cs_change)
spi_tx_cfg |= CS_TOGGLE;
- trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+ if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+ trans_len =
+ ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+ } else {
+ int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+ trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK;
+ }
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
m_param |= FRAGMENTATION;
@@ -860,6 +887,9 @@
}
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
geni_setup_m_cmd(mas->base, m_cmd, m_param);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n",
+ __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd);
if (m_cmd & SPI_TX_ONLY)
geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure all writes are done before the WM interrupt */
@@ -872,6 +902,7 @@
reinit_completion(&mas->xfer_done);
geni_cancel_m_cmd(mas->base);
+ geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure cmd cancel is written */
mb();
timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
@@ -966,12 +997,25 @@
{
int i = 0;
int tx_fifo_width = (mas->tx_fifo_width >> 3);
- int max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
+ int max_bytes = 0;
const u8 *tx_buf = NULL;
if (!mas->cur_xfer)
return;
+ /*
+ * For non-byte aligned bits-per-word values:
+ * Assumption is that each SPI word will be accomodated in
+ * ceil (bits_per_word / bits_per_byte)
+ * and the next SPI word starts at the next byte.
+ * In such cases, we can fit 1 SPI word per FIFO word so adjust the
+ * max byte that can be sent per IRQ accordingly.
+ */
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ max_bytes = (mas->tx_fifo_depth - mas->tx_wm) *
+ ((mas->cur_word_len / BITS_PER_BYTE) + 1);
+ else
+ max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
tx_buf = mas->cur_xfer->tx_buf;
tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);
@@ -979,8 +1023,13 @@
int j;
u32 fifo_word = 0;
u8 *fifo_byte;
- int bytes_to_write = min_t(int, (max_bytes - i), tx_fifo_width);
+ int bytes_per_fifo = tx_fifo_width;
+ int bytes_to_write = 0;
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ bytes_per_fifo =
+ (mas->cur_word_len / BITS_PER_BYTE) + 1;
+ bytes_to_write = min_t(int, (max_bytes - i), bytes_per_fifo);
fifo_byte = (u8 *)&fifo_word;
for (j = 0; j < bytes_to_write; j++)
fifo_byte[j] = tx_buf[i++];
@@ -1019,15 +1068,24 @@
rx_bytes += rx_last_byte_valid;
}
}
- rx_bytes += rx_wc * fifo_width;
+ if (!(mas->tx_fifo_width % mas->cur_word_len))
+ rx_bytes += rx_wc * fifo_width;
+ else
+ rx_bytes += rx_wc *
+ ((mas->cur_word_len / BITS_PER_BYTE) + 1);
rx_bytes = min_t(int, mas->rx_rem_bytes, rx_bytes);
rx_buf += (mas->cur_xfer->len - mas->rx_rem_bytes);
while (i < rx_bytes) {
u32 fifo_word = 0;
u8 *fifo_byte;
- int read_bytes = min_t(int, (rx_bytes - i), fifo_width);
+ int bytes_per_fifo = fifo_width;
+ int read_bytes = 0;
int j;
+ if ((mas->tx_fifo_width % mas->cur_word_len))
+ bytes_per_fifo =
+ (mas->cur_word_len / BITS_PER_BYTE) + 1;
+ read_bytes = min_t(int, (rx_bytes - i), bytes_per_fifo);
fifo_word = geni_read_reg(mas->base, SE_GENI_RX_FIFOn);
fifo_byte = (u8 *)&fifo_word;
for (j = 0; j < read_bytes; j++)
@@ -1039,8 +1097,14 @@
static irqreturn_t geni_spi_irq(int irq, void *dev)
{
struct spi_geni_master *mas = dev;
- u32 m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
+ u32 m_irq = 0;
+ if (pm_runtime_status_suspended(dev)) {
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: device is suspended\n", __func__);
+ goto exit_geni_spi_irq;
+ }
+ m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
geni_spi_handle_rx(mas);
@@ -1050,7 +1114,26 @@
if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) ||
(m_irq & M_CMD_ABORT_EN)) {
complete(&mas->xfer_done);
+ /*
+ * If this happens, then a CMD_DONE came before all the buffer
+ * bytes were sent out. This is unusual, log this condition and
+ * disable the WM interrupt to prevent the system from stalling
+ * due an interrupt storm.
+ * If this happens when all Rx bytes haven't been received, log
+ * the condition.
+ */
+ if (mas->tx_rem_bytes) {
+ geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Premature Done.tx_rem%d bpw%d\n",
+ __func__, mas->tx_rem_bytes, mas->cur_word_len);
+ }
+ if (mas->rx_rem_bytes)
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s:Premature Done.rx_rem%d bpw%d\n",
+ __func__, mas->rx_rem_bytes, mas->cur_word_len);
}
+exit_geni_spi_irq:
geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c
index ce9dc7e..192661b 100644
--- a/drivers/staging/android/fiq_debugger/fiq_debugger.c
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c
@@ -401,7 +401,7 @@
cmd += 6;
while (*cmd == ' ')
cmd++;
- if ((cmd != '\0') && sysrq_on())
+ if ((*cmd != '\0') && sysrq_on())
kernel_restart(cmd);
else
kernel_restart(NULL);
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 616375a..8d67f76 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -48,6 +48,7 @@
#include <linux/fs.h>
#include <linux/cpuset.h>
#include <linux/vmpressure.h>
+#include <linux/freezer.h>
#define CREATE_TRACE_POINTS
#include <trace/events/almk.h>
@@ -116,6 +117,10 @@
static int vmpressure_file_min;
module_param_named(vmpressure_file_min, vmpressure_file_min, int, 0644);
+/* User knob to enable/disable oom reaping feature */
+static int oom_reaper;
+module_param_named(oom_reaper, oom_reaper, int, 0644);
+
enum {
VMPRESSURE_NO_ADJUST = 0,
VMPRESSURE_ADJUST_ENCROACH,
@@ -406,6 +411,14 @@
}
}
+static void mark_lmk_victim(struct task_struct *tsk)
+{
+ struct mm_struct *mm = tsk->mm;
+
+ if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm))
+ atomic_inc(&tsk->signal->oom_mm->mm_count);
+}
+
static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
struct task_struct *tsk;
@@ -524,7 +537,11 @@
send_sig(SIGKILL, selected, 0);
if (selected->mm)
task_set_lmk_waiting(selected);
+ if (oom_reaper)
+ mark_lmk_victim(selected);
task_unlock(selected);
+ if (oom_reaper)
+ wake_oom_reaper(selected);
trace_lowmemory_kill(selected, cache_size, cache_limit, free);
lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
"to free %ldkB on behalf of '%s' (%d) because\n"
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index ec99790..7458df4 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2385,6 +2385,7 @@
continue;
}
+ set_current_state(TASK_RUNNING);
wp = async->buf_write_ptr;
n1 = min(n, async->prealloc_bufsz - wp);
n2 = n - n1;
@@ -2517,6 +2518,8 @@
}
continue;
}
+
+ set_current_state(TASK_RUNNING);
rp = async->buf_read_ptr;
n1 = min(n, async->prealloc_bufsz - rp);
n2 = n - n1;
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 6b99263..598f0fa 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -472,7 +472,7 @@
long m)
{
struct ad2s1210_state *st = iio_priv(indio_dev);
- bool negative;
+ u16 negative;
int ret = 0;
u16 pos;
s16 vel;
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index b432153..0f63a36 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -45,6 +45,7 @@
{USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
{USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
{USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */
{} /* Terminating entry */
};
diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c
index 6370a5e..defffa7 100644
--- a/drivers/staging/wilc1000/linux_wlan.c
+++ b/drivers/staging/wilc1000/linux_wlan.c
@@ -269,23 +269,12 @@
int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
{
- int i = 0;
- int ret = -1;
- struct wilc_vif *vif;
- struct wilc *wilc;
+ struct wilc_vif *vif = netdev_priv(wilc_netdev);
- vif = netdev_priv(wilc_netdev);
- wilc = vif->wilc;
+ memcpy(vif->bssid, bssid, 6);
+ vif->mode = mode;
- for (i = 0; i < wilc->vif_num; i++)
- if (wilc->vif[i]->ndev == wilc_netdev) {
- memcpy(wilc->vif[i]->bssid, bssid, 6);
- wilc->vif[i]->mode = mode;
- ret = 0;
- break;
- }
-
- return ret;
+ return 0;
}
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
@@ -1212,16 +1201,11 @@
void wilc_netdev_cleanup(struct wilc *wilc)
{
- int i = 0;
- struct wilc_vif *vif[NUM_CONCURRENT_IFC];
+ int i;
- if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
+ if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev))
unregister_inetaddr_notifier(&g_dev_notifier);
- for (i = 0; i < NUM_CONCURRENT_IFC; i++)
- vif[i] = netdev_priv(wilc->vif[i]->ndev);
- }
-
if (wilc && wilc->firmware) {
release_firmware(wilc->firmware);
wilc->firmware = NULL;
@@ -1230,7 +1214,7 @@
if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
if (wilc->vif[i]->ndev)
- if (vif[i]->mac_opened)
+ if (wilc->vif[i]->mac_opened)
wilc_mac_close(wilc->vif[i]->ndev);
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
@@ -1278,9 +1262,9 @@
vif->idx = wl->vif_num;
vif->wilc = *wilc;
+ vif->ndev = ndev;
wl->vif[i] = vif;
- wl->vif[wl->vif_num]->ndev = ndev;
- wl->vif_num++;
+ wl->vif_num = i;
ndev->netdev_ops = &wilc_netdev_ops;
{
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 182b2d5..165c46f 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -666,8 +666,11 @@
void prism2_roamed(struct wlandevice *wlandev)
{
- cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
- NULL, 0, NULL, 0, GFP_KERNEL);
+ struct cfg80211_roam_info roam_info = {
+ .bssid = wlandev->bssid,
+ };
+
+ cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL);
}
/* Structures for declaring wiphy interface */
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 155fe0e..e49fcd5 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -418,6 +418,7 @@
return 0;
}
np->np_thread_state = ISCSI_NP_THREAD_RESET;
+ atomic_inc(&np->np_reset_count);
if (np->np_thread) {
spin_unlock_bh(&np->np_thread_lock);
@@ -2177,6 +2178,7 @@
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
+ kfree(cmd->text_in_ptr);
cmd->text_in_ptr = NULL;
return 0;
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 6128e8e..9ccd5da 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1233,9 +1233,11 @@
flush_signals(current);
spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
+ spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
+ return 1;
} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
spin_unlock_bh(&np->np_thread_lock);
goto exit;
@@ -1268,7 +1270,8 @@
goto exit;
} else if (rc < 0) {
spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
+ np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
iscsit_put_transport(conn->conn_transport);
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 6693d7c..e8efb42 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -490,14 +490,60 @@
static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *);
-static bool iscsi_target_sk_state_check(struct sock *sk)
+static bool __iscsi_target_sk_check_close(struct sock *sk)
{
if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) {
- pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE,"
+ pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE,"
"returning FALSE\n");
- return false;
+ return true;
}
- return true;
+ return false;
+}
+
+static bool iscsi_target_sk_check_close(struct iscsi_conn *conn)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ read_lock_bh(&sk->sk_callback_lock);
+ state = (__iscsi_target_sk_check_close(sk) ||
+ test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+ read_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
+}
+
+static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ read_lock_bh(&sk->sk_callback_lock);
+ state = test_bit(flag, &conn->login_flags);
+ read_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
+}
+
+static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag)
+{
+ bool state = false;
+
+ if (conn->sock) {
+ struct sock *sk = conn->sock->sk;
+
+ write_lock_bh(&sk->sk_callback_lock);
+ state = (__iscsi_target_sk_check_close(sk) ||
+ test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags));
+ if (!state)
+ clear_bit(flag, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ return state;
}
static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login)
@@ -537,6 +583,20 @@
pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n",
conn, current->comm, current->pid);
+ /*
+ * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready()
+ * before initial PDU processing in iscsi_target_start_negotiation()
+ * has completed, go ahead and retry until it's cleared.
+ *
+ * Otherwise if the TCP connection drops while this is occuring,
+ * iscsi_target_start_negotiation() will detect the failure, call
+ * cancel_delayed_work_sync(&conn->login_work), and cleanup the
+ * remaining iscsi connection resources from iscsi_np process context.
+ */
+ if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) {
+ schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10));
+ return;
+ }
spin_lock(&tpg->tpg_state_lock);
state = (tpg->tpg_state == TPG_STATE_ACTIVE);
@@ -544,26 +604,12 @@
if (!state) {
pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n");
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
+ goto err;
}
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
-
- read_lock_bh(&sk->sk_callback_lock);
- state = iscsi_target_sk_state_check(sk);
- read_unlock_bh(&sk->sk_callback_lock);
-
- if (!state) {
- pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
- }
+ if (iscsi_target_sk_check_close(conn)) {
+ pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
+ goto err;
}
conn->login_kworker = current;
@@ -581,34 +627,29 @@
flush_signals(current);
conn->login_kworker = NULL;
- if (rc < 0) {
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
- return;
- }
+ if (rc < 0)
+ goto err;
pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n",
conn, current->comm, current->pid);
rc = iscsi_target_do_login(conn, login);
if (rc < 0) {
- iscsi_target_restore_sock_callbacks(conn);
- iscsi_target_login_drop(conn, login);
- iscsit_deaccess_np(np, tpg, tpg_np);
+ goto err;
} else if (!rc) {
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
-
- write_lock_bh(&sk->sk_callback_lock);
- clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags);
- write_unlock_bh(&sk->sk_callback_lock);
- }
+ if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE))
+ goto err;
} else if (rc == 1) {
iscsi_target_nego_release(conn);
iscsi_post_login_handler(np, conn, zero_tsih);
iscsit_deaccess_np(np, tpg, tpg_np);
}
+ return;
+
+err:
+ iscsi_target_restore_sock_callbacks(conn);
+ iscsi_target_login_drop(conn, login);
+ iscsit_deaccess_np(np, tpg, tpg_np);
}
static void iscsi_target_do_cleanup(struct work_struct *work)
@@ -656,31 +697,54 @@
orig_state_change(sk);
return;
}
+ state = __iscsi_target_sk_check_close(sk);
+ pr_debug("__iscsi_target_sk_close_change: state: %d\n", state);
+
if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {
pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change"
" conn: %p\n", conn);
+ if (state)
+ set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
return;
}
- if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
+ if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n",
conn);
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
return;
}
-
- state = iscsi_target_sk_state_check(sk);
- write_unlock_bh(&sk->sk_callback_lock);
-
- pr_debug("iscsi_target_sk_state_change: state: %d\n", state);
-
- if (!state) {
+ /*
+ * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED,
+ * but only queue conn->login_work -> iscsi_target_do_login_rx()
+ * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared.
+ *
+ * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close()
+ * will detect the dropped TCP connection from delayed workqueue context.
+ *
+ * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial
+ * iscsi_target_start_negotiation() is running, iscsi_target_do_login()
+ * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation()
+ * via iscsi_target_sk_check_and_clear() is responsible for detecting the
+ * dropped TCP connection in iscsi_np process context, and cleaning up
+ * the remaining iscsi connection resources.
+ */
+ if (state) {
pr_debug("iscsi_target_sk_state_change got failed state\n");
- schedule_delayed_work(&conn->login_cleanup_work, 0);
+ set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
+ state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+
+ orig_state_change(sk);
+
+ if (!state)
+ schedule_delayed_work(&conn->login_work, 0);
return;
}
+ write_unlock_bh(&sk->sk_callback_lock);
+
orig_state_change(sk);
}
@@ -945,6 +1009,15 @@
if (iscsi_target_handle_csg_one(conn, login) < 0)
return -1;
if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+ /*
+ * Check to make sure the TCP connection has not
+ * dropped asynchronously while session reinstatement
+ * was occuring in this kthread context, before
+ * transitioning to full feature phase operation.
+ */
+ if (iscsi_target_sk_check_close(conn))
+ return -1;
+
login->tsih = conn->sess->tsih;
login->login_complete = 1;
iscsi_target_restore_sock_callbacks(conn);
@@ -971,21 +1044,6 @@
break;
}
- if (conn->sock) {
- struct sock *sk = conn->sock->sk;
- bool state;
-
- read_lock_bh(&sk->sk_callback_lock);
- state = iscsi_target_sk_state_check(sk);
- read_unlock_bh(&sk->sk_callback_lock);
-
- if (!state) {
- pr_debug("iscsi_target_do_login() failed state for"
- " conn: %p\n", conn);
- return -1;
- }
- }
-
return 0;
}
@@ -1252,13 +1310,25 @@
if (conn->sock) {
struct sock *sk = conn->sock->sk;
- write_lock_bh(&sk->sk_callback_lock);
- set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
- write_unlock_bh(&sk->sk_callback_lock);
- }
+ write_lock_bh(&sk->sk_callback_lock);
+ set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
+ set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+ write_unlock_bh(&sk->sk_callback_lock);
+ }
+ /*
+ * If iscsi_target_do_login returns zero to signal more PDU
+ * exchanges are required to complete the login, go ahead and
+ * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection
+ * is still active.
+ *
+ * Otherwise if TCP connection dropped asynchronously, go ahead
+ * and perform connection cleanup now.
+ */
+ ret = iscsi_target_do_login(conn, login);
+ if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU))
+ ret = -1;
- ret = iscsi_target_do_login(conn, login);
- if (ret < 0) {
+ if (ret < 0) {
cancel_delayed_work_sync(&conn->login_work);
cancel_delayed_work_sync(&conn->login_cleanup_work);
iscsi_target_restore_sock_callbacks(conn);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 1949f50..0e2e71f 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -364,7 +364,7 @@
mutex_lock(&tpg->acl_node_mutex);
if (acl->dynamic_node_acl)
acl->dynamic_node_acl = 0;
- list_del(&acl->acl_list);
+ list_del_init(&acl->acl_list);
mutex_unlock(&tpg->acl_node_mutex);
target_shutdown_sessions(acl);
@@ -540,7 +540,7 @@
* in transport_deregister_session().
*/
list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {
- list_del(&nacl->acl_list);
+ list_del_init(&nacl->acl_list);
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index e8a1f5c..bacfa8f 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -465,7 +465,7 @@
}
mutex_lock(&se_tpg->acl_node_mutex);
- list_del(&nacl->acl_list);
+ list_del_init(&nacl->acl_list);
mutex_unlock(&se_tpg->acl_node_mutex);
core_tpg_wait_for_nacl_pr_ref(nacl);
@@ -537,7 +537,7 @@
spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
if (se_nacl->dynamic_stop)
- list_del(&se_nacl->acl_list);
+ list_del_init(&se_nacl->acl_list);
}
mutex_unlock(&se_tpg->acl_node_mutex);
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 101e51b..bb5f706 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -863,7 +863,7 @@
tzd = thermal_zone_get_zone_by_name(
sensor_data->virt_zone_name);
if (IS_ERR(tzd)) {
- dev_err(dev, "sens:%s not available err: %ld\n",
+ dev_dbg(dev, "sens:%s not available err: %ld\n",
sensor_data->virt_zone_name,
PTR_ERR(tzd));
return tzd;
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index d590d24..4e5546e 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -354,7 +354,13 @@
mutex_lock(&hw->access_lock);
for_each_cpu(cpu_idx, &hw->core_map) {
if (cpu_idx == cpu)
- hw->cdev_data[idx].max_freq = freq;
+ /*
+ * If there is no limits restriction for CPU scaling max
+ * frequency, vote for a very high value. This will allow
+ * the CPU to use the boost frequencies.
+ */
+ hw->cdev_data[idx].max_freq =
+ (freq == hw->max_freq) ? U32_MAX : freq;
if (max_freq > hw->cdev_data[idx].max_freq)
max_freq = hw->cdev_data[idx].max_freq;
idx++;
diff --git a/drivers/thermal/qcom/qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling.c
index af82030..e1a01d8 100644
--- a/drivers/thermal/qcom/qmi_cooling.c
+++ b/drivers/thermal/qcom/qmi_cooling.c
@@ -85,6 +85,10 @@
.type = QMI_CDEV_MAX_LIMIT_TYPE,
},
{
+ .dev_name = "modem_skin",
+ .type = QMI_CDEV_MAX_LIMIT_TYPE,
+ },
+ {
.dev_name = "modem_bw",
.type = QMI_CDEV_MAX_LIMIT_TYPE,
},
diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c
index 923680a..8cb7dc3 100644
--- a/drivers/thermal/qcom/qti_virtual_sensor.c
+++ b/drivers/thermal/qcom/qti_virtual_sensor.c
@@ -46,6 +46,24 @@
"cpu3-gold-usr"},
.logic = VIRT_MAXIMUM,
},
+ {
+ .virt_zone_name = "hexa-silv-max-step",
+ .num_sensors = 6,
+ .sensor_names = {"cpu0-silver-usr",
+ "cpu1-silver-usr",
+ "cpu2-silver-usr",
+ "cpu3-silver-usr",
+ "cpu4-silver-usr",
+ "cpu5-silver-usr"},
+ .logic = VIRT_MAXIMUM,
+ },
+ {
+ .virt_zone_name = "dual-gold-max-step",
+ .num_sensors = 2,
+ .sensor_names = {"cpu0-gold-usr",
+ "cpu1-gold-usr"},
+ .logic = VIRT_MAXIMUM,
+ },
};
int qti_virtual_sensor_register(struct device *dev)
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index f9054cb..c5e2703 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -98,7 +98,9 @@
#define UART_PARAM (0x1)
/* UART DMA Rx GP_IRQ_BITS */
-#define UART_DMA_RX_ERRS (GENMASK(5, 8))
+#define UART_DMA_RX_PARITY_ERR BIT(5)
+#define UART_DMA_RX_ERRS (GENMASK(5, 6))
+#define UART_DMA_RX_BREAK (GENMASK(7, 8))
#define UART_OVERSAMPLING (32)
#define STALE_TIMEOUT (16)
@@ -125,6 +127,7 @@
} while (0)
#define DMA_RX_BUF_SIZE (2048)
+#define CONSOLE_YIELD_LEN (8 * 1024)
struct msm_geni_serial_port {
struct uart_port uport;
char name[20];
@@ -141,7 +144,8 @@
int (*handle_rx)(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
struct device *wrapper_dev;
struct se_geni_rsc serial_rsc;
dma_addr_t tx_dma;
@@ -159,6 +163,7 @@
unsigned int cur_baud;
int ioctl_count;
int edge_count;
+ unsigned int tx_yield_count;
};
static const struct uart_ops msm_geni_serial_pops;
@@ -167,11 +172,13 @@
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
static int handle_rx_hs(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last);
+ unsigned int rx_last,
+ bool drop_rx);
static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
static int msm_geni_serial_power_on(struct uart_port *uport);
static void msm_geni_serial_power_off(struct uart_port *uport);
@@ -681,7 +688,8 @@
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
int i, c;
unsigned char *rx_char;
@@ -694,6 +702,8 @@
*(msm_port->rx_fifo) =
geni_read_reg_nolog(uport->membase, SE_GENI_RX_FIFOn);
+ if (drop_rx)
+ continue;
rx_char = (unsigned char *)msm_port->rx_fifo;
if (i == (rx_fifo_wc - 1)) {
@@ -710,14 +720,16 @@
tty_insert_flip_char(tport, rx_char[c], flag);
}
}
- tty_flip_buffer_push(tport);
+ if (!drop_rx)
+ tty_flip_buffer_push(tport);
return 0;
}
#else
static int handle_rx_console(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
return -EPERM;
}
@@ -1001,7 +1013,8 @@
static int handle_rx_hs(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
- unsigned int rx_last)
+ unsigned int rx_last,
+ bool drop_rx)
{
unsigned char *rx_char;
struct tty_port *tport;
@@ -1016,6 +1029,8 @@
tport = &uport->state->port;
ioread32_rep((uport->membase + SE_GENI_RX_FIFOn), msm_port->rx_fifo,
rx_fifo_wc);
+ if (drop_rx)
+ return 0;
rx_char = (unsigned char *)msm_port->rx_fifo;
ret = tty_insert_flip_string(tport, rx_char, rx_bytes);
@@ -1031,7 +1046,7 @@
return ret;
}
-static int msm_geni_serial_handle_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx)
{
int ret = 0;
unsigned int rx_fifo_status;
@@ -1050,7 +1065,7 @@
rx_last = rx_fifo_status & RX_LAST;
if (rx_fifo_wc)
port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid,
- rx_last);
+ rx_last, drop_rx);
return ret;
}
@@ -1070,6 +1085,14 @@
xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
msm_port->xmit_size = 0;
+ if (uart_console(uport) &&
+ (uport->icount.tx - msm_port->tx_yield_count) > CONSOLE_YIELD_LEN) {
+ msm_port->tx_yield_count = uport->icount.tx;
+ msm_geni_serial_stop_tx(uport);
+ uart_write_wakeup(uport);
+ goto exit_handle_tx;
+ }
+
tx_fifo_status = geni_read_reg_nolog(uport->membase,
SE_GENI_TX_FIFO_STATUS);
if (uart_circ_empty(xmit) && !tx_fifo_status) {
@@ -1128,13 +1151,13 @@
} else {
msm_port->xmit_size = xmit_size;
}
+exit_handle_tx:
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
-exit_handle_tx:
return ret;
}
-static int msm_geni_serial_handle_dma_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
{
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
unsigned int rx_bytes = 0;
@@ -1160,6 +1183,8 @@
__func__, rx_bytes);
goto exit_handle_dma_rx;
}
+ if (drop_rx)
+ goto exit_handle_dma_rx;
tport = &uport->state->port;
ret = tty_insert_flip_string(tport, (unsigned char *)(msm_port->rx_buf),
@@ -1211,6 +1236,7 @@
unsigned long flags;
unsigned int m_irq_en;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ bool drop_rx = false;
spin_lock_irqsave(&uport->lock, flags);
if (uart_console(uport) && uport->suspended)
@@ -1239,21 +1265,29 @@
}
if (!dma) {
- if ((s_irq_status & S_GP_IRQ_0_EN) ||
- (s_irq_status & S_GP_IRQ_1_EN) ||
- (s_irq_status & S_GP_IRQ_2_EN) ||
- (s_irq_status & S_GP_IRQ_3_EN)) {
- IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s.sirq 0x%x.\n", __func__, s_irq_status);
- goto exit_geni_serial_isr;
- }
- if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
- (s_irq_status & S_RX_FIFO_LAST_EN))
- msm_geni_serial_handle_rx(uport);
-
if ((m_irq_status & m_irq_en) &
(M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
msm_geni_serial_handle_tx(uport);
+
+ if ((s_irq_status & S_GP_IRQ_0_EN) ||
+ (s_irq_status & S_GP_IRQ_1_EN)) {
+ if (s_irq_status & S_GP_IRQ_0_EN)
+ uport->icount.parity++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.sirq 0x%x parity:%d\n",
+ __func__, s_irq_status, uport->icount.parity);
+ drop_rx = true;
+ } else if ((s_irq_status & S_GP_IRQ_2_EN) ||
+ (s_irq_status & S_GP_IRQ_3_EN)) {
+ uport->icount.brk++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.sirq 0x%x break:%d\n",
+ __func__, s_irq_status, uport->icount.brk);
+ }
+
+ if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
+ (s_irq_status & S_RX_FIFO_LAST_EN))
+ msm_geni_serial_handle_rx(uport, drop_rx);
} else {
if (dma_tx_status) {
geni_write_reg_nolog(dma_tx_status, uport->membase,
@@ -1272,13 +1306,22 @@
goto exit_geni_serial_isr;
}
if (dma_rx_status & UART_DMA_RX_ERRS) {
+ if (dma_rx_status & UART_DMA_RX_PARITY_ERR)
+ uport->icount.parity++;
IPC_LOG_MSG(msm_port->ipc_log_misc,
- "%s.Rx Errors. 0x%x.\n",
- __func__, dma_rx_status);
- goto exit_geni_serial_isr;
+ "%s.Rx Errors. 0x%x parity:%d\n",
+ __func__, dma_rx_status,
+ uport->icount.parity);
+ drop_rx = true;
+ } else if (dma_rx_status & UART_DMA_RX_BREAK) {
+ uport->icount.brk++;
+ IPC_LOG_MSG(msm_port->ipc_log_misc,
+ "%s.Rx Errors. 0x%x break:%d\n",
+ __func__, dma_rx_status,
+ uport->icount.brk);
}
if (dma_rx_status & RX_DMA_DONE)
- msm_geni_serial_handle_dma_rx(uport);
+ msm_geni_serial_handle_dma_rx(uport, drop_rx);
}
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e07fa76..c0f1e46 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1878,7 +1878,7 @@
/* No more submits can occur */
spin_lock_irq(&hcd_urb_list_lock);
rescan:
- list_for_each_entry (urb, &ep->urb_list, urb_list) {
+ list_for_each_entry_reverse(urb, &ep->urb_list, urb_list) {
int is_in;
if (urb->unlinked)
@@ -2532,6 +2532,8 @@
}
if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
hcd = hcd->shared_hcd;
+ clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+ set_bit(HCD_FLAG_DEAD, &hcd->flags);
if (hcd->rh_registered) {
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 50679bc..3b0cc03 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4741,7 +4741,8 @@
static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
u16 portchange)
{
- int status, i;
+ int status = -ENODEV;
+ int i;
unsigned unit_load;
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
@@ -4945,9 +4946,10 @@
done:
hub_port_disable(hub, port1, 1);
- if (hcd->driver->relinquish_port && !hub->hdev->parent)
- hcd->driver->relinquish_port(hcd, port1);
-
+ if (hcd->driver->relinquish_port && !hub->hdev->parent) {
+ if (status != -ENOTCONN && status != -ENODEV)
+ hcd->driver->relinquish_port(hcd, port1);
+ }
}
/* Handle physical or logical connection change events.
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 3116edf..574da2b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -150,6 +150,9 @@
/* appletouch */
{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Genesys Logic hub, internally used by Moshi USB to Ethernet Adapter */
+ { USB_DEVICE(0x05e3, 0x0616), .driver_info = USB_QUIRK_NO_LPM },
+
/* Avision AV600U */
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
USB_QUIRK_STRING_FETCH_255 },
@@ -249,6 +252,7 @@
{ USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME },
{ USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME },
{ USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME },
+ { USB_DEVICE(0x03f0, 0x2b4a), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Optical Mouse M90/M100 */
{ USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 2776cfe..ef9cf4a 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -127,6 +127,22 @@
*/
#define USB_ACPI_LOCATION_VALID (1 << 31)
+static struct acpi_device *usb_acpi_find_port(struct acpi_device *parent,
+ int raw)
+{
+ struct acpi_device *adev;
+
+ if (!parent)
+ return NULL;
+
+ list_for_each_entry(adev, &parent->children, node) {
+ if (acpi_device_adr(adev) == raw)
+ return adev;
+ }
+
+ return acpi_find_child_device(parent, raw, false);
+}
+
static struct acpi_device *usb_acpi_find_companion(struct device *dev)
{
struct usb_device *udev;
@@ -174,8 +190,10 @@
int raw;
raw = usb_hcd_find_raw_port_number(hcd, port1);
- adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev),
- raw, false);
+
+ adev = usb_acpi_find_port(ACPI_COMPANION(&udev->dev),
+ raw);
+
if (!adev)
return NULL;
} else {
@@ -186,7 +204,9 @@
return NULL;
acpi_bus_get_device(parent_handle, &adev);
- adev = acpi_find_child_device(adev, port1, false);
+
+ adev = usb_acpi_find_port(adev, port1);
+
if (!adev)
return NULL;
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 1c8d8dc..d316821 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2857,8 +2857,7 @@
}
/*
- * Handle EUD based soft detach/attach event, and force USB high speed mode
- * functionality on receiving soft attach event.
+ * Handle EUD based soft detach/attach event
*
* @nb - notifier handler
* @event - event information i.e. soft detach/attach event
@@ -2877,9 +2876,6 @@
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
- /* Force USB High-Speed enumeration Only */
- dwc->maximum_speed = USB_SPEED_HIGH;
- dbg_event(0xFF, "Speed", dwc->maximum_speed);
mdwc->vbus_active = event;
if (dwc->is_drd && !mdwc->in_restart)
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index f910990..d6e77a5 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1533,6 +1533,18 @@
gi = container_of(cdev, struct gadget_info, cdev);
+ /* FIXME: There's a race between usb_gadget_udc_stop() which is likely
+ * to set the gadget driver to NULL in the udc driver and this drivers
+ * gadget disconnect fn which likely checks for the gadget driver to
+ * be a null ptr. It happens that unbind (doing set_gadget_data(NULL))
+ * is called before the gadget driver is set to NULL and the udc driver
+ * calls disconnect fn which results in cdev being a null ptr.
+ */
+ if (cdev == NULL) {
+ WARN(1, "%s: gadget driver already disconnected\n", __func__);
+ return;
+ }
+
/* accessory HID support can be active while the
accessory function is not actually enabled,
so we need to inform it when we are disconnected.
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index a7cb586..9240956 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -864,6 +864,14 @@
.probe = acc_hid_probe,
};
+static void acc_complete_setup_noop(struct usb_ep *ep, struct usb_request *req)
+{
+ /*
+ * Default no-op function when nothing needs to be done for the
+ * setup request
+ */
+}
+
int acc_ctrlrequest(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
@@ -891,6 +899,7 @@
schedule_delayed_work(
&dev->start_work, msecs_to_jiffies(10));
value = 0;
+ cdev->req->complete = acc_complete_setup_noop;
} else if (b_request == ACCESSORY_SEND_STRING) {
dev->string_index = w_index;
cdev->gadget->ep0->driver_data = dev;
@@ -899,10 +908,13 @@
} else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
w_index == 0 && w_length == 0) {
dev->audio_mode = w_value;
+ cdev->req->complete = acc_complete_setup_noop;
value = 0;
} else if (b_request == ACCESSORY_REGISTER_HID) {
+ cdev->req->complete = acc_complete_setup_noop;
value = acc_register_hid(dev, w_value, w_index);
} else if (b_request == ACCESSORY_UNREGISTER_HID) {
+ cdev->req->complete = acc_complete_setup_noop;
value = acc_unregister_hid(dev, w_value);
} else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
spin_lock_irqsave(&dev->lock, flags);
@@ -937,7 +949,7 @@
if (b_request == ACCESSORY_GET_PROTOCOL) {
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
value = sizeof(u16);
-
+ cdev->req->complete = acc_complete_setup_noop;
/* clear any string left over from a previous session */
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
memset(dev->model, 0, sizeof(dev->model));
diff --git a/drivers/usb/gadget/function/f_ccid.h b/drivers/usb/gadget/function/f_ccid.h
index 42a7ebb..935308c 100644
--- a/drivers/usb/gadget/function/f_ccid.h
+++ b/drivers/usb/gadget/function/f_ccid.h
@@ -55,29 +55,29 @@
#define CCID_READ_DTR _IOR('C', 3, int)
struct usb_ccid_notification {
- unsigned char buf[4];
+ __u8 buf[4];
} __packed;
struct ccid_bulk_in_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bStatus;
- unsigned char bError;
- unsigned char bSpecific;
- unsigned char abData[ABDATA_SIZE];
- unsigned char bSizeToSend;
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bStatus;
+ __u8 bError;
+ __u8 bSpecific;
+ __u8 abData[ABDATA_SIZE];
+ __u8 bSizeToSend;
} __packed;
struct ccid_bulk_out_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bSpecific_0;
- unsigned char bSpecific_1;
- unsigned char bSpecific_2;
- unsigned char APDU[ABDATA_SIZE];
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bSpecific_0;
+ __u8 bSpecific_1;
+ __u8 bSpecific_2;
+ __u8 APDU[ABDATA_SIZE];
} __packed;
#endif
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index e908ecf..be22de048 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -386,9 +386,11 @@
ch->priv = priv;
ch->notify = notify;
- spin_lock_irqsave(&ch_lock, flags);
- list_add_tail(&ch->list, &usb_diag_ch_list);
- spin_unlock_irqrestore(&ch_lock, flags);
+ if (!found) {
+ spin_lock_irqsave(&ch_lock, flags);
+ list_add_tail(&ch->list, &usb_diag_ch_list);
+ spin_unlock_irqrestore(&ch_lock, flags);
+ }
return ch;
}
@@ -863,6 +865,7 @@
struct diag_context *dev;
struct usb_diag_ch *_ch;
int found = 0;
+ unsigned long flags;
pr_debug("%s\n", __func__);
@@ -872,9 +875,19 @@
break;
}
}
+
if (!found) {
- pr_err("%s: unable to get diag usb channel\n", __func__);
- return ERR_PTR(-ENODEV);
+ pr_warn("%s: unable to get diag usb channel\n", __func__);
+
+ _ch = kzalloc(sizeof(*_ch), GFP_KERNEL);
+ if (_ch == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ _ch->name = name;
+
+ spin_lock_irqsave(&ch_lock, flags);
+ list_add_tail(&_ch->list, &usb_diag_ch_list);
+ spin_unlock_irqrestore(&ch_lock, flags);
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index ccf9dac..18241f4 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2618,10 +2618,10 @@
info.string_defs = qdss_gsi_string_defs;
info.data_desc = &qdss_gsi_data_intf_desc;
info.data_str_idx = 0;
- info.fs_in_desc = &qdss_gsi_hs_data_desc;
+ info.fs_in_desc = &qdss_gsi_fs_data_desc;
info.hs_in_desc = &qdss_gsi_hs_data_desc;
info.ss_in_desc = &qdss_gsi_ss_data_desc;
- info.fs_desc_hdr = qdss_gsi_hs_data_only_desc;
+ info.fs_desc_hdr = qdss_gsi_fs_data_only_desc;
info.hs_desc_hdr = qdss_gsi_hs_data_only_desc;
info.ss_desc_hdr = qdss_gsi_ss_data_only_desc;
info.in_epname = "gsi-epin";
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 0fe3665..48454b7 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -1340,6 +1340,14 @@
.bInterfaceProtocol = 0xff,
};
+static struct usb_endpoint_descriptor qdss_gsi_fs_data_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(64),
+};
+
static struct usb_endpoint_descriptor qdss_gsi_hs_data_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -1364,6 +1372,12 @@
.wBytesPerInterval = 0,
};
+static struct usb_descriptor_header *qdss_gsi_fs_data_only_desc[] = {
+ (struct usb_descriptor_header *) &qdss_gsi_data_intf_desc,
+ (struct usb_descriptor_header *) &qdss_gsi_fs_data_desc,
+ NULL,
+};
+
static struct usb_descriptor_header *qdss_gsi_hs_data_only_desc[] = {
(struct usb_descriptor_header *) &qdss_gsi_data_intf_desc,
(struct usb_descriptor_header *) &qdss_gsi_hs_data_desc,
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index ba78e3f..d2cfefa 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -685,21 +685,32 @@
return usb3_req;
}
+static void __usb3_request_done(struct renesas_usb3_ep *usb3_ep,
+ struct renesas_usb3_request *usb3_req,
+ int status)
+{
+ struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
+
+ dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
+ usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
+ status);
+ usb3_req->req.status = status;
+ usb3_ep->started = false;
+ list_del_init(&usb3_req->queue);
+ spin_unlock(&usb3->lock);
+ usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
+ spin_lock(&usb3->lock);
+}
+
static void usb3_request_done(struct renesas_usb3_ep *usb3_ep,
struct renesas_usb3_request *usb3_req, int status)
{
struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep);
unsigned long flags;
- dev_dbg(usb3_to_dev(usb3), "giveback: ep%2d, %u, %u, %d\n",
- usb3_ep->num, usb3_req->req.length, usb3_req->req.actual,
- status);
- usb3_req->req.status = status;
spin_lock_irqsave(&usb3->lock, flags);
- usb3_ep->started = false;
- list_del_init(&usb3_req->queue);
+ __usb3_request_done(usb3_ep, usb3_req, status);
spin_unlock_irqrestore(&usb3->lock, flags);
- usb_gadget_giveback_request(&usb3_ep->ep, &usb3_req->req);
}
static void usb3_irq_epc_pipe0_status_end(struct renesas_usb3 *usb3)
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c8989c6..5f4ca78 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -98,6 +98,7 @@
AMD_CHIPSET_HUDSON2,
AMD_CHIPSET_BOLTON,
AMD_CHIPSET_YANGTZE,
+ AMD_CHIPSET_TAISHAN,
AMD_CHIPSET_UNKNOWN,
};
@@ -141,6 +142,11 @@
pinfo->sb_type.gen = AMD_CHIPSET_SB700;
else if (rev >= 0x40 && rev <= 0x4f)
pinfo->sb_type.gen = AMD_CHIPSET_SB800;
+ }
+ pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ 0x145c, NULL);
+ if (pinfo->smbus_dev) {
+ pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
} else {
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
@@ -260,11 +266,12 @@
{
/* Make sure amd chipset type has already been initialized */
usb_amd_find_chipset_info();
- if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE)
- return 0;
-
- dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
- return 1;
+ if (amd_chipset.sb_type.gen == AMD_CHIPSET_YANGTZE ||
+ amd_chipset.sb_type.gen == AMD_CHIPSET_TAISHAN) {
+ dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n");
+ return 1;
+ }
+ return 0;
}
EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk);
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 99beda9..55c624f 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -139,6 +139,7 @@
"Could not flush host TX%d fifo: csr: %04x\n",
ep->epnum, csr))
return;
+ mdelay(1);
}
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 5a96299..e8961b5 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -430,6 +430,7 @@
int num_svids;
struct vdm_tx *vdm_tx;
struct vdm_tx *vdm_tx_retry;
+ struct mutex svid_handler_lock;
struct list_head svid_handlers;
struct list_head instance;
@@ -581,10 +582,15 @@
{
struct usbpd_svid_handler *handler;
- list_for_each_entry(handler, &pd->svid_handlers, entry)
- if (svid == handler->svid)
+ mutex_lock(&pd->svid_handler_lock);
+ list_for_each_entry(handler, &pd->svid_handlers, entry) {
+ if (svid == handler->svid) {
+ mutex_unlock(&pd->svid_handler_lock);
return handler;
+ }
+ }
+ mutex_unlock(&pd->svid_handler_lock);
return NULL;
}
@@ -1412,9 +1418,11 @@
return -EINVAL;
}
- usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid);
-
+ usbpd_dbg(&pd->dev, "registered handler(%pK) for SVID 0x%04x\n",
+ hdlr, hdlr->svid);
+ mutex_lock(&pd->svid_handler_lock);
list_add_tail(&hdlr->entry, &pd->svid_handlers);
+ mutex_unlock(&pd->svid_handler_lock);
hdlr->request_usb_ss_lane = usbpd_release_ss_lane;
/* already connected with this SVID discovered? */
@@ -1436,7 +1444,12 @@
void usbpd_unregister_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr)
{
+
+ usbpd_dbg(&pd->dev, "unregistered handler(%pK) for SVID 0x%04x\n",
+ hdlr, hdlr->svid);
+ mutex_lock(&pd->svid_handler_lock);
list_del_init(&hdlr->entry);
+ mutex_unlock(&pd->svid_handler_lock);
}
EXPORT_SYMBOL(usbpd_unregister_svid);
@@ -1747,6 +1760,7 @@
{
struct usbpd_svid_handler *handler;
+ mutex_lock(&pd->svid_handler_lock);
list_for_each_entry(handler, &pd->svid_handlers, entry) {
if (handler->discovered) {
handler->disconnect(handler);
@@ -1754,6 +1768,7 @@
}
}
+ mutex_unlock(&pd->svid_handler_lock);
pd->vdm_state = VDM_NONE;
kfree(pd->vdm_tx_retry);
pd->vdm_tx_retry = NULL;
@@ -3853,6 +3868,7 @@
hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pd->timer.function = pd_timeout;
mutex_init(&pd->swap_lock);
+ mutex_init(&pd->svid_handler_lock);
pd->usb_psy = power_supply_get_by_name("usb");
if (!pd->usb_psy) {
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
index d544b33..02b67ab 100644
--- a/drivers/usb/renesas_usbhs/rcar3.c
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -20,9 +20,13 @@
/* Low Power Status register (LPSTS) */
#define LPSTS_SUSPM 0x4000
-/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */
+/*
+ * USB General control register 2 (UGCTRL2)
+ * Remarks: bit[31:11] and bit[9:6] should be 0
+ */
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
#define UGCTRL2_USB0SEL_OTG 0x00000030
+#define UGCTRL2_VBUSSEL 0x00000400
static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
{
@@ -34,7 +38,8 @@
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
+ usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG |
+ UGCTRL2_VBUSSEL);
if (enable) {
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 84b444f..470b17b 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -136,6 +136,7 @@
{ USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */
{ USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */
{ USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */
+ { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index ebe51f11..fe12315 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2025,6 +2025,8 @@
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1db4b61..a51b283 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -49,6 +49,7 @@
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+ { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 09d9be8..3b5a15d 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -27,6 +27,7 @@
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
#define ATEN_PRODUCT_ID 0x2008
+#define ATEN_PRODUCT_UC485 0x2021
#define ATEN_PRODUCT_ID2 0x2118
#define IODATA_VENDOR_ID 0x04bb
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index cbea9f3..cde1153 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -124,9 +124,9 @@
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
"Initio Corporation",
- "",
+ "INIC-3069",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
- US_FL_NO_ATA_1X),
+ US_FL_NO_ATA_1X | US_FL_IGNORE_RESIDUE),
/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 76c1ad9..f8a3839 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1097,6 +1097,13 @@
void __user *argp = (void __user *)arg;
long ret = 0;
+ memset(&var, 0, sizeof(var));
+ memset(&fix, 0, sizeof(fix));
+ memset(&con2fb, 0, sizeof(con2fb));
+ memset(&cmap_from, 0, sizeof(cmap_from));
+ memset(&cmap, 0, sizeof(cmap));
+ memset(&event, 0, sizeof(event));
+
switch (cmd) {
case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info))
diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c
index 4da69db..1bdd02a 100644
--- a/drivers/xen/biomerge.c
+++ b/drivers/xen/biomerge.c
@@ -10,8 +10,7 @@
unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page));
unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page));
- return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&
- ((bfn1 == bfn2) || ((bfn1+1) == bfn2));
+ return bfn1 + PFN_DOWN(vec1->bv_offset + vec1->bv_len) == bfn2;
#else
/*
* XXX: Add support for merging bio_vec when using different page
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 14a37ff..705bb5f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4759,10 +4759,6 @@
else
flush = BTRFS_RESERVE_NO_FLUSH;
spin_lock(&space_info->lock);
- if (can_overcommit(root, space_info, orig, flush)) {
- spin_unlock(&space_info->lock);
- break;
- }
if (list_empty(&space_info->tickets) &&
list_empty(&space_info->priority_tickets)) {
spin_unlock(&space_info->lock);
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 900ffaf..7b79a54 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -188,7 +188,7 @@
/*
* read a single page, without unlocking it.
*/
-static int readpage_nounlock(struct file *filp, struct page *page)
+static int ceph_do_readpage(struct file *filp, struct page *page)
{
struct inode *inode = file_inode(filp);
struct ceph_inode_info *ci = ceph_inode(inode);
@@ -218,7 +218,7 @@
err = ceph_readpage_from_fscache(inode, page);
if (err == 0)
- goto out;
+ return -EINPROGRESS;
dout("readpage inode %p file %p page %p index %lu\n",
inode, filp, page, page->index);
@@ -248,8 +248,11 @@
static int ceph_readpage(struct file *filp, struct page *page)
{
- int r = readpage_nounlock(filp, page);
- unlock_page(page);
+ int r = ceph_do_readpage(filp, page);
+ if (r != -EINPROGRESS)
+ unlock_page(page);
+ else
+ r = 0;
return r;
}
@@ -1235,7 +1238,7 @@
goto retry_locked;
r = writepage_nounlock(page, NULL);
if (r < 0)
- goto fail_nosnap;
+ goto fail_unlock;
goto retry_locked;
}
@@ -1263,11 +1266,14 @@
}
/* we need to read it. */
- r = readpage_nounlock(file, page);
- if (r < 0)
- goto fail_nosnap;
+ r = ceph_do_readpage(file, page);
+ if (r < 0) {
+ if (r == -EINPROGRESS)
+ return -EAGAIN;
+ goto fail_unlock;
+ }
goto retry_locked;
-fail_nosnap:
+fail_unlock:
unlock_page(page);
return r;
}
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 5bc5d37..a2d7997 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -240,13 +240,7 @@
}
}
-static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
-{
- if (!error)
- SetPageUptodate(page);
-}
-
-static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
+static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
{
if (!error)
SetPageUptodate(page);
@@ -274,7 +268,7 @@
return -ENOBUFS;
ret = fscache_read_or_alloc_page(ci->fscache, page,
- ceph_vfs_readpage_complete, NULL,
+ ceph_readpage_from_fscache_complete, NULL,
GFP_KERNEL);
switch (ret) {
@@ -303,7 +297,7 @@
return -ENOBUFS;
ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
- ceph_vfs_readpage_complete_unlock,
+ ceph_readpage_from_fscache_complete,
NULL, mapping_gfp_mask(mapping));
switch (ret) {
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 789ff1d..dd3e236 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -183,15 +183,20 @@
}
/*
+ * Don't allow path components longer than the server max.
* Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix.
*/
static int
-check_name(struct dentry *direntry)
+check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
int i;
+ if (unlikely(direntry->d_name.len >
+ le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
+ return -ENAMETOOLONG;
+
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') {
@@ -489,10 +494,6 @@
return finish_no_open(file, res);
}
- rc = check_name(direntry);
- if (rc)
- return rc;
-
xid = get_xid();
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
@@ -505,6 +506,11 @@
}
tcon = tlink_tcon(tlink);
+
+ rc = check_name(direntry, tcon);
+ if (rc)
+ goto out_free_xid;
+
server = tcon->ses->server;
if (server->ops->new_lease_key)
@@ -765,7 +771,7 @@
}
pTcon = tlink_tcon(tlink);
- rc = check_name(direntry);
+ rc = check_name(direntry, pTcon);
if (rc)
goto lookup_out;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 7c1c6c3..0437e5f 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2930,8 +2930,8 @@
kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
- kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
- kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+ kst->f_bfree = kst->f_bavail =
+ le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
return;
}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index dc0d141..1e1449a 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -84,8 +84,8 @@
#define NUMBER_OF_SMB2_COMMANDS 0x0013
-/* BB FIXME - analyze following length BB */
-#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
+/* 4 len + 52 transform hdr + 64 hdr + 56 create rsp */
+#define MAX_SMB2_HDR_SIZE 0x00b0
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index dc4a34f..5b96ba7 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -524,8 +524,13 @@
wait_queue_head_t *whead;
rcu_read_lock();
- /* If it is cleared by POLLFREE, it should be rcu-safe */
- whead = rcu_dereference(pwq->whead);
+ /*
+ * If it is cleared by POLLFREE, it should be rcu-safe.
+ * If we read NULL we need a barrier paired with
+ * smp_store_release() in ep_poll_callback(), otherwise
+ * we rely on whead->lock.
+ */
+ whead = smp_load_acquire(&pwq->whead);
if (whead)
remove_wait_queue(whead, &pwq->wait);
rcu_read_unlock();
@@ -1010,17 +1015,6 @@
struct eventpoll *ep = epi->ep;
int ewake = 0;
- if ((unsigned long)key & POLLFREE) {
- ep_pwq_from_wait(wait)->whead = NULL;
- /*
- * whead = NULL above can race with ep_remove_wait_queue()
- * which can do another remove_wait_queue() after us, so we
- * can't use __remove_wait_queue(). whead->lock is held by
- * the caller.
- */
- list_del_init(&wait->task_list);
- }
-
spin_lock_irqsave(&ep->lock, flags);
/*
@@ -1102,10 +1096,26 @@
if (pwake)
ep_poll_safewake(&ep->poll_wait);
- if (epi->event.events & EPOLLEXCLUSIVE)
- return ewake;
+ if (!(epi->event.events & EPOLLEXCLUSIVE))
+ ewake = 1;
- return 1;
+ if ((unsigned long)key & POLLFREE) {
+ /*
+ * If we race with ep_remove_wait_queue() it can miss
+ * ->whead = NULL and do another remove_wait_queue() after
+ * us, so we can't use __remove_wait_queue().
+ */
+ list_del_init(&wait->task_list);
+ /*
+ * ->whead != NULL protects us from the race with ep_free()
+ * or ep_remove(), ep_remove_wait_queue() takes whead->lock
+ * held by the caller. Once we nullify it, nothing protects
+ * ep/epi or even wait.
+ */
+ smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
+ }
+
+ return ewake;
}
/*
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 9e77c08..d17d12e 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -469,6 +469,8 @@
lastoff = page_offset(page);
bh = head = page_buffers(page);
do {
+ if (lastoff + bh->b_size <= startoff)
+ goto next;
if (buffer_uptodate(bh) ||
buffer_unwritten(bh)) {
if (whence == SEEK_DATA)
@@ -483,6 +485,7 @@
unlock_page(page);
goto out;
}
+next:
lastoff += bh->b_size;
bh = bh->b_this_page;
} while (bh != head);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index cf68100..95bf466 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1926,7 +1926,8 @@
n_desc_blocks = o_desc_blocks +
le16_to_cpu(es->s_reserved_gdt_blocks);
n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb);
- n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb);
+ n_blocks_count = (ext4_fsblk_t)n_group *
+ EXT4_BLOCKS_PER_GROUP(sb);
n_group--; /* set to last group number */
}
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 75c95659..21d829b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -55,7 +55,7 @@
{
struct fuse_file *ff;
- ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+ ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL);
if (unlikely(!ff))
return NULL;
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index f31fd0d..b1daeaf 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -121,6 +121,7 @@
config PNFS_BLOCK
tristate
depends on NFS_V4_1 && BLK_DEV_DM
+ depends on 64BIT || LBDAF
default NFS_V4
config PNFS_OBJLAYOUT
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index f7a3f6b..9009989 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -30,6 +30,7 @@
{
nfs4_print_deviceid(&mirror_ds->id_node.deviceid);
nfs4_pnfs_ds_put(mirror_ds->ds);
+ kfree(mirror_ds->ds_versions);
kfree_rcu(mirror_ds, id_node.rcu);
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 46ca788..a53b8e0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7410,7 +7410,7 @@
cdata->res.server_scope = NULL;
}
/* Save the EXCHANGE_ID verifier session trunk tests */
- memcpy(clp->cl_confirm.data, cdata->args.verifier->data,
+ memcpy(clp->cl_confirm.data, cdata->args.verifier.data,
sizeof(clp->cl_confirm.data));
}
out:
@@ -7447,7 +7447,6 @@
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
u32 sp4_how, struct rpc_xprt *xprt)
{
- nfs4_verifier verifier;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
.rpc_cred = cred,
@@ -7470,8 +7469,7 @@
if (!calldata)
goto out;
- if (!xprt)
- nfs4_init_boot_verifier(clp, &verifier);
+ nfs4_init_boot_verifier(clp, &calldata->args.verifier);
status = nfs4_init_uniform_client_string(clp);
if (status)
@@ -7516,9 +7514,8 @@
task_setup_data.rpc_xprt = xprt;
task_setup_data.flags =
RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC;
- calldata->args.verifier = &clp->cl_confirm;
- } else {
- calldata->args.verifier = &verifier;
+ memcpy(calldata->args.verifier.data, clp->cl_confirm.data,
+ sizeof(calldata->args.verifier.data));
}
calldata->args.client = clp;
#ifdef CONFIG_NFS_V4_1_MIGRATION
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c9c4d985..5e2724a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1761,7 +1761,7 @@
int len = 0;
encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
- encode_nfs4_verifier(xdr, args->verifier);
+ encode_nfs4_verifier(xdr, &args->verifier);
encode_string(xdr, strlen(args->client->cl_owner_id),
args->client->cl_owner_id);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4e7a56a..2c4f7a2 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -129,7 +129,7 @@
argp->p = page_address(argp->pagelist[0]);
argp->pagelist++;
if (argp->pagelen < PAGE_SIZE) {
- argp->end = argp->p + (argp->pagelen>>2);
+ argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
argp->pagelen = 0;
} else {
argp->end = argp->p + (PAGE_SIZE>>2);
@@ -1246,9 +1246,7 @@
argp->pagelen -= pages * PAGE_SIZE;
len -= pages * PAGE_SIZE;
- argp->p = (__be32 *)page_address(argp->pagelist[0]);
- argp->pagelist++;
- argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
+ next_decode_page(argp);
}
argp->p += XDR_QUADLEN(len);
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
index 6076c34..5ac0b0b 100644
--- a/fs/sdcardfs/file.c
+++ b/fs/sdcardfs/file.c
@@ -104,12 +104,19 @@
{
long err = -ENOTTY;
struct file *lower_file;
+ const struct cred *saved_cred = NULL;
+ struct dentry *dentry = file->f_path.dentry;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
lower_file = sdcardfs_lower_file(file);
/* XXX: use vfs_ioctl if/when VFS exports it */
if (!lower_file || !lower_file->f_op)
goto out;
+
+ /* save current_cred and override it */
+ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+
if (lower_file->f_op->unlocked_ioctl)
err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
@@ -117,6 +124,7 @@
if (!err)
sdcardfs_copy_and_fix_attrs(file_inode(file),
file_inode(lower_file));
+ REVERT_CRED(saved_cred);
out:
return err;
}
@@ -127,15 +135,23 @@
{
long err = -ENOTTY;
struct file *lower_file;
+ const struct cred *saved_cred = NULL;
+ struct dentry *dentry = file->f_path.dentry;
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
lower_file = sdcardfs_lower_file(file);
/* XXX: use vfs_ioctl if/when VFS exports it */
if (!lower_file || !lower_file->f_op)
goto out;
+
+ /* save current_cred and override it */
+ OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+
if (lower_file->f_op->compat_ioctl)
err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+ REVERT_CRED(saved_cred);
out:
return err;
}
diff --git a/include/asm-generic/topology.h b/include/asm-generic/topology.h
index fc824e2..5d2add1 100644
--- a/include/asm-generic/topology.h
+++ b/include/asm-generic/topology.h
@@ -48,7 +48,11 @@
#define parent_node(node) ((void)(node),0)
#endif
#ifndef cpumask_of_node
-#define cpumask_of_node(node) ((void)node, cpu_online_mask)
+ #ifdef CONFIG_NEED_MULTIPLE_NODES
+ #define cpumask_of_node(node) ((node) == 0 ? cpu_online_mask : cpu_none_mask)
+ #else
+ #define cpumask_of_node(node) ((void)node, cpu_online_mask)
+ #endif
#endif
#ifndef pcibus_to_node
#define pcibus_to_node(bus) ((void)(bus), -1)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 31e1d63..dc81e52 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -60,6 +60,22 @@
#define ALIGN_FUNCTION() . = ALIGN(8)
/*
+ * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which
+ * generates .data.identifier sections, which need to be pulled in with
+ * .data. We don't want to pull in .data..other sections, which Linux
+ * has defined. Same for text and bss.
+ */
+#ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
+#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
+#define DATA_MAIN .data .data.[0-9a-zA-Z_]*
+#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]*
+#else
+#define TEXT_MAIN .text
+#define DATA_MAIN .data
+#define BSS_MAIN .bss
+#endif
+
+/*
* Align to a 32 byte boundary equal to the
* alignment gcc 4.5 uses for a struct
*/
@@ -198,12 +214,9 @@
/*
* .data section
- * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections generates
- * .data.identifier which needs to be pulled in with .data, but don't want to
- * pull in .data..stuff which has its own requirements. Same for bss.
*/
#define DATA_DATA \
- *(.data .data.[0-9a-zA-Z_]*) \
+ *(DATA_MAIN) \
*(.ref.data) \
*(.data..shared_aligned) /* percpu related */ \
MEM_KEEP(init.data) \
@@ -436,16 +449,17 @@
VMLINUX_SYMBOL(__security_initcall_end) = .; \
}
-/* .text section. Map to function alignment to avoid address changes
+/*
+ * .text section. Map to function alignment to avoid address changes
* during second ld run in second ld pass when generating System.map
- * LD_DEAD_CODE_DATA_ELIMINATION option enables -ffunction-sections generates
- * .text.identifier which needs to be pulled in with .text , but some
- * architectures define .text.foo which is not intended to be pulled in here.
- * Those enabling LD_DEAD_CODE_DATA_ELIMINATION must ensure they don't have
- * conflicting section names, and must pull in .text.[0-9a-zA-Z_]* */
+ *
+ * TEXT_MAIN here will match .text.fixup and .text.unlikely if dead
+ * code elimination is enabled, so these sections should be converted
+ * to use ".." first.
+ */
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
- *(.text.hot .text .text.fixup .text.unlikely) \
+ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \
*(.ref.text) \
MEM_KEEP(init.text) \
MEM_KEEP(exit.text) \
@@ -613,7 +627,7 @@
BSS_FIRST_SECTIONS \
*(.bss..page_aligned) \
*(.dynbss) \
- *(.bss .bss.[0-9a-zA-Z_]*) \
+ *(BSS_MAIN) \
*(COMMON) \
}
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index a13b031..3101141 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -40,6 +40,7 @@
*/
s64 min_value;
u64 max_value;
+ bool value_from_signed;
};
enum bpf_stack_slot_type {
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 9ddaf05..6be0299 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -10,7 +10,6 @@
CPUHP_PERF_X86_PREPARE,
CPUHP_PERF_X86_UNCORE_PREP,
CPUHP_PERF_X86_AMD_UNCORE_PREP,
- CPUHP_PERF_X86_RAPL_PREP,
CPUHP_PERF_BFIN,
CPUHP_PERF_POWER,
CPUHP_PERF_SUPERH,
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index bfc204e..cd32a49 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -16,6 +16,19 @@
#ifdef CONFIG_CPUSETS
+/*
+ * Static branch rewrites can happen in an arbitrary order for a given
+ * key. In code paths where we need to loop with read_mems_allowed_begin() and
+ * read_mems_allowed_retry() to get a consistent view of mems_allowed, we need
+ * to ensure that begin() always gets rewritten before retry() in the
+ * disabled -> enabled transition. If not, then if local irqs are disabled
+ * around the loop, we can deadlock since retry() would always be
+ * comparing the latest value of the mems_allowed seqcount against 0 as
+ * begin() still would see cpusets_enabled() as false. The enabled -> disabled
+ * transition should happen in reverse order for the same reasons (want to stop
+ * looking at real value of mems_allowed.sequence in retry() first).
+ */
+extern struct static_key_false cpusets_pre_enable_key;
extern struct static_key_false cpusets_enabled_key;
static inline bool cpusets_enabled(void)
{
@@ -30,12 +43,14 @@
static inline void cpuset_inc(void)
{
+ static_branch_inc(&cpusets_pre_enable_key);
static_branch_inc(&cpusets_enabled_key);
}
static inline void cpuset_dec(void)
{
static_branch_dec(&cpusets_enabled_key);
+ static_branch_dec(&cpusets_pre_enable_key);
}
extern int cpuset_init(void);
@@ -113,7 +128,7 @@
*/
static inline unsigned int read_mems_allowed_begin(void)
{
- if (!cpusets_enabled())
+ if (!static_branch_unlikely(&cpusets_pre_enable_key))
return 0;
return read_seqcount_begin(¤t->mems_allowed_seq);
@@ -127,7 +142,7 @@
*/
static inline bool read_mems_allowed_retry(unsigned int seq)
{
- if (!cpusets_enabled())
+ if (!static_branch_unlikely(&cpusets_enabled_key))
return false;
return read_seqcount_retry(¤t->mems_allowed_seq, seq);
diff --git a/include/linux/dma-mapping-fast.h b/include/linux/dma-mapping-fast.h
index 560f047..64ae548 100644
--- a/include/linux/dma-mapping-fast.h
+++ b/include/linux/dma-mapping-fast.h
@@ -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
@@ -41,19 +41,17 @@
};
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
-int fast_smmu_attach_device(struct device *dev,
+int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping);
-void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping);
+void fast_smmu_release_mapping(struct kref *kref);
#else
-static inline int fast_smmu_attach_device(struct device *dev,
+static inline int fast_smmu_init_mapping(struct device *dev,
struct dma_iommu_mapping *mapping)
{
return -ENODEV;
}
-static inline void fast_smmu_detach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
+static inline void fast_smmu_release_mapping(struct kref *kref)
{
}
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 026aa0a..6d6114a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -941,9 +941,9 @@
/* Page cache limit. The filesystems should put that into their s_maxbytes
limits, otherwise bad things can happen in VM. */
#if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE (((loff_t)PAGE_SIZE << (BITS_PER_LONG-1))-1)
+#define MAX_LFS_FILESIZE ((loff_t)ULONG_MAX << PAGE_SHIFT)
#elif BITS_PER_LONG==64
-#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffffLL)
+#define MAX_LFS_FILESIZE ((loff_t)LLONG_MAX)
#endif
#define FL_POSIX 1
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 0b8aedf..99eb77a 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -142,6 +142,7 @@
DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT,
DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
DOMAIN_ATTR_CB_STALL_DISABLE,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR,
DOMAIN_ATTR_MAX,
};
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 37e5178..600c905 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -64,6 +64,7 @@
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
#define __init_memblock __meminit
#define __initdata_memblock __meminitdata
+void memblock_discard(void);
#else
#define __init_memblock
#define __initdata_memblock
@@ -77,8 +78,6 @@
int nid, ulong flags);
phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align);
-phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
-phys_addr_t get_allocated_memblock_memory_regions_info(phys_addr_t *addr);
void memblock_allow_resize(void);
int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
int memblock_add(phys_addr_t base, phys_addr_t size);
@@ -114,6 +113,9 @@
void __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start,
phys_addr_t *out_end);
+void __memblock_free_early(phys_addr_t base, phys_addr_t size);
+void __memblock_free_late(phys_addr_t base, phys_addr_t size);
+
/**
* for_each_mem_range - iterate through memblock areas from type_a and not
* included in type_b. Or just type_a if type_b is NULL.
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3139ea4..5942478 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -515,6 +515,10 @@
*/
bool tlb_flush_pending;
#endif
+#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
+ /* See flush_tlb_batched_pending() */
+ bool tlb_flush_batched;
+#endif
struct uprobes_state uprobes_state;
#ifdef CONFIG_X86_INTEL_MPX
/* address of the bounds directory */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index f214b0c..1e07ed2 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -226,6 +226,7 @@
unsigned int resp_arg;
unsigned int dev_pend_tasks;
bool resp_err;
+ bool skip_err_handling;
int tag; /* used for command queuing */
u8 ctx_id;
};
@@ -543,6 +544,7 @@
unsigned int bus_resume_flags;
#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0)
#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1)
+ bool ignore_bus_resume_flags;
unsigned int sdio_irqs;
struct task_struct *sdio_irq_thread;
diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h
index c298666..a584e0a 100644
--- a/include/linux/msm-bus.h
+++ b/include/linux/msm-bus.h
@@ -130,6 +130,8 @@
uint32_t cl, unsigned int index);
int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle,
uint32_t cl);
+int msm_bus_noc_throttle_wa(bool enable);
+int msm_bus_noc_priority_wa(bool enable);
/* AXI Port configuration APIs */
int msm_bus_axi_porthalt(int master_port);
@@ -211,6 +213,16 @@
return 0;
}
+static inline int msm_bus_noc_throttle_wa(bool enable)
+{
+ return 0;
+}
+
+static inline int msm_bus_noc_priority_wa(bool enable)
+{
+ return 0;
+}
+
#endif
#if defined(CONFIG_OF) && defined(CONFIG_QCOM_BUS_SCALING)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index beb1e10..3bf867a 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1199,7 +1199,7 @@
struct nfs41_exchange_id_args {
struct nfs_client *client;
- nfs4_verifier *verifier;
+ nfs4_verifier verifier;
u32 flags;
struct nfs41_state_protection state_protect;
};
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 3ca2526..4443a29 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -24,6 +24,9 @@
#define NMI_WATCHDOG_ENABLED (1 << NMI_WATCHDOG_ENABLED_BIT)
#define SOFT_WATCHDOG_ENABLED (1 << SOFT_WATCHDOG_ENABLED_BIT)
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts);
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+
/**
* touch_nmi_watchdog - restart NMI watchdog timeout.
*
@@ -31,8 +34,11 @@
* may be used to reset the timeout - for code which intentionally
* disables interrupts for a long time. This call is stateless.
*/
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI)
#include <asm/nmi.h>
+#endif
+
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
extern void touch_nmi_watchdog(void);
#else
static inline void touch_nmi_watchdog(void)
@@ -130,6 +136,7 @@
#define sysctl_softlockup_all_cpu_backtrace 0
#define sysctl_hardlockup_all_cpu_backtrace 0
#endif
+
extern bool is_hardlockup(void);
struct ctl_table;
extern int proc_watchdog(struct ctl_table *, int ,
diff --git a/include/linux/oom.h b/include/linux/oom.h
index b986840..5b5d4c7 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -82,6 +82,8 @@
extern void dump_tasks(struct mem_cgroup *memcg,
const nodemask_t *nodemask);
+extern void wake_oom_reaper(struct task_struct *tsk);
+
/* sysctls */
extern int sysctl_oom_dump_tasks;
extern int sysctl_oom_kill_allocating_task;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 7c5b2b4..b6c8c92 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -199,6 +199,8 @@
POWER_SUPPLY_PROP_LOW_POWER,
POWER_SUPPLY_PROP_COOL_TEMP,
POWER_SUPPLY_PROP_WARM_TEMP,
+ POWER_SUPPLY_PROP_COLD_TEMP,
+ POWER_SUPPLY_PROP_HOT_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
diff --git a/include/linux/property.h b/include/linux/property.h
index 856e50b..338f9b7 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -33,6 +33,8 @@
DEV_DMA_COHERENT,
};
+struct fwnode_handle *dev_fwnode(struct device *dev);
+
bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval);
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index 6c70444..b83507c 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -340,9 +340,9 @@
__PTR_RING_PEEK_CALL_v; \
})
-static inline void **__ptr_ring_init_queue_alloc(int size, gfp_t gfp)
+static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp)
{
- return kzalloc(ALIGN(size * sizeof(void *), SMP_CACHE_BYTES), gfp);
+ return kcalloc(size, sizeof(void *), gfp);
}
static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
@@ -417,7 +417,8 @@
* In particular if you consume ring in interrupt or BH context, you must
* disable interrupts/BH when doing so.
*/
-static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings,
+static inline int ptr_ring_resize_multiple(struct ptr_ring **rings,
+ unsigned int nrings,
int size,
gfp_t gfp, void (*destroy)(void *))
{
@@ -425,7 +426,7 @@
void ***queues;
int i;
- queues = kmalloc(nrings * sizeof *queues, gfp);
+ queues = kmalloc_array(nrings, sizeof(*queues), gfp);
if (!queues)
goto noqueues;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e1345ec..e5541af 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -928,6 +928,16 @@
#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */
+#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
+ SIGNAL_STOP_CONTINUED)
+
+static inline void signal_set_stop_flags(struct signal_struct *sig,
+ unsigned int flags)
+{
+ WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
+ sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
+}
+
/* If true, all threads except ->group_exit_task have pending SIGKILL */
static inline int signal_group_exit(const struct signal_struct *sig)
{
@@ -2380,23 +2390,6 @@
}
static inline int pid_alive(const struct task_struct *p);
-static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
-{
- pid_t pid = 0;
-
- rcu_read_lock();
- if (pid_alive(tsk))
- pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
- rcu_read_unlock();
-
- return pid;
-}
-
-static inline pid_t task_ppid_nr(const struct task_struct *tsk)
-{
- return task_ppid_nr_ns(tsk, &init_pid_ns);
-}
static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk,
struct pid_namespace *ns)
@@ -2431,6 +2424,23 @@
return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, NULL);
}
+static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
+{
+ pid_t pid = 0;
+
+ rcu_read_lock();
+ if (pid_alive(tsk))
+ pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns);
+ rcu_read_unlock();
+
+ return pid;
+}
+
+static inline pid_t task_ppid_nr(const struct task_struct *tsk)
+{
+ return task_ppid_nr_ns(tsk, &init_pid_ns);
+}
+
/* obsolete, do not use */
static inline pid_t task_pgrp_nr(struct task_struct *tsk)
{
@@ -3964,4 +3974,6 @@
void cpufreq_remove_update_util_hook(int cpu);
#endif /* CONFIG_CPU_FREQ */
+extern DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
+
#endif
diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h
index f4dfade..be8b902 100644
--- a/include/linux/skb_array.h
+++ b/include/linux/skb_array.h
@@ -162,7 +162,8 @@
}
static inline int skb_array_resize_multiple(struct skb_array **rings,
- int nrings, int size, gfp_t gfp)
+ int nrings, unsigned int size,
+ gfp_t gfp)
{
BUILD_BUG_ON(offsetof(struct skb_array, ring));
return ptr_ring_resize_multiple((struct ptr_ring **)rings,
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 084b12b..4c53635 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -226,7 +226,7 @@
* (PAGE_SIZE*2). Larger requests are passed to the page allocator.
*/
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
-#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT)
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
@@ -239,7 +239,7 @@
* be allocated from the same page.
*/
#define KMALLOC_SHIFT_HIGH PAGE_SHIFT
-#define KMALLOC_SHIFT_MAX 30
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 0a34489..17a33f3 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -23,6 +23,8 @@
extern int snprint_stack_trace(char *buf, size_t size,
struct stack_trace *trace, int spaces);
+#define BACKPORTED_EXPORT_SAVE_STACK_TRACE_TSK_ARM
+
#ifdef CONFIG_USER_STACKTRACE_SUPPORT
extern void save_stack_trace_user(struct stack_trace *trace);
#else
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 6eb24cc..a700e5f 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -47,7 +47,7 @@
#define THERMAL_WEIGHT_DEFAULT 0
/* Max sensors that can be used for a single virtual thermalzone */
-#define THERMAL_MAX_VIRT_SENSORS 5
+#define THERMAL_MAX_VIRT_SENSORS 8
/* use value, which < 0K, to indicate an invalid/uninitialized temperature */
#define THERMAL_TEMP_INVALID -274000
diff --git a/include/linux/usb/ccid_desc.h b/include/linux/usb/ccid_desc.h
index 9a0c726..2e6dbb5 100644
--- a/include/linux/usb/ccid_desc.h
+++ b/include/linux/usb/ccid_desc.h
@@ -86,27 +86,27 @@
* Table 5.1-1 Smart Card Device Class descriptors
*/
struct usb_ccid_class_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType;
- unsigned short bcdCCID;
- unsigned char bMaxSlotIndex;
- unsigned char bVoltageSupport;
- unsigned long dwProtocols;
- unsigned long dwDefaultClock;
- unsigned long dwMaximumClock;
- unsigned char bNumClockSupported;
- unsigned long dwDataRate;
- unsigned long dwMaxDataRate;
- unsigned char bNumDataRatesSupported;
- unsigned long dwMaxIFSD;
- unsigned long dwSynchProtocols;
- unsigned long dwMechanical;
- unsigned long dwFeatures;
- unsigned long dwMaxCCIDMessageLength;
- unsigned char bClassGetResponse;
- unsigned char bClassEnvelope;
- unsigned short wLcdLayout;
- unsigned char bPINSupport;
- unsigned char bMaxCCIDBusySlots;
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u16 bcdCCID;
+ __u8 bMaxSlotIndex;
+ __u8 bVoltageSupport;
+ __u32 dwProtocols;
+ __u32 dwDefaultClock;
+ __u32 dwMaximumClock;
+ __u8 bNumClockSupported;
+ __u32 dwDataRate;
+ __u32 dwMaxDataRate;
+ __u8 bNumDataRatesSupported;
+ __u32 dwMaxIFSD;
+ __u32 dwSynchProtocols;
+ __u32 dwMechanical;
+ __u32 dwFeatures;
+ __u32 dwMaxCCIDMessageLength;
+ __u8 bClassGetResponse;
+ __u8 bClassEnvelope;
+ __u16 wLcdLayout;
+ __u8 bPINSupport;
+ __u8 bMaxCCIDBusySlots;
} __packed;
#endif
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index fc6e221..733a21e 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -311,6 +311,7 @@
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
+ __WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
@@ -409,7 +410,8 @@
* Pointer to the allocated workqueue on success, %NULL on failure.
*/
#define alloc_ordered_workqueue(fmt, flags, args...) \
- alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
+ alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | \
+ __WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
#define create_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 82b4b53..73da337 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -49,6 +49,13 @@
#define CFG80211_REKEY_DATA_KEK_LEN 1
/**
+ * Indicate backport support for the new cfg80211_roamed event which unifies the
+ * old APIs cfg80211_roamed and cfg80211_roamed_bss and takes a structure to
+ * update roam information to the kernel.
+ */
+#define CFG80211_ROAMED_API_UNIFIED 1
+
+/**
* DOC: Introduction
*
* cfg80211 is the configuration API for 802.11 devices in Linux. It bridges
@@ -2661,8 +2668,7 @@
* indication of requesting reassociation.
* In both the driver-initiated and new connect() call initiated roaming
* cases, the result of roaming is indicated with a call to
- * cfg80211_roamed() or cfg80211_roamed_bss().
- * (invoked with the wireless_dev mutex held)
+ * cfg80211_roamed(). (invoked with the wireless_dev mutex held)
* @update_connect_params: Update the connect parameters while connected to a
* BSS. The updated parameters can be used by driver/firmware for
* subsequent BSS selection (roaming) decisions and to form the
@@ -5301,51 +5307,50 @@
}
/**
+ * struct cfg80211_roam_info - driver initiated roaming information
+ *
+ * @channel: the channel of the new AP
+ * @bss: entry of bss to which STA got roamed (may be %NULL if %bssid is set)
+ * @bssid: the BSSID of the new AP (may be %NULL if %bss is set)
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @authorized: true if the 802.1X authentication was done by the driver or is
+ * not needed (e.g., when Fast Transition protocol was used), false
+ * otherwise. Ignored for networks that don't use 802.1X authentication.
+ */
+struct cfg80211_roam_info {
+ struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss;
+ const u8 *bssid;
+ const u8 *req_ie;
+ size_t req_ie_len;
+ const u8 *resp_ie;
+ size_t resp_ie_len;
+ bool authorized;
+};
+
+/**
* cfg80211_roamed - notify cfg80211 of roaming
*
* @dev: network device
- * @channel: the channel of the new AP
- * @bssid: the BSSID of the new AP
- * @req_ie: association request IEs (maybe be %NULL)
- * @req_ie_len: association request IEs length
- * @resp_ie: association response IEs (may be %NULL)
- * @resp_ie_len: assoc response IEs length
+ * @info: information about the new BSS. struct &cfg80211_roam_info.
* @gfp: allocation flags
*
- * It should be called by the underlying driver whenever it roamed
- * from one AP to another while connected.
- */
-void cfg80211_roamed(struct net_device *dev,
- struct ieee80211_channel *channel,
- const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
-
-/**
- * cfg80211_roamed_bss - notify cfg80211 of roaming
- *
- * @dev: network device
- * @bss: entry of bss to which STA got roamed
- * @req_ie: association request IEs (maybe be %NULL)
- * @req_ie_len: association request IEs length
- * @resp_ie: association response IEs (may be %NULL)
- * @resp_ie_len: assoc response IEs length
- * @gfp: allocation flags
- *
- * This is just a wrapper to notify cfg80211 of roaming event with driver
- * passing bss to avoid a race in timeout of the bss entry. It should be
- * called by the underlying driver whenever it roamed from one AP to another
- * while connected. Drivers which have roaming implemented in firmware
- * may use this function to avoid a race in bss entry timeout where the bss
- * entry of the new AP is seen in the driver, but gets timed out by the time
- * it is accessed in __cfg80211_roamed() due to delay in scheduling
+ * This function may be called with the driver passing either the BSSID of the
+ * new AP or passing the bss entry to avoid a race in timeout of the bss entry.
+ * It should be called by the underlying driver whenever it roamed from one AP
+ * to another while connected. Drivers which have roaming implemented in
+ * firmware should pass the bss entry to avoid a race in bss entry timeout where
+ * the bss entry of the new AP is seen in the driver, but gets timed out by the
+ * time it is accessed in __cfg80211_roamed() due to delay in scheduling
* rdev->event_work. In case of any failures, the reference is released
- * either in cfg80211_roamed_bss() or in __cfg80211_romed(), Otherwise,
- * it will be released while diconneting from the current bss.
+ * either in cfg80211_roamed() or in __cfg80211_romed(), Otherwise, it will be
+ * released while diconneting from the current bss.
*/
-void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
+ gfp_t gfp);
/**
* cfg80211_disconnected - notify cfg80211 that connection was dropped
diff --git a/include/net/ip.h b/include/net/ip.h
index 9816365..4ef6792 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -342,7 +342,7 @@
!forwarding)
return dst_mtu(dst);
- return min(dst->dev->mtu, IP_MAX_MTU);
+ return min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
}
static inline unsigned int ip_skb_dst_mtu(struct sock *sk,
@@ -354,7 +354,7 @@
return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
}
- return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
+ return min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU);
}
u32 ip_idents_reserve(u32 hash, int segs);
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index e0f4109..c2aa73e 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -556,7 +556,8 @@
memcpy(stream + lcp_len,
((char *) &iwe->u) + IW_EV_POINT_OFF,
IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
- memcpy(stream + point_len, extra, iwe->u.data.length);
+ if (iwe->u.data.length && extra)
+ memcpy(stream + point_len, extra, iwe->u.data.length);
stream += event_len;
}
return stream;
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e6aa0a2..f18fc1a 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -768,8 +768,11 @@
old = *pold;
*pold = new;
if (old != NULL) {
- qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
+ unsigned int qlen = old->q.qlen;
+ unsigned int backlog = old->qstats.backlog;
+
qdisc_reset(old);
+ qdisc_tree_reduce_backlog(old, qlen, backlog);
}
sch_tree_unlock(sch);
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 31acc3f..61d9ce8 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -460,6 +460,8 @@
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
+ (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\
+ (void *)chunk + end) &&\
pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
pos.v += SCTP_PAD4(ntohs(pos.p->length)))
@@ -470,6 +472,8 @@
#define _sctp_walk_errors(err, chunk_hdr, end)\
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
sizeof(sctp_chunkhdr_t));\
+ ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\
+ (void *)chunk_hdr + end) &&\
(void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
ntohs(err->length) >= sizeof(sctp_errhdr_t); \
err = (sctp_errhdr_t *)((void *)err + SCTP_PAD4(ntohs(err->length))))
diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h
index 50e4b8c..e67ee0e 100644
--- a/include/soc/qcom/memory_dump.h
+++ b/include/soc/qcom/memory_dump.h
@@ -83,6 +83,7 @@
MSM_DUMP_DATA_RPM = 0xEA,
MSM_DUMP_DATA_SCANDUMP = 0xEB,
MSM_DUMP_DATA_RPMH = 0xEC,
+ MSM_DUMP_DATA_POWER_REGS = 0xED,
MSM_DUMP_DATA_TMC_ETF = 0xF0,
MSM_DUMP_DATA_TMC_REG = 0x100,
MSM_DUMP_DATA_LOG_BUF = 0x110,
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
index 33b2e75..6021c3a 100644
--- a/include/target/iscsi/iscsi_target_core.h
+++ b/include/target/iscsi/iscsi_target_core.h
@@ -563,6 +563,7 @@
#define LOGIN_FLAGS_READ_ACTIVE 1
#define LOGIN_FLAGS_CLOSED 2
#define LOGIN_FLAGS_READY 4
+#define LOGIN_FLAGS_INITIAL_PDU 8
unsigned long login_flags;
struct delayed_work login_work;
struct delayed_work login_cleanup_work;
@@ -784,6 +785,7 @@
int np_sock_type;
enum np_thread_state_table np_thread_state;
bool enabled;
+ atomic_t np_reset_count;
enum iscsi_timer_flags_table np_login_timer_flags;
u32 np_exports;
enum np_flags_table np_flags;
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index 285508a..1a43659 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -295,6 +295,44 @@
struct sde_drm_de_v1 de;
};
+/* Number of dest scalers supported */
+#define SDE_MAX_DS_COUNT 2
+
+/*
+ * Destination scaler flag config
+ */
+#define SDE_DRM_DESTSCALER_ENABLE 0x1
+#define SDE_DRM_DESTSCALER_SCALE_UPDATE 0x2
+#define SDE_DRM_DESTSCALER_ENHANCER_UPDATE 0x4
+#define SDE_DRM_DESTSCALER_PU_ENABLE 0x8
+
+/**
+ * struct sde_drm_dest_scaler_cfg - destination scaler config structure
+ * @flags: Flag to switch between mode for destination scaler
+ * refer to destination scaler flag config
+ * @index: Destination scaler selection index
+ * @lm_width: Layer mixer width configuration
+ * @lm_height: Layer mixer height configuration
+ * @scaler_cfg: The scaling parameters for all the mode except disable
+ * Userspace pointer to struct sde_drm_scaler_v2
+ */
+struct sde_drm_dest_scaler_cfg {
+ uint32_t flags;
+ uint32_t index;
+ uint32_t lm_width;
+ uint32_t lm_height;
+ uint64_t scaler_cfg;
+};
+
+/**
+ * struct sde_drm_dest_scaler_data - destination scaler data struct
+ * @num_dest_scaler: Number of dest scalers to be configured
+ * @ds_cfg: Destination scaler block configuration
+ */
+struct sde_drm_dest_scaler_data {
+ uint32_t num_dest_scaler;
+ struct sde_drm_dest_scaler_cfg ds_cfg[SDE_MAX_DS_COUNT];
+};
/*
* Define constants for struct sde_drm_csc
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 8c0fc7b..9fbdc11 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -546,6 +546,12 @@
* well to remain backwards compatible.
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
* sent as an event when the card/driver roamed by itself.
+ * When used as an event, and the driver roamed in a network that requires
+ * 802.1X authentication, %NL80211_ATTR_PORT_AUTHORIZED should be set
+ * if the 802.1X authentication was done by the driver or if roaming was
+ * done using Fast Transition protocol (in which case 802.1X authentication
+ * is not needed). If %NL80211_ATTR_PORT_AUTHORIZED is not set, user space
+ * is responsible for the 802.1X authentication.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -2066,6 +2072,10 @@
*
* @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
* This is used with @NL80211_CMD_SET_PMKSA.
+ * @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_ROAMED
+ * notification indicating that that 802.1X authentication was done by
+ * the driver or is not needed (because roaming used the Fast Transition
+ * protocol).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2486,6 +2496,13 @@
NL80211_ATTR_PMK,
+ NL80211_ATTR_SCHED_SCAN_MULTI,
+ NL80211_ATTR_SCHED_SCAN_MAX_REQS,
+
+ NL80211_ATTR_WANT_1X_4WAY_HS,
+ NL80211_ATTR_PMKR0_NAME,
+ NL80211_ATTR_PORT_AUTHORIZED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 26506d5..d750568 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1126,6 +1126,14 @@
#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 114)
+#define V4L2_CID_MPEG_VIDC_VIDEO_FLIP (V4L2_CID_MPEG_MSM_VIDC_BASE + 115)
+enum v4l2_mpeg_vidc_video_flip {
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH = 3,
+};
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 23a8ccf..fee26a9 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -23,6 +23,7 @@
#define CAM_CCI_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 10)
#define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11)
#define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12)
+#define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13)
/* cam_req_mgr hdl info */
#define CAM_REQ_MGR_HDL_IDX_POS 8
diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h
index ac370ba..2fe7f2b 100644
--- a/include/uapi/media/cam_sensor.h
+++ b/include/uapi/media/cam_sensor.h
@@ -7,6 +7,7 @@
#define CAM_SENSOR_PROBE_CMD (CAM_COMMON_OPCODE_MAX + 1)
#define CAM_FLASH_MAX_LED_TRIGGERS 3
+#define MAX_OIS_NAME_SIZE 32
/**
* struct cam_sensor_query_cap - capabilities info for sensor
*
@@ -75,6 +76,16 @@
} __attribute__((packed));
/**
+ * struct cam_ois_query_cap_t - capabilities info for ois
+ *
+ * @slot_info : Indicates about the slotId or cell Index
+ */
+struct cam_ois_query_cap_t {
+ uint32_t slot_info;
+ uint16_t reserved;
+} __attribute__((packed));
+
+/**
* struct cam_cmd_i2c_info - Contains slave I2C related info
*
* @slave_addr : Slave address
@@ -88,6 +99,42 @@
} __attribute__((packed));
/**
+ * struct cam_ois_opcode - Contains OIS opcode
+ *
+ * @prog : OIS FW prog register address
+ * @coeff : OIS FW coeff register address
+ * @pheripheral : OIS pheripheral
+ * @memory : OIS memory
+ */
+struct cam_ois_opcode {
+ uint32_t prog;
+ uint32_t coeff;
+ uint32_t pheripheral;
+ uint32_t memory;
+} __attribute__((packed));
+
+/**
+ * struct cam_cmd_ois_info - Contains OIS slave info
+ *
+ * @slave_addr : OIS i2c slave address
+ * @i2c_freq_mode : i2c frequency mode
+ * @ois_fw_flag : indicates if fw is present or not
+ * @is_ois_calib : indicates the calibration data is available
+ * @ois_name : OIS name
+ * @opcode : opcode
+ * @cmd_type : Explains type of command
+ */
+struct cam_cmd_ois_info {
+ uint16_t slave_addr;
+ uint8_t i2c_freq_mode;
+ uint8_t ois_fw_flag;
+ uint8_t is_ois_calib;
+ char ois_name[MAX_OIS_NAME_SIZE];
+ struct cam_ois_opcode opcode;
+ uint8_t cmd_type;
+} __attribute__((packed));
+
+/**
* struct cam_cmd_probe - Contains sensor slave info
*
* @data_type : Slave register data type
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 0d302a8..690e1e3 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -457,13 +457,15 @@
list_del(&krule->rlist);
if (list_empty(&watch->rules)) {
+ /*
+ * audit_remove_watch() drops our reference to 'parent' which
+ * can get freed. Grab our own reference to be safe.
+ */
+ audit_get_parent(parent);
audit_remove_watch(watch);
-
- if (list_empty(&parent->watches)) {
- audit_get_parent(parent);
+ if (list_empty(&parent->watches))
fsnotify_destroy_mark(&parent->mark, audit_watch_group);
- audit_put_parent(parent);
- }
+ audit_put_parent(parent);
}
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8ce679d..779c871 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -139,7 +139,7 @@
struct bpf_verifier_stack_elem *next;
};
-#define BPF_COMPLEXITY_LIMIT_INSNS 65536
+#define BPF_COMPLEXITY_LIMIT_INSNS 98304
#define BPF_COMPLEXITY_LIMIT_STACK 1024
struct bpf_call_arg_meta {
@@ -682,12 +682,13 @@
return -EACCES;
}
-static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+static bool __is_pointer_value(bool allow_ptr_leaks,
+ const struct bpf_reg_state *reg)
{
- if (env->allow_ptr_leaks)
+ if (allow_ptr_leaks)
return false;
- switch (env->cur_state.regs[regno].type) {
+ switch (reg->type) {
case UNKNOWN_VALUE:
case CONST_IMM:
return false;
@@ -696,6 +697,11 @@
}
}
+static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
+{
+ return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
+}
+
static int check_ptr_alignment(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, int off, int size)
{
@@ -1467,6 +1473,65 @@
return 0;
}
+static int evaluate_reg_imm_alu_unknown(struct bpf_verifier_env *env,
+ struct bpf_insn *insn)
+{
+ struct bpf_reg_state *regs = env->cur_state.regs;
+ struct bpf_reg_state *dst_reg = ®s[insn->dst_reg];
+ struct bpf_reg_state *src_reg = ®s[insn->src_reg];
+ u8 opcode = BPF_OP(insn->code);
+ s64 imm_log2 = __ilog2_u64((long long)dst_reg->imm);
+
+ /* BPF_X code with src_reg->type UNKNOWN_VALUE here. */
+ if (src_reg->imm > 0 && dst_reg->imm) {
+ switch (opcode) {
+ case BPF_ADD:
+ /* dreg += sreg
+ * where both have zero upper bits. Adding them
+ * can only result making one more bit non-zero
+ * in the larger value.
+ * Ex. 0xffff (imm=48) + 1 (imm=63) = 0x10000 (imm=47)
+ * 0xffff (imm=48) + 0xffff = 0x1fffe (imm=47)
+ */
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
+ dst_reg->imm--;
+ break;
+ case BPF_AND:
+ /* dreg &= sreg
+ * AND can not extend zero bits only shrink
+ * Ex. 0x00..00ffffff
+ * & 0x0f..ffffffff
+ * ----------------
+ * 0x00..00ffffff
+ */
+ dst_reg->imm = max(src_reg->imm, 63 - imm_log2);
+ break;
+ case BPF_OR:
+ /* dreg |= sreg
+ * OR can only extend zero bits
+ * Ex. 0x00..00ffffff
+ * | 0x0f..ffffffff
+ * ----------------
+ * 0x0f..00ffffff
+ */
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
+ break;
+ case BPF_SUB:
+ case BPF_MUL:
+ case BPF_RSH:
+ case BPF_LSH:
+ /* These may be flushed out later */
+ default:
+ mark_reg_unknown_value(regs, insn->dst_reg);
+ }
+ } else {
+ mark_reg_unknown_value(regs, insn->dst_reg);
+ }
+
+ dst_reg->type = UNKNOWN_VALUE;
+ return 0;
+}
+
static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
@@ -1475,6 +1540,9 @@
struct bpf_reg_state *src_reg = ®s[insn->src_reg];
u8 opcode = BPF_OP(insn->code);
+ if (BPF_SRC(insn->code) == BPF_X && src_reg->type == UNKNOWN_VALUE)
+ return evaluate_reg_imm_alu_unknown(env, insn);
+
/* dst_reg->type == CONST_IMM here, simulate execution of 'add' insn.
* Don't care about overflow or negative values, just add them
*/
@@ -1530,10 +1598,24 @@
}
/* We don't know anything about what was done to this register, mark it
- * as unknown.
+ * as unknown. Also, if both derived bounds came from signed/unsigned
+ * mixed compares and one side is unbounded, we cannot really do anything
+ * with them as boundaries cannot be trusted. Thus, arithmetic of two
+ * regs of such kind will get invalidated bounds on the dst side.
*/
- if (min_val == BPF_REGISTER_MIN_RANGE &&
- max_val == BPF_REGISTER_MAX_RANGE) {
+ if ((min_val == BPF_REGISTER_MIN_RANGE &&
+ max_val == BPF_REGISTER_MAX_RANGE) ||
+ (BPF_SRC(insn->code) == BPF_X &&
+ ((min_val != BPF_REGISTER_MIN_RANGE &&
+ max_val == BPF_REGISTER_MAX_RANGE) ||
+ (min_val == BPF_REGISTER_MIN_RANGE &&
+ max_val != BPF_REGISTER_MAX_RANGE) ||
+ (dst_reg->min_value != BPF_REGISTER_MIN_RANGE &&
+ dst_reg->max_value == BPF_REGISTER_MAX_RANGE) ||
+ (dst_reg->min_value == BPF_REGISTER_MIN_RANGE &&
+ dst_reg->max_value != BPF_REGISTER_MAX_RANGE)) &&
+ regs[insn->dst_reg].value_from_signed !=
+ regs[insn->src_reg].value_from_signed)) {
reset_reg_range_values(regs, insn->dst_reg);
return;
}
@@ -1542,10 +1624,12 @@
* do our normal operations to the register, we need to set the values
* to the min/max since they are undefined.
*/
- if (min_val == BPF_REGISTER_MIN_RANGE)
- dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
- if (max_val == BPF_REGISTER_MAX_RANGE)
- dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ if (opcode != BPF_SUB) {
+ if (min_val == BPF_REGISTER_MIN_RANGE)
+ dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+ if (max_val == BPF_REGISTER_MAX_RANGE)
+ dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ }
switch (opcode) {
case BPF_ADD:
@@ -1555,10 +1639,17 @@
dst_reg->max_value += max_val;
break;
case BPF_SUB:
+ /* If one of our values was at the end of our ranges, then the
+ * _opposite_ value in the dst_reg goes to the end of our range.
+ */
+ if (min_val == BPF_REGISTER_MIN_RANGE)
+ dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+ if (max_val == BPF_REGISTER_MAX_RANGE)
+ dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
- dst_reg->min_value -= min_val;
+ dst_reg->min_value -= max_val;
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
- dst_reg->max_value -= max_val;
+ dst_reg->max_value -= min_val;
break;
case BPF_MUL:
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
@@ -1808,6 +1899,7 @@
* register as unknown.
*/
if (env->allow_ptr_leaks &&
+ BPF_CLASS(insn->code) == BPF_ALU64 && opcode == BPF_ADD &&
(dst_reg->type == PTR_TO_MAP_VALUE ||
dst_reg->type == PTR_TO_MAP_VALUE_ADJ))
dst_reg->type = PTR_TO_MAP_VALUE_ADJ;
@@ -1876,38 +1968,63 @@
struct bpf_reg_state *false_reg, u64 val,
u8 opcode)
{
+ bool value_from_signed = true;
+ bool is_range = true;
+
switch (opcode) {
case BPF_JEQ:
/* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure.
*/
true_reg->max_value = true_reg->min_value = val;
+ is_range = false;
break;
case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure;
*/
false_reg->max_value = false_reg->min_value = val;
+ is_range = false;
break;
case BPF_JGT:
- /* Unsigned comparison, the minimum value is 0. */
- false_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGT:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGT) {
+ /* Unsigned comparison, the minimum value is 0. */
+ false_reg->min_value = 0;
+ }
/* If this is false then we know the maximum val is val,
* otherwise we know the min val is val+1.
*/
false_reg->max_value = val;
+ false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val + 1;
+ true_reg->value_from_signed = value_from_signed;
break;
case BPF_JGE:
- /* Unsigned comparison, the minimum value is 0. */
- false_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGE:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGE) {
+ /* Unsigned comparison, the minimum value is 0. */
+ false_reg->min_value = 0;
+ }
/* If this is false then we know the maximum value is val - 1,
* otherwise we know the mimimum value is val.
*/
false_reg->max_value = val - 1;
+ false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val;
+ true_reg->value_from_signed = value_from_signed;
break;
default:
break;
@@ -1915,6 +2032,12 @@
check_reg_overflow(false_reg);
check_reg_overflow(true_reg);
+ if (is_range) {
+ if (__is_pointer_value(false, false_reg))
+ reset_reg_range_values(false_reg, 0);
+ if (__is_pointer_value(false, true_reg))
+ reset_reg_range_values(true_reg, 0);
+ }
}
/* Same as above, but for the case that dst_reg is a CONST_IMM reg and src_reg
@@ -1924,39 +2047,64 @@
struct bpf_reg_state *false_reg, u64 val,
u8 opcode)
{
+ bool value_from_signed = true;
+ bool is_range = true;
+
switch (opcode) {
case BPF_JEQ:
/* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure.
*/
true_reg->max_value = true_reg->min_value = val;
+ is_range = false;
break;
case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure;
*/
false_reg->max_value = false_reg->min_value = val;
+ is_range = false;
break;
case BPF_JGT:
- /* Unsigned comparison, the minimum value is 0. */
- true_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGT:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGT) {
+ /* Unsigned comparison, the minimum value is 0. */
+ true_reg->min_value = 0;
+ }
/*
* If this is false, then the val is <= the register, if it is
* true the register <= to the val.
*/
false_reg->min_value = val;
+ false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val - 1;
+ true_reg->value_from_signed = value_from_signed;
break;
case BPF_JGE:
- /* Unsigned comparison, the minimum value is 0. */
- true_reg->min_value = 0;
+ value_from_signed = false;
+ /* fallthrough */
case BPF_JSGE:
+ if (true_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(true_reg, 0);
+ if (false_reg->value_from_signed != value_from_signed)
+ reset_reg_range_values(false_reg, 0);
+ if (opcode == BPF_JGE) {
+ /* Unsigned comparison, the minimum value is 0. */
+ true_reg->min_value = 0;
+ }
/* If this is false then constant < register, if it is true then
* the register < constant.
*/
false_reg->min_value = val + 1;
+ false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val;
+ true_reg->value_from_signed = value_from_signed;
break;
default:
break;
@@ -1964,6 +2112,12 @@
check_reg_overflow(false_reg);
check_reg_overflow(true_reg);
+ if (is_range) {
+ if (__is_pointer_value(false, false_reg))
+ reset_reg_range_values(false_reg, 0);
+ if (__is_pointer_value(false, true_reg))
+ reset_reg_range_values(true_reg, 0);
+ }
}
static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
@@ -2390,6 +2544,7 @@
env->explored_states[t + 1] = STATE_LIST_MARK;
} else {
/* conditional jump with two edges */
+ env->explored_states[t] = STATE_LIST_MARK;
ret = push_insn(t, t + 1, FALLTHROUGH, env);
if (ret == 1)
goto peek_stack;
@@ -2548,6 +2703,12 @@
rcur->type != NOT_INIT))
continue;
+ /* Don't care about the reg->id in this case. */
+ if (rold->type == PTR_TO_MAP_VALUE_OR_NULL &&
+ rcur->type == PTR_TO_MAP_VALUE_OR_NULL &&
+ rold->map_ptr == rcur->map_ptr)
+ continue;
+
if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET &&
compare_ptrs_to_packet(rold, rcur))
continue;
@@ -2682,6 +2843,9 @@
goto process_bpf_exit;
}
+ if (need_resched())
+ cond_resched();
+
if (log_level && do_print_state) {
verbose("\nfrom %d to %d:", prev_insn_idx, insn_idx);
print_verifier_state(&env->cur_state);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 7bb21fd..26c624e 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -3508,11 +3508,11 @@
cgrp->subtree_control &= ~disable;
ret = cgroup_apply_control(cgrp);
-
cgroup_finalize_control(cgrp, ret);
+ if (ret)
+ goto out_unlock;
kernfs_activate(cgrp->kn);
- ret = 0;
out_unlock:
cgroup_kn_unlock(of->kn);
return ret ?: nbytes;
@@ -5744,6 +5744,10 @@
if (ss->bind)
ss->bind(init_css_set.subsys[ssid]);
+
+ mutex_lock(&cgroup_mutex);
+ css_populate_dir(init_css_set.subsys[ssid]);
+ mutex_unlock(&cgroup_mutex);
}
/* init_css_set.subsys[] has been updated, re-hash */
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
index 80df048..7dc5b07 100644
--- a/kernel/configs/android-base.config
+++ b/kernel/configs/android-base.config
@@ -37,6 +37,7 @@
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IPV6=y
@@ -140,11 +141,6 @@
CONFIG_PPP_MPPE=y
CONFIG_PREEMPT=y
CONFIG_PROFILING=y
-CONFIG_QFMT_V2=y
-CONFIG_QUOTA=y
-CONFIG_QUOTACTL=y
-CONFIG_QUOTA_NETLINK_INTERFACE=y
-CONFIG_QUOTA_TREE=y
CONFIG_RANDOMIZE_BASE=y
CONFIG_RTC_CLASS=y
CONFIG_RT_GROUP_SCHED=y
@@ -154,7 +150,6 @@
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY_SELINUX=y
CONFIG_STAGING=y
-CONFIG_SYNC=y
CONFIG_TUN=y
CONFIG_UID_SYS_STATS=y
CONFIG_UNIX=y
diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config
index 36ec6c1..da146fa 100644
--- a/kernel/configs/android-recommended.config
+++ b/kernel/configs/android-recommended.config
@@ -107,6 +107,11 @@
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_RAM=y
+CONFIG_QFMT_V2=y
+CONFIG_QUOTA=y
+CONFIG_QUOTACTL=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QUOTA_TREE=y
CONFIG_SCHEDSTATS=y
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_SND=y
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index a99cd8d..d3a7411 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -61,6 +61,7 @@
#include <linux/cgroup.h>
#include <linux/wait.h>
+DEFINE_STATIC_KEY_FALSE(cpusets_pre_enable_key);
DEFINE_STATIC_KEY_FALSE(cpusets_enabled_key);
/* See "Frequency meter" comments, below. */
@@ -1907,6 +1908,7 @@
{
.name = "memory_pressure",
.read_u64 = cpuset_read_u64,
+ .private = FILE_MEMORY_PRESSURE,
},
{
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0d4a401..f6e81b5 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9894,28 +9894,27 @@
goto err_context;
/*
- * Do not allow to attach to a group in a different
- * task or CPU context:
+ * Make sure we're both events for the same CPU;
+ * grouping events for different CPUs is broken; since
+ * you can never concurrently schedule them anyhow.
*/
- if (move_group) {
- /*
- * Make sure we're both on the same task, or both
- * per-cpu events.
- */
- if (group_leader->ctx->task != ctx->task)
- goto err_context;
+ if (group_leader->cpu != event->cpu)
+ goto err_context;
- /*
- * Make sure we're both events for the same CPU;
- * grouping events for different CPUs is broken; since
- * you can never concurrently schedule them anyhow.
- */
- if (group_leader->cpu != event->cpu)
- goto err_context;
- } else {
- if (group_leader->ctx != ctx)
- goto err_context;
- }
+ /*
+ * Make sure we're both on the same task, or both
+ * per-CPU events.
+ */
+ if (group_leader->ctx->task != ctx->task)
+ goto err_context;
+
+ /*
+ * Do not allow to attach to a group in a different task
+ * or CPU context. If we're moving SW events, we'll fix
+ * this up later, so allow that.
+ */
+ if (!move_group && group_leader->ctx != ctx)
+ goto err_context;
/*
* Only a group leader can be exclusive or pinned
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index f9ec9ad..a1de021 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1254,8 +1254,6 @@
void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
{
- newmm->uprobes_state.xol_area = NULL;
-
if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) {
set_bit(MMF_HAS_UPROBES, &newmm->flags);
/* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */
diff --git a/kernel/fork.c b/kernel/fork.c
index 39c0709..610aded 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -745,6 +745,13 @@
#endif
}
+static void mm_init_uprobes_state(struct mm_struct *mm)
+{
+#ifdef CONFIG_UPROBES
+ mm->uprobes_state.xol_area = NULL;
+#endif
+}
+
static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
struct user_namespace *user_ns)
{
@@ -766,11 +773,13 @@
mm_init_cpumask(mm);
mm_init_aio(mm);
mm_init_owner(mm, p);
+ RCU_INIT_POINTER(mm->exe_file, NULL);
mmu_notifier_mm_init(mm);
clear_tlb_flush_pending(mm);
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
mm->pmd_huge_pte = NULL;
#endif
+ mm_init_uprobes_state(mm);
if (current->mm) {
mm->flags = current->mm->flags & MMF_INIT_MASK;
diff --git a/kernel/futex.c b/kernel/futex.c
index 4c6b6e6..88bad86 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -668,13 +668,14 @@
* this reference was taken by ihold under the page lock
* pinning the inode in place so i_lock was unnecessary. The
* only way for this check to fail is if the inode was
- * truncated in parallel so warn for now if this happens.
+ * truncated in parallel which is almost certainly an
+ * application bug. In such a case, just retry.
*
* We are not calling into get_futex_key_refs() in file-backed
* cases, therefore a successful atomic_inc return below will
* guarantee that get_futex_key() will still imply smp_mb(); (B).
*/
- if (WARN_ON_ONCE(!atomic_inc_not_zero(&inode->i_count))) {
+ if (!atomic_inc_not_zero(&inode->i_count)) {
rcu_read_unlock();
put_page(page);
diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c
index 2f9df37..c51a49c 100644
--- a/kernel/gcov/base.c
+++ b/kernel/gcov/base.c
@@ -98,6 +98,12 @@
}
EXPORT_SYMBOL(__gcov_merge_icall_topn);
+void __gcov_exit(void)
+{
+ /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_exit);
+
/**
* gcov_enable_events - enable event reporting through gcov_event()
*
diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c
index 6a5c239..46a18e7 100644
--- a/kernel/gcov/gcc_4_7.c
+++ b/kernel/gcov/gcc_4_7.c
@@ -18,7 +18,9 @@
#include <linux/vmalloc.h>
#include "gcov.h"
-#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
+#if (__GNUC__ >= 7)
+#define GCOV_COUNTERS 9
+#elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
#define GCOV_COUNTERS 10
#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
#define GCOV_COUNTERS 9
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 077c87f..f30110e 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -895,13 +895,15 @@
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
- unsigned long flags;
+ unsigned long flags, trigger, tmp;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
+ trigger = irqd_get_trigger_type(&desc->irq_data);
+
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
if (irq_settings_has_no_balance_set(desc))
@@ -913,7 +915,11 @@
if (irq_settings_is_level(desc))
irqd_set(&desc->irq_data, IRQD_LEVEL);
- irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));
+ tmp = irq_settings_get_trigger_mask(desc);
+ if (tmp != IRQ_TYPE_NONE)
+ trigger = tmp;
+
+ irqd_set(&desc->irq_data, trigger);
irq_put_desc_unlock(desc, flags);
}
diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c
index 1a9abc1..259a22a 100644
--- a/kernel/irq/ipi.c
+++ b/kernel/irq/ipi.c
@@ -165,7 +165,7 @@
struct irq_data *data = irq_get_irq_data(irq);
struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL;
- if (!data || !ipimask || cpu > nr_cpu_ids)
+ if (!data || !ipimask || cpu >= nr_cpu_ids)
return INVALID_HWIRQ;
if (!cpumask_test_cpu(cpu, ipimask))
@@ -195,7 +195,7 @@
if (!chip->ipi_send_single && !chip->ipi_send_mask)
return -EINVAL;
- if (cpu > nr_cpu_ids)
+ if (cpu >= nr_cpu_ids)
return -EINVAL;
if (dest) {
diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c
index e99d860..10e6d8b 100644
--- a/kernel/locking/spinlock_debug.c
+++ b/kernel/locking/spinlock_debug.c
@@ -110,38 +110,14 @@
lock->owner_cpu = -1;
}
-static void __spin_lock_debug(raw_spinlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
-
- for (i = 0; i < loops; i++) {
- if (arch_spin_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- spin_bug(lock, "lockup suspected");
-#ifdef CONFIG_SMP
- trigger_all_cpu_backtrace();
-#endif
-
- /*
- * The trylock above was causing a livelock. Give the lower level arch
- * specific lock code a chance to acquire the lock. We have already
- * printed a warning/backtrace at this point. The non-debug arch
- * specific code might actually succeed in acquiring the lock. If it is
- * not successful, the end-result is the same - there is no forward
- * progress.
- */
- arch_spin_lock(&lock->raw_lock);
-}
-
+/*
+ * We are now relying on the NMI watchdog to detect lockup instead of doing
+ * the detection here with an unfair lock which can cause problem of its own.
+ */
void do_raw_spin_lock(raw_spinlock_t *lock)
{
debug_spin_lock_before(lock);
- if (unlikely(!arch_spin_trylock(&lock->raw_lock)))
- __spin_lock_debug(lock);
+ arch_spin_lock(&lock->raw_lock);
debug_spin_lock_after(lock);
}
@@ -179,32 +155,6 @@
#define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg)
-#if 0 /* __write_lock_debug() can lock up - maybe this can too? */
-static void __read_lock_debug(rwlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
- int print_once = 1;
-
- for (;;) {
- for (i = 0; i < loops; i++) {
- if (arch_read_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- if (print_once) {
- print_once = 0;
- printk(KERN_EMERG "BUG: read-lock lockup on CPU#%d, "
- "%s/%d, %p\n",
- raw_smp_processor_id(), current->comm,
- current->pid, lock);
- dump_stack();
- }
- }
-}
-#endif
-
void do_raw_read_lock(rwlock_t *lock)
{
RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
@@ -254,32 +204,6 @@
lock->owner_cpu = -1;
}
-#if 0 /* This can cause lockups */
-static void __write_lock_debug(rwlock_t *lock)
-{
- u64 i;
- u64 loops = loops_per_jiffy * HZ;
- int print_once = 1;
-
- for (;;) {
- for (i = 0; i < loops; i++) {
- if (arch_write_trylock(&lock->raw_lock))
- return;
- __delay(1);
- }
- /* lockup suspected: */
- if (print_once) {
- print_once = 0;
- printk(KERN_EMERG "BUG: write-lock lockup on CPU#%d, "
- "%s/%d, %p\n",
- raw_smp_processor_id(), current->comm,
- current->pid, lock);
- dump_stack();
- }
- }
-}
-#endif
-
void do_raw_write_lock(rwlock_t *lock)
{
debug_write_lock_before(lock);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4573d45..ccfb9bf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3232,9 +3232,9 @@
static inline
unsigned long sum_capacity_reqs(unsigned long cfs_cap,
- struct sched_capacity_reqs *scr)
+ struct sched_capacity_reqs *scr, int cpu)
{
- unsigned long total = add_capacity_margin(cfs_cap + scr->rt);
+ unsigned long total = add_capacity_margin(cfs_cap + scr->rt, cpu);
return total += scr->dl;
}
@@ -3246,7 +3246,7 @@
struct sched_capacity_reqs *scr;
scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
- if (sum_capacity_reqs(cpu_utilization, scr) < capacity_curr)
+ if (sum_capacity_reqs(cpu_utilization, scr, cpu) < capacity_curr)
return;
/*
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 116ffe4..c2372f8 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -84,6 +84,7 @@
};
static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
+static unsigned int stale_ns;
/************************ Governor internals ***********************/
@@ -364,7 +365,7 @@
* idle now (and clear iowait_boost for it).
*/
delta_ns = last_freq_update_time - j_sg_cpu->last_update;
- if (delta_ns > sched_ravg_window) {
+ if (delta_ns > stale_ns) {
j_sg_cpu->iowait_boost = 0;
continue;
}
@@ -716,6 +717,7 @@
policy->governor_data = sg_policy;
sg_policy->tunables = tunables;
+ stale_ns = sched_ravg_window + (sched_ravg_window >> 3);
ret = kobject_init_and_add(&tunables->attr_set.kobj, &sugov_tunables_ktype,
get_governor_parent_kobj(policy), "%s",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fde0639..38fa781 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -89,6 +89,7 @@
unsigned int sysctl_sched_sync_hint_enable = 1;
unsigned int sysctl_sched_initial_task_util = 0;
unsigned int sysctl_sched_cstate_aware = 1;
+DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
#ifdef CONFIG_SCHED_WALT
unsigned int sysctl_sched_use_walt_cpu_util = 1;
@@ -7043,7 +7044,7 @@
cpu_idle_idx = idle_get_state_idx(cpu_rq(i));
if (!need_idle &&
- add_capacity_margin(new_util_cum) <
+ add_capacity_margin(new_util_cum, i) <
capacity_curr_of(i)) {
if (sysctl_sched_cstate_aware) {
if (cpu_idle_idx < min_idle_idx) {
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 6b935e7..1bc4828 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1811,7 +1811,7 @@
cpu_idle_idx =
idle_get_state_idx(cpu_rq(cpu));
- if (add_capacity_margin(new_util_cum) <
+ if (add_capacity_margin(new_util_cum, cpu) <
capacity_curr_of(cpu)) {
if (cpu_idle_idx < best_cpu_idle_idx ||
(best_cpu != task_cpu(task) &&
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 72b79bb..0a1e62f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -29,6 +29,7 @@
#ifdef CONFIG_SCHED_WALT
extern unsigned int sched_ravg_window;
+extern unsigned int walt_cpu_util_freq_divisor;
struct walt_sched_stats {
int nr_big_tasks;
@@ -1805,47 +1806,87 @@
#endif
static inline unsigned long
-cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+cpu_util_freq_pelt(int cpu)
{
struct rq *rq = cpu_rq(cpu);
- u64 util = rq->cfs.avg.util_avg;
+ unsigned long util = rq->cfs.avg.util_avg;
unsigned long capacity = capacity_orig_of(cpu);
-#ifdef CONFIG_SCHED_WALT
- if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
+ util *= (100 + per_cpu(sched_load_boost, cpu));
+ do_div(util, 100);
- util = freq_policy_load(rq);
- util = div64_u64(util,
- sched_ravg_window >> SCHED_CAPACITY_SHIFT);
-
- if (walt_load) {
- u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
- rq->grp_time.nt_prev_runnable_sum;
- u64 pl = rq->walt_stats.pred_demands_sum;
-
- nl = div64_u64(nl, sched_ravg_window >>
- SCHED_CAPACITY_SHIFT);
- pl = div64_u64(pl, sched_ravg_window >>
- SCHED_CAPACITY_SHIFT);
-
- walt_load->prev_window_util = util;
- walt_load->nl = nl;
- walt_load->pl = pl;
- rq->old_busy_time = util;
- rq->old_estimated_time = pl;
- walt_load->ws = rq->window_start;
- }
- }
-#endif
return (util >= capacity) ? capacity : util;
}
+
+#ifdef CONFIG_SCHED_WALT
+static inline unsigned long
+cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ u64 util, util_unboosted;
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long capacity = capacity_orig_of(cpu);
+ int boost;
+
+ if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
+ return cpu_util_freq_pelt(cpu);
+
+ boost = per_cpu(sched_load_boost, cpu);
+ util_unboosted = util = freq_policy_load(rq);
+ util = div64_u64(util * (100 + boost),
+ walt_cpu_util_freq_divisor);
+
+ if (walt_load) {
+ u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
+ rq->grp_time.nt_prev_runnable_sum;
+ u64 pl = rq->walt_stats.pred_demands_sum;
+
+ /* do_pl_notif() needs unboosted signals */
+ rq->old_busy_time = div64_u64(util_unboosted,
+ sched_ravg_window >>
+ SCHED_CAPACITY_SHIFT);
+ rq->old_estimated_time = div64_u64(pl, sched_ravg_window >>
+ SCHED_CAPACITY_SHIFT);
+
+ nl = div64_u64(nl * (100 + boost),
+ walt_cpu_util_freq_divisor);
+ pl = div64_u64(pl * (100 + boost),
+ walt_cpu_util_freq_divisor);
+
+ walt_load->prev_window_util = util;
+ walt_load->nl = nl;
+ walt_load->pl = pl;
+ walt_load->ws = rq->window_start;
+ }
+
+ return (util >= capacity) ? capacity : util;
+}
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ return cpu_util_freq_walt(cpu, walt_load);
+}
+
+#else
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+ return cpu_util_freq_pelt(cpu);
+}
+
+#endif /* CONFIG_SCHED_WALT */
+
#endif
extern unsigned int capacity_margin_freq;
-static inline unsigned long add_capacity_margin(unsigned long cpu_capacity)
+static inline unsigned long
+add_capacity_margin(unsigned long cpu_capacity, int cpu)
{
- cpu_capacity = cpu_capacity * capacity_margin_freq;
+ cpu_capacity = cpu_capacity * capacity_margin_freq *
+ (100 + per_cpu(sched_load_boost, cpu));
+ cpu_capacity /= 100;
cpu_capacity /= SCHED_CAPACITY_SCALE;
return cpu_capacity;
}
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 60249e4..316c276 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -109,6 +109,12 @@
/* Window size (in ns) */
__read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW;
+/*
+ * A after-boot constant divisor for cpu_util_freq_walt() to apply the load
+ * boost.
+ */
+__read_mostly unsigned int walt_cpu_util_freq_divisor;
+
/* Initial task load. Newly created tasks are assigned this load. */
unsigned int __read_mostly sched_init_task_load_windows;
unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15;
@@ -3107,4 +3113,7 @@
clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
}
rq->cum_window_demand = 0;
+
+ walt_cpu_util_freq_divisor =
+ (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100;
}
diff --git a/kernel/signal.c b/kernel/signal.c
index deb04d5..e48668c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -346,7 +346,7 @@
* fresh group stop. Read comment in do_signal_stop() for details.
*/
if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
- sig->flags = SIGNAL_STOP_STOPPED;
+ signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
return true;
}
return false;
@@ -845,7 +845,7 @@
* will take ->siglock, notice SIGNAL_CLD_MASK, and
* notify its parent. See get_signal_to_deliver().
*/
- signal->flags = why | SIGNAL_STOP_CONTINUED;
+ signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
signal->group_stop_count = 0;
signal->group_exit_code = 0;
}
diff --git a/kernel/smp.c b/kernel/smp.c
index ee80cc8..313d9a8 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -15,6 +15,7 @@
#include <linux/cpu.h>
#include <linux/sched.h>
#include <linux/hypervisor.h>
+#include <linux/suspend.h>
#include "smpboot.h"
@@ -751,7 +752,8 @@
for_each_online_cpu(cpu) {
if (cpu == smp_processor_id())
continue;
- if (!cpu_isolated(cpu))
+ if (suspend_freeze_state == FREEZE_STATE_ENTER ||
+ !cpu_isolated(cpu))
wake_up_if_idle(cpu);
}
preempt_enable();
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index e671a32..80aa30d 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -201,6 +201,7 @@
bool migration_enabled;
bool nohz_active;
bool is_idle;
+ bool must_forward_clk;
DECLARE_BITMAP(pending_map, WHEEL_SIZE);
struct hlist_head vectors[WHEEL_SIZE];
} ____cacheline_aligned;
@@ -874,13 +875,19 @@
static inline void forward_timer_base(struct timer_base *base)
{
- unsigned long jnow = READ_ONCE(jiffies);
+ unsigned long jnow;
/*
- * We only forward the base when it's idle and we have a delta between
- * base clock and jiffies.
+ * We only forward the base when we are idle or have just come out of
+ * idle (must_forward_clk logic), and have a delta between base clock
+ * and jiffies. In the common case, run_timers will take care of it.
*/
- if (!base->is_idle || (long) (jnow - base->clk) < 2)
+ if (likely(!base->must_forward_clk))
+ return;
+
+ jnow = READ_ONCE(jiffies);
+ base->must_forward_clk = base->is_idle;
+ if ((long)(jnow - base->clk) < 2)
return;
/*
@@ -956,6 +963,11 @@
* same array bucket then just return:
*/
if (timer_pending(timer)) {
+ /*
+ * The downside of this optimization is that it can result in
+ * larger granularity than you would get from adding a new
+ * timer with this expiry.
+ */
if (timer->expires == expires)
return 1;
@@ -966,6 +978,7 @@
* dequeue/enqueue dance.
*/
base = lock_timer_base(timer, &flags);
+ forward_timer_base(base);
clk = base->clk;
idx = calc_wheel_index(expires, clk);
@@ -982,6 +995,7 @@
}
} else {
base = lock_timer_base(timer, &flags);
+ forward_timer_base(base);
}
ret = detach_if_pending(timer, base, false);
@@ -1009,12 +1023,10 @@
spin_lock(&base->lock);
WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | base->cpu);
+ forward_timer_base(base);
}
}
- /* Try to forward a stale timer base clock */
- forward_timer_base(base);
-
timer->expires = expires;
/*
* If 'idx' was calculated above and the base time did not advance
@@ -1130,6 +1142,7 @@
WRITE_ONCE(timer->flags,
(timer->flags & ~TIMER_BASEMASK) | cpu);
}
+ forward_timer_base(base);
debug_activate(timer, timer->expires);
internal_add_timer(base, timer);
@@ -1544,12 +1557,18 @@
base->is_idle = false;
} else {
if (!is_max_delta)
- expires = basem + (nextevt - basej) * TICK_NSEC;
+ expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
/*
- * If we expect to sleep more than a tick, mark the base idle:
+ * If we expect to sleep more than a tick, mark the base idle.
+ * Also the tick is stopped so any added timer must forward
+ * the base clk itself to keep granularity small. This idle
+ * logic is only maintained for the BASE_STD base, deferrable
+ * timers may still see large granularity skew (by design).
*/
- if ((expires - basem) > TICK_NSEC)
+ if ((expires - basem) > TICK_NSEC) {
+ base->must_forward_clk = true;
base->is_idle = true;
+ }
}
spin_unlock(&base->lock);
@@ -1659,6 +1678,19 @@
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
+ /*
+ * must_forward_clk must be cleared before running timers so that any
+ * timer functions that call mod_timer will not try to forward the
+ * base. idle trcking / clock forwarding logic is only used with
+ * BASE_STD timers.
+ *
+ * The deferrable base does not do idle tracking at all, so we do
+ * not forward it. This can result in very large variations in
+ * granularity for deferrable timers, but they can be deferred for
+ * long periods due to idle.
+ */
+ base->must_forward_clk = false;
+
__run_timers(base);
if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 5dcb992..41805fb 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -203,10 +203,36 @@
fmt_cnt++;
}
- return __trace_printk(1/* fake ip will not be printed */, fmt,
- mod[0] == 2 ? arg1 : mod[0] == 1 ? (long) arg1 : (u32) arg1,
- mod[1] == 2 ? arg2 : mod[1] == 1 ? (long) arg2 : (u32) arg2,
- mod[2] == 2 ? arg3 : mod[2] == 1 ? (long) arg3 : (u32) arg3);
+/* Horrid workaround for getting va_list handling working with different
+ * argument type combinations generically for 32 and 64 bit archs.
+ */
+#define __BPF_TP_EMIT() __BPF_ARG3_TP()
+#define __BPF_TP(...) \
+ __trace_printk(1 /* Fake ip will not be printed. */, \
+ fmt, ##__VA_ARGS__)
+
+#define __BPF_ARG1_TP(...) \
+ ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_TP(arg1, ##__VA_ARGS__) \
+ : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_TP((long)arg1, ##__VA_ARGS__) \
+ : __BPF_TP((u32)arg1, ##__VA_ARGS__)))
+
+#define __BPF_ARG2_TP(...) \
+ ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG1_TP(arg2, ##__VA_ARGS__) \
+ : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG1_TP((long)arg2, ##__VA_ARGS__) \
+ : __BPF_ARG1_TP((u32)arg2, ##__VA_ARGS__)))
+
+#define __BPF_ARG3_TP(...) \
+ ((mod[2] == 2 || (mod[2] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG2_TP(arg3, ##__VA_ARGS__) \
+ : ((mod[2] == 1 || (mod[2] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG2_TP((long)arg3, ##__VA_ARGS__) \
+ : __BPF_ARG2_TP((u32)arg3, ##__VA_ARGS__)))
+
+ return __BPF_TP_EMIT();
}
static const struct bpf_func_proto bpf_trace_printk_proto = {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4f7ea84..6e432ed 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -876,6 +876,10 @@
function_profile_call(trace->func, 0, NULL, NULL);
+ /* If function graph is shutting down, ret_stack can be NULL */
+ if (!current->ret_stack)
+ return 0;
+
if (index >= 0 && index < FTRACE_RETFUNC_DEPTH)
current->ret_stack[index].subtime = 0;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 66b0714..cddedb5 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -7926,4 +7926,4 @@
}
fs_initcall(tracer_init_tracefs);
-late_initcall(clear_boot_tracer);
+late_initcall_sync(clear_boot_tracer);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 9daa9b3..0193f58 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1926,6 +1926,10 @@
if (err && set_str)
append_filter_err(ps, filter);
}
+ if (err && !set_str) {
+ free_event_filter(filter);
+ filter = NULL;
+ }
create_filter_finish(ps);
*filterp = filter;
diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c
index 0a689bb..305039b 100644
--- a/kernel/trace/tracing_map.c
+++ b/kernel/trace/tracing_map.c
@@ -221,16 +221,19 @@
if (!a)
return;
- if (!a->pages) {
- kfree(a);
- return;
- }
+ if (!a->pages)
+ goto free;
for (i = 0; i < a->n_pages; i++) {
if (!a->pages[i])
break;
free_page((unsigned long)a->pages[i]);
}
+
+ kfree(a->pages);
+
+ free:
+ kfree(a);
}
struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index cffb5f2..cfbf027 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -81,10 +81,10 @@
static DEFINE_PER_CPU(unsigned int, watchdog_en);
static DEFINE_PER_CPU(bool, softlockup_touch_sync);
static DEFINE_PER_CPU(bool, soft_watchdog_warn);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
static unsigned long soft_lockup_nmi_warn;
unsigned int __read_mostly softlockup_panic =
@@ -254,6 +254,10 @@
{
}
+void __weak watchdog_check_hardlockup_other_cpu(void)
+{
+}
+
static int watchdog_enable_all_cpus(void);
static void watchdog_disable_all_cpus(void);
@@ -271,6 +275,9 @@
/* kick the hardlockup detector */
watchdog_interrupt_count();
+ /* test for hardlockups on the next cpu */
+ watchdog_check_hardlockup_other_cpu();
+
/* kick the softlockup detector */
wake_up_process(__this_cpu_read(softlockup_watchdog));
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index 12b8dd6..5b2c127 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -18,7 +18,11 @@
static DEFINE_PER_CPU(bool, hard_watchdog_warn);
static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static cpumask_t __read_mostly watchdog_cpus;
+#else
static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+#endif
/* boot commands */
/*
@@ -26,7 +30,10 @@
*/
unsigned int __read_mostly hardlockup_panic =
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static unsigned long hardlockup_allcpu_dumped;
+#endif
/*
* We may not want to enable hard lockup detection by default in all cases,
* for example when running the kernel as a guest on a hypervisor. In these
@@ -68,6 +75,108 @@
}
EXPORT_SYMBOL(touch_nmi_watchdog);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static unsigned int watchdog_next_cpu(unsigned int cpu)
+{
+ cpumask_t cpus = watchdog_cpus;
+ unsigned int next_cpu;
+
+ next_cpu = cpumask_next(cpu, &cpus);
+ if (next_cpu >= nr_cpu_ids)
+ next_cpu = cpumask_first(&cpus);
+
+ if (next_cpu == cpu)
+ return nr_cpu_ids;
+
+ return next_cpu;
+}
+
+static int is_hardlockup_other_cpu(unsigned int cpu)
+{
+ unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
+
+ if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
+ return 1;
+
+ per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
+ return 0;
+}
+
+void watchdog_check_hardlockup_other_cpu(void)
+{
+ unsigned int next_cpu;
+
+ /*
+ * Test for hardlockups every 3 samples. The sample period is
+ * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
+ * watchdog_thresh (over by 20%).
+ */
+ if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
+ return;
+
+ /* check for a hardlockup on the next cpu */
+ next_cpu = watchdog_next_cpu(smp_processor_id());
+ if (next_cpu >= nr_cpu_ids)
+ return;
+
+ smp_rmb();
+
+ if (per_cpu(watchdog_nmi_touch, next_cpu) == true) {
+ per_cpu(watchdog_nmi_touch, next_cpu) = false;
+ return;
+ }
+
+ if (is_hardlockup_other_cpu(next_cpu)) {
+ /* only warn once */
+ if (per_cpu(hard_watchdog_warn, next_cpu) == true)
+ return;
+
+ if (hardlockup_panic)
+ panic("Watchdog detected hard LOCKUP on cpu %u",
+ next_cpu);
+ else
+ WARN(1, "Watchdog detected hard LOCKUP on cpu %u",
+ next_cpu);
+
+ per_cpu(hard_watchdog_warn, next_cpu) = true;
+ } else {
+ per_cpu(hard_watchdog_warn, next_cpu) = false;
+ }
+}
+
+int watchdog_nmi_enable(unsigned int cpu)
+{
+ /*
+ * The new cpu will be marked online before the first hrtimer interrupt
+ * runs on it. If another cpu tests for a hardlockup on the new cpu
+ * before it has run its first hrtimer, it will get a false positive.
+ * Touch the watchdog on the new cpu to delay the first check for at
+ * least 3 sampling periods to guarantee one hrtimer has run on the new
+ * cpu.
+ */
+ per_cpu(watchdog_nmi_touch, cpu) = true;
+ smp_wmb();
+ cpumask_set_cpu(cpu, &watchdog_cpus);
+ return 0;
+}
+
+void watchdog_nmi_disable(unsigned int cpu)
+{
+ unsigned int next_cpu = watchdog_next_cpu(cpu);
+
+ /*
+ * Offlining this cpu will cause the cpu before this one to start
+ * checking the one after this one. If this cpu just finished checking
+ * the next cpu and updating hrtimer_interrupts_saved, and then the
+ * previous cpu checks it within one sample period, it will trigger a
+ * false positive. Touch the watchdog on the next cpu to prevent it.
+ */
+ if (next_cpu < nr_cpu_ids)
+ per_cpu(watchdog_nmi_touch, next_cpu) = true;
+ smp_wmb();
+ cpumask_clear_cpu(cpu, &watchdog_cpus);
+}
+#else
static struct perf_event_attr wd_hw_attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
@@ -228,3 +337,4 @@
cpu0_err = 0;
}
}
+#endif
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 812b8f8..0e5e54f 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3737,8 +3737,12 @@
return -EINVAL;
/* creating multiple pwqs breaks ordering guarantee */
- if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
- return -EINVAL;
+ if (!list_empty(&wq->pwqs)) {
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
+ return -EINVAL;
+
+ wq->flags &= ~__WQ_ORDERED;
+ }
ctx = apply_wqattrs_prepare(wq, attrs);
if (!ctx)
@@ -3922,6 +3926,16 @@
struct workqueue_struct *wq;
struct pool_workqueue *pwq;
+ /*
+ * Unbound && max_active == 1 used to imply ordered, which is no
+ * longer the case on NUMA machines due to per-node pools. While
+ * alloc_ordered_workqueue() is the right way to create an ordered
+ * workqueue, keep the previous behavior to avoid subtle breakages
+ * on NUMA.
+ */
+ if ((flags & WQ_UNBOUND) && max_active == 1)
+ flags |= __WQ_ORDERED;
+
/* see the comment above the definition of WQ_POWER_EFFICIENT */
if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
flags |= WQ_UNBOUND;
@@ -4110,13 +4124,14 @@
struct pool_workqueue *pwq;
/* disallow meddling with max_active for ordered workqueues */
- if (WARN_ON(wq->flags & __WQ_ORDERED))
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
return;
max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
mutex_lock(&wq->mutex);
+ wq->flags &= ~__WQ_ORDERED;
wq->saved_max_active = max_active;
for_each_pwq(pwq, wq)
@@ -5221,7 +5236,7 @@
* attributes breaks ordering guarantee. Disallow exposing ordered
* workqueues.
*/
- if (WARN_ON(wq->flags & __WQ_ORDERED))
+ if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
return -EINVAL;
wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2f9f7aa..2812580 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -145,7 +145,7 @@
config DEBUG_INFO_SPLIT
bool "Produce split debuginfo in .dwo files"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && !FRV
help
Generate debug info into separate .dwo files. This significantly
reduces the build directory size for builds with DEBUG_INFO,
@@ -779,11 +779,20 @@
The frequency of hrtimer and NMI events and the soft and hard lockup
thresholds can be controlled through the sysctl watchdog_thresh.
-config HARDLOCKUP_DETECTOR
+config HARDLOCKUP_DETECTOR_NMI
def_bool y
depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
+config HARDLOCKUP_DETECTOR_OTHER_CPU
+ def_bool y
+ depends on LOCKUP_DETECTOR && SMP
+ depends on !HARDLOCKUP_DETECTOR_NMI && !HAVE_NMI_WATCHDOG
+
+config HARDLOCKUP_DETECTOR
+ def_bool y
+ depends on HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU
+
config BOOTPARAM_HARDLOCKUP_PANIC
bool "Panic (Reboot) On Hard Lockups"
depends on HARDLOCKUP_DETECTOR
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c
index f344f76..6b2e046 100644
--- a/lib/lz4/lz4hc_compress.c
+++ b/lib/lz4/lz4hc_compress.c
@@ -131,7 +131,7 @@
#endif
int nbattempts = MAX_NB_ATTEMPTS;
size_t repl = 0, ml = 0;
- u16 delta;
+ u16 delta = 0;
/* HC4 match finder */
lz4hc_insert(hc4, ip);
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
index 5a0f75a..eead4b3 100644
--- a/lib/mpi/mpicoder.c
+++ b/lib/mpi/mpicoder.c
@@ -364,11 +364,11 @@
}
miter.consumed = lzeros;
- sg_miter_stop(&miter);
nbytes -= lzeros;
nbits = nbytes * 8;
if (nbits > MAX_EXTERN_MPI_BITS) {
+ sg_miter_stop(&miter);
pr_info("MPI: mpi too large (%u bits)\n", nbits);
return NULL;
}
@@ -376,6 +376,8 @@
if (nbytes > 0)
nbits -= count_leading_zeros(*buff) - (BITS_PER_LONG - 8);
+ sg_miter_stop(&miter);
+
nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
val = mpi_alloc(nlimbs);
if (!val)
diff --git a/mm/internal.h b/mm/internal.h
index df6319f..0ee4f54 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -477,6 +477,7 @@
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
void try_to_unmap_flush(void);
void try_to_unmap_flush_dirty(void);
+void flush_tlb_batched_pending(struct mm_struct *mm);
#else
static inline void try_to_unmap_flush(void)
{
@@ -484,7 +485,9 @@
static inline void try_to_unmap_flush_dirty(void)
{
}
-
+static inline void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+}
#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
extern const struct trace_print_flags pageflag_names[];
diff --git a/mm/madvise.c b/mm/madvise.c
index 279627a..088a5b22 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -21,6 +21,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/mmu_notifier.h>
+#include "internal.h"
#include <asm/tlb.h>
@@ -282,6 +283,7 @@
return 0;
orig_pte = pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ flush_tlb_batched_pending(mm);
arch_enter_lazy_mmu_mode();
for (; addr != end; pte++, addr += PAGE_SIZE) {
ptent = *pte;
@@ -329,8 +331,8 @@
pte_offset_map_lock(mm, pmd, addr, &ptl);
goto out;
}
- put_page(page);
unlock_page(page);
+ put_page(page);
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
pte--;
addr -= PAGE_SIZE;
@@ -531,6 +533,8 @@
static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
{
struct page *p;
+ struct zone *zone;
+
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
for (; start < end; start += PAGE_SIZE <<
@@ -559,6 +563,11 @@
if (ret)
return ret;
}
+
+ /* Ensure that all poisoned pages are removed from per-cpu lists */
+ for_each_populated_zone(zone)
+ drain_all_pages(zone);
+
return 0;
}
#endif
diff --git a/mm/memblock.c b/mm/memblock.c
index f1eabcc..3b7d23c 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -301,31 +301,27 @@
}
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
-
-phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
- phys_addr_t *addr)
+/**
+ * Discard memory and reserved arrays if they were allocated
+ */
+void __init memblock_discard(void)
{
- if (memblock.reserved.regions == memblock_reserved_init_regions)
- return 0;
+ phys_addr_t addr, size;
- *addr = __pa(memblock.reserved.regions);
+ if (memblock.reserved.regions != memblock_reserved_init_regions) {
+ addr = __pa(memblock.reserved.regions);
+ size = PAGE_ALIGN(sizeof(struct memblock_region) *
+ memblock.reserved.max);
+ __memblock_free_late(addr, size);
+ }
- return PAGE_ALIGN(sizeof(struct memblock_region) *
- memblock.reserved.max);
+ if (memblock.memory.regions != memblock_memory_init_regions) {
+ addr = __pa(memblock.memory.regions);
+ size = PAGE_ALIGN(sizeof(struct memblock_region) *
+ memblock.memory.max);
+ __memblock_free_late(addr, size);
+ }
}
-
-phys_addr_t __init_memblock get_allocated_memblock_memory_regions_info(
- phys_addr_t *addr)
-{
- if (memblock.memory.regions == memblock_memory_init_regions)
- return 0;
-
- *addr = __pa(memblock.memory.regions);
-
- return PAGE_ALIGN(sizeof(struct memblock_region) *
- memblock.memory.max);
-}
-
#endif
/**
diff --git a/mm/memory.c b/mm/memory.c
index 49d9b42..b5e0ed3 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1124,6 +1124,7 @@
init_rss_vec(rss);
start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
pte = start_pte;
+ flush_tlb_batched_pending(mm);
arch_enter_lazy_mmu_mode();
do {
pte_t ptent = *pte;
@@ -3634,8 +3635,18 @@
* further.
*/
if (unlikely((current->flags & PF_KTHREAD) && !(ret & VM_FAULT_ERROR)
- && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags)))
+ && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags))) {
+
+ /*
+ * We are going to enforce SIGBUS but the PF path might have
+ * dropped the mmap_sem already so take it again so that
+ * we do not break expectations of all arch specific PF paths
+ * and g-u-p
+ */
+ if (ret & VM_FAULT_RETRY)
+ down_read(&vma->vm_mm->mmap_sem);
ret = VM_FAULT_SIGBUS;
+ }
return ret;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 9ff5657..9547583 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -927,11 +927,6 @@
*policy |= (pol->flags & MPOL_MODE_FLAGS);
}
- if (vma) {
- up_read(¤t->mm->mmap_sem);
- vma = NULL;
- }
-
err = 0;
if (nmask) {
if (mpol_store_user_nodemask(pol)) {
diff --git a/mm/migrate.c b/mm/migrate.c
index 4213d27..eb1f043 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -40,6 +40,7 @@
#include <linux/mmu_notifier.h>
#include <linux/page_idle.h>
#include <linux/page_owner.h>
+#include <linux/ptrace.h>
#include <asm/tlbflush.h>
@@ -1665,7 +1666,6 @@
const int __user *, nodes,
int __user *, status, int, flags)
{
- const struct cred *cred = current_cred(), *tcred;
struct task_struct *task;
struct mm_struct *mm;
int err;
@@ -1689,14 +1689,9 @@
/*
* Check if this process has the right to modify the specified
- * process. The right exists if the process has administrative
- * capabilities, superuser privileges or the same
- * userid as the target process.
+ * process. Use the regular "ptrace_may_access()" checks.
*/
- tcred = __task_cred(task);
- if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
- !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) &&
- !capable(CAP_SYS_NICE)) {
+ if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
rcu_read_unlock();
err = -EPERM;
goto out;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 2c40836..1f2c969 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -74,6 +74,7 @@
if (!pte)
return 0;
+ flush_tlb_batched_pending(vma->vm_mm);
arch_enter_lazy_mmu_mode();
do {
oldpte = *pte;
diff --git a/mm/mremap.c b/mm/mremap.c
index 30d7d24..1597671 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -142,6 +142,7 @@
new_ptl = pte_lockptr(mm, new_pmd);
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+ flush_tlb_batched_pending(vma->vm_mm);
arch_enter_lazy_mmu_mode();
for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index e1e8c63..aa59572 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -146,22 +146,6 @@
NULL)
count += __free_memory_core(start, end);
-#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
- {
- phys_addr_t size;
-
- /* Free memblock.reserved array if it was allocated */
- size = get_allocated_memblock_reserved_regions_info(&start);
- if (size)
- count += __free_memory_core(start, start + size);
-
- /* Free memblock.memory array if it was allocated */
- size = get_allocated_memblock_memory_regions_info(&start);
- if (size)
- count += __free_memory_core(start, start + size);
- }
-#endif
-
return count;
}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 3a22b14..af783a6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -608,18 +608,23 @@
return 0;
}
-static void wake_oom_reaper(struct task_struct *tsk)
+void wake_oom_reaper(struct task_struct *tsk)
{
if (!oom_reaper_th)
return;
+ /* move the lock here to avoid scenario of queuing
+ * the same task by both OOM killer and LMK.
+ */
+ spin_lock(&oom_reaper_lock);
/* tsk is already queued? */
- if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+ if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+ spin_unlock(&oom_reaper_lock);
return;
+ }
get_task_struct(tsk);
- spin_lock(&oom_reaper_lock);
tsk->oom_reaper_list = oom_reaper_list;
oom_reaper_list = tsk;
spin_unlock(&oom_reaper_lock);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3eb5f68..acf411c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1579,6 +1579,10 @@
/* Reinit limits that are based on free pages after the kernel is up */
files_maxfiles_init();
#endif
+#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+ /* Discard memblock private memory */
+ memblock_discard();
+#endif
for_each_populated_zone(zone)
set_zone_contiguous(zone);
@@ -1865,14 +1869,14 @@
#endif
for (page = start_page; page <= end_page;) {
- /* Make sure we are not inadvertently changing nodes */
- VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
if (!pfn_valid_within(page_to_pfn(page))) {
page++;
continue;
}
+ /* Make sure we are not inadvertently changing nodes */
+ VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+
if (!PageBuddy(page)) {
page++;
continue;
@@ -6525,8 +6529,8 @@
}
if (pages && s)
- pr_info("Freeing %s memory: %ldK (%p - %p)\n",
- s, pages << (PAGE_SHIFT - 10), start, end);
+ pr_info("Freeing %s memory: %ldK\n",
+ s, pages << (PAGE_SHIFT - 10));
return pages;
}
@@ -7416,7 +7420,7 @@
/* Make sure the range is really isolated. */
if (test_pages_isolated(outer_start, end, false)) {
- pr_info("%s: [%lx, %lx) PFNs busy\n",
+ pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
__func__, outer_start, end);
ret = -EBUSY;
goto done;
diff --git a/mm/rmap.c b/mm/rmap.c
index dfb19f0..4d19dd1 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -617,6 +617,13 @@
tlb_ubc->flush_required = true;
/*
+ * Ensure compiler does not re-order the setting of tlb_flush_batched
+ * before the PTE is cleared.
+ */
+ barrier();
+ mm->tlb_flush_batched = true;
+
+ /*
* If the PTE was dirty then it's best to assume it's writable. The
* caller must use try_to_unmap_flush_dirty() or try_to_unmap_flush()
* before the page is queued for IO.
@@ -643,6 +650,35 @@
return should_defer;
}
+
+/*
+ * Reclaim unmaps pages under the PTL but do not flush the TLB prior to
+ * releasing the PTL if TLB flushes are batched. It's possible for a parallel
+ * operation such as mprotect or munmap to race between reclaim unmapping
+ * the page and flushing the page. If this race occurs, it potentially allows
+ * access to data via a stale TLB entry. Tracking all mm's that have TLB
+ * batching in flight would be expensive during reclaim so instead track
+ * whether TLB batching occurred in the past and if so then do a flush here
+ * if required. This will cost one additional flush per reclaim cycle paid
+ * by the first operation at risk such as mprotect and mumap.
+ *
+ * This must be called under the PTL so that an access to tlb_flush_batched
+ * that is potentially a "reclaim vs mprotect/munmap/etc" race will synchronise
+ * via the PTL.
+ */
+void flush_tlb_batched_pending(struct mm_struct *mm)
+{
+ if (mm->tlb_flush_batched) {
+ flush_tlb_mm(mm);
+
+ /*
+ * Do not allow the compiler to re-order the clearing of
+ * tlb_flush_batched before the tlb is flushed.
+ */
+ barrier();
+ mm->tlb_flush_batched = false;
+ }
+}
#else
static void set_tlb_ubc_flush_pending(struct mm_struct *mm,
struct page *page, bool writable)
diff --git a/mm/shmem.c b/mm/shmem.c
index 142887f..7a74b6d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1007,7 +1007,11 @@
*/
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) {
spin_lock(&sbinfo->shrinklist_lock);
- if (list_empty(&info->shrinklist)) {
+ /*
+ * _careful to defend against unlocked access to
+ * ->shrink_list in shmem_unused_huge_shrink()
+ */
+ if (list_empty_careful(&info->shrinklist)) {
list_add_tail(&info->shrinklist,
&sbinfo->shrinklist);
sbinfo->shrinklist_len++;
@@ -1774,7 +1778,11 @@
* to shrink under memory pressure.
*/
spin_lock(&sbinfo->shrinklist_lock);
- if (list_empty(&info->shrinklist)) {
+ /*
+ * _careful to defend against unlocked access to
+ * ->shrink_list in shmem_unused_huge_shrink()
+ */
+ if (list_empty_careful(&info->shrinklist)) {
list_add_tail(&info->shrinklist,
&sbinfo->shrinklist);
sbinfo->shrinklist_len++;
@@ -3802,7 +3810,7 @@
}
#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
- if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY)
+ if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)
SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
else
shmem_huge = 0; /* just in case it was patched */
@@ -3863,7 +3871,7 @@
return -EINVAL;
shmem_huge = huge;
- if (shmem_huge < SHMEM_HUGE_DENY)
+ if (shmem_huge > SHMEM_HUGE_DENY)
SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
return count;
}
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index fbf251f..4d6b94d 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,16 +484,16 @@
struct net_device *dev = s->dev;
struct sock *sk = s->sock->sk;
struct sk_buff *skb;
- wait_queue_t wait;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
BT_DBG("");
set_user_nice(current, -15);
- init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&s->terminate))
break;
@@ -515,9 +515,8 @@
break;
netif_wake_queue(dev);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
/* Cleanup session */
@@ -666,7 +665,7 @@
s = __bnep_get_session(req->dst);
if (s) {
atomic_inc(&s->terminate);
- wake_up_process(s->task);
+ wake_up_interruptible(sk_sleep(s->sock->sk));
} else
err = -ENOENT;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 9e59b66..1152ce3 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -280,16 +280,16 @@
struct cmtp_session *session = arg;
struct sock *sk = session->sock->sk;
struct sk_buff *skb;
- wait_queue_t wait;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
BT_DBG("session %p", session);
set_user_nice(current, -15);
- init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&session->terminate))
break;
@@ -306,9 +306,8 @@
cmtp_process_transmit(session);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
down_write(&cmtp_session_sem);
@@ -393,7 +392,7 @@
err = cmtp_attach_device(session);
if (err < 0) {
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+ wake_up_interruptible(sk_sleep(session->sock->sk));
up_write(&cmtp_session_sem);
return err;
}
@@ -431,7 +430,11 @@
/* Stop session thread */
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+
+ /* Ensure session->terminate is updated */
+ smp_mb__after_atomic();
+
+ wake_up_interruptible(sk_sleep(session->sock->sk));
} else
err = -ENOENT;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 0bec458..1fc0764 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -36,6 +36,7 @@
#define VERSION "1.2"
static DECLARE_RWSEM(hidp_session_sem);
+static DECLARE_WAIT_QUEUE_HEAD(hidp_session_wq);
static LIST_HEAD(hidp_session_list);
static unsigned char hidp_keycode[256] = {
@@ -1068,12 +1069,12 @@
* Wake up session thread and notify it to stop. This is asynchronous and
* returns immediately. Call this whenever a runtime error occurs and you want
* the session to stop.
- * Note: wake_up_process() performs any necessary memory-barriers for us.
+ * Note: wake_up_interruptible() performs any necessary memory-barriers for us.
*/
static void hidp_session_terminate(struct hidp_session *session)
{
atomic_inc(&session->terminate);
- wake_up_process(session->task);
+ wake_up_interruptible(&hidp_session_wq);
}
/*
@@ -1180,7 +1181,9 @@
struct sock *ctrl_sk = session->ctrl_sock->sk;
struct sock *intr_sk = session->intr_sock->sk;
struct sk_buff *skb;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ add_wait_queue(&hidp_session_wq, &wait);
for (;;) {
/*
* This thread can be woken up two ways:
@@ -1188,12 +1191,10 @@
* session->terminate flag and wakes this thread up.
* - Via modifying the socket state of ctrl/intr_sock. This
* thread is woken up by ->sk_state_changed().
- *
- * Note: set_current_state() performs any necessary
- * memory-barriers for us.
*/
- set_current_state(TASK_INTERRUPTIBLE);
+ /* Ensure session->terminate is updated */
+ smp_mb__before_atomic();
if (atomic_read(&session->terminate))
break;
@@ -1227,11 +1228,22 @@
hidp_process_transmit(session, &session->ctrl_transmit,
session->ctrl_sock);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
+ remove_wait_queue(&hidp_session_wq, &wait);
atomic_inc(&session->terminate);
- set_current_state(TASK_RUNNING);
+
+ /* Ensure session->terminate is updated */
+ smp_mb__after_atomic();
+}
+
+static int hidp_session_wake_function(wait_queue_t *wait,
+ unsigned int mode,
+ int sync, void *key)
+{
+ wake_up_interruptible(&hidp_session_wq);
+ return false;
}
/*
@@ -1244,7 +1256,8 @@
static int hidp_session_thread(void *arg)
{
struct hidp_session *session = arg;
- wait_queue_t ctrl_wait, intr_wait;
+ DEFINE_WAIT_FUNC(ctrl_wait, hidp_session_wake_function);
+ DEFINE_WAIT_FUNC(intr_wait, hidp_session_wake_function);
BT_DBG("session %p", session);
@@ -1254,8 +1267,6 @@
set_user_nice(current, -15);
hidp_set_timer(session);
- init_waitqueue_entry(&ctrl_wait, current);
- init_waitqueue_entry(&intr_wait, current);
add_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait);
add_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
/* This memory barrier is paired with wq_has_sleeper(). See
diff --git a/net/core/dev.c b/net/core/dev.c
index 610e5f8..33cbbe6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2705,7 +2705,7 @@
{
if (tx_path)
return skb->ip_summed != CHECKSUM_PARTIAL &&
- skb->ip_summed != CHECKSUM_NONE;
+ skb->ip_summed != CHECKSUM_UNNECESSARY;
return skb->ip_summed == CHECKSUM_NONE;
}
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index b94b1d2..151e047 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -28,6 +28,7 @@
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
return -EFAULT;
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
if (error)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 9c6fd7f..4d26297 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1965,7 +1965,8 @@
struct sockaddr *sa;
int len;
- len = sizeof(sa_family_t) + dev->addr_len;
+ len = sizeof(sa_family_t) + max_t(size_t, dev->addr_len,
+ sizeof(*sa));
sa = kmalloc(len, GFP_KERNEL);
if (!sa) {
err = -ENOMEM;
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 1704948..f227f00 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1471,9 +1471,12 @@
* singleton values (which always leads to failure).
* These settings can still (later) be overridden via sockopts.
*/
- if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
- ccid_get_builtin_ccids(&rx.val, &rx.len))
+ if (ccid_get_builtin_ccids(&tx.val, &tx.len))
return -ENOBUFS;
+ if (ccid_get_builtin_ccids(&rx.val, &rx.len)) {
+ kfree(tx.val);
+ return -ENOBUFS;
+ }
if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
!dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 86b0933..8fc1600 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -637,6 +637,7 @@
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+ reqsk_put(req);
return 0;
drop_and_free:
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 2ac9d2a..28e8252 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -380,6 +380,7 @@
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
+ reqsk_put(req);
return 0;
drop_and_free:
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 9fe25bf..b68168f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -24,6 +24,7 @@
#include <net/checksum.h>
#include <net/inet_sock.h>
+#include <net/inet_common.h>
#include <net/sock.h>
#include <net/xfrm.h>
@@ -170,6 +171,15 @@
EXPORT_SYMBOL_GPL(dccp_packet_name);
+static void dccp_sk_destruct(struct sock *sk)
+{
+ struct dccp_sock *dp = dccp_sk(sk);
+
+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+ dp->dccps_hc_tx_ccid = NULL;
+ inet_sock_destruct(sk);
+}
+
int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -179,6 +189,7 @@
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
sk->sk_state = DCCP_CLOSED;
sk->sk_write_space = dccp_write_space;
+ sk->sk_destruct = dccp_sk_destruct;
icsk->icsk_sync_mss = dccp_sync_mss;
dp->dccps_mss_cache = 536;
dp->dccps_rate_last = jiffies;
@@ -201,10 +212,7 @@
{
struct dccp_sock *dp = dccp_sk(sk);
- /*
- * DCCP doesn't use sk_write_queue, just sk_send_head
- * for retransmissions
- */
+ __skb_queue_purge(&sk->sk_write_queue);
if (sk->sk_send_head != NULL) {
kfree_skb(sk->sk_send_head);
sk->sk_send_head = NULL;
@@ -222,8 +230,7 @@
dp->dccps_hc_rx_ackvec = NULL;
}
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
- ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
- dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+ dp->dccps_hc_rx_ccid = NULL;
/* clean up feature negotiation state */
dccp_feat_list_purge(&dp->dccps_featneg);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index ceddf42..2b887c5 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1714,6 +1714,13 @@
net->ipv4.sysctl_ip_dynaddr = 0;
net->ipv4.sysctl_ip_early_demux = 1;
+ /* Some igmp sysctl, whose values are always used */
+ net->ipv4.sysctl_igmp_max_memberships = 20;
+ net->ipv4.sysctl_igmp_max_msf = 10;
+ /* IGMP reports for link-local multicast groups are enabled by default */
+ net->ipv4.sysctl_igmp_llm_reports = 1;
+ net->ipv4.sysctl_igmp_qrv = 2;
+
return 0;
}
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 37f4578..c8409ca0 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1320,13 +1320,14 @@
void __init ip_fib_init(void)
{
- rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
- rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
- rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
+ fib_trie_init();
register_pernet_subsys(&fib_net_ops);
+
register_netdevice_notifier(&fib_netdev_notifier);
register_inetaddr_notifier(&fib_inetaddr_notifier);
- fib_trie_init();
+ rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
+ rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
+ rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
}
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 7563831..38c1c97 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1044,15 +1044,17 @@
fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
if (!fi)
goto failure;
- fib_info_cnt++;
if (cfg->fc_mx) {
fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL);
- if (!fi->fib_metrics)
- goto failure;
+ if (unlikely(!fi->fib_metrics)) {
+ kfree(fi);
+ return ERR_PTR(err);
+ }
atomic_set(&fi->fib_metrics->refcnt, 1);
- } else
+ } else {
fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
-
+ }
+ fib_info_cnt++;
fi->fib_net = net;
fi->fib_protocol = cfg->fc_protocol;
fi->fib_scope = cfg->fc_scope;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 19930da..08575e3 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2974,12 +2974,6 @@
goto out_sock;
}
- /* Sysctl initialization */
- net->ipv4.sysctl_igmp_max_memberships = 20;
- net->ipv4.sysctl_igmp_max_msf = 10;
- /* IGMP reports for link-local multicast groups are enabled by default */
- net->ipv4.sysctl_igmp_llm_reports = 1;
- net->ipv4.sysctl_igmp_qrv = 2;
return 0;
out_sock:
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2c18bcf..e60f9fa 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -958,10 +958,12 @@
csummode = CHECKSUM_PARTIAL;
cork->length += length;
- if (((length > mtu) || (skb && skb_is_gso(skb))) &&
+ if ((skb && skb_is_gso(skb)) ||
+ ((length > mtu) &&
+ (skb_queue_len(queue) <= 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
- (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) {
+ (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx)) {
err = ip_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, transhdrlen,
maxfraglen, flags);
@@ -1277,6 +1279,7 @@
return -EINVAL;
if ((size + skb->len > mtu) &&
+ (skb_queue_len(&sk->sk_write_queue) == 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO)) {
if (skb->ip_summed != CHECKSUM_PARTIAL)
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
index fd82202..146d861 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -126,6 +126,8 @@
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb));
+ nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
+
skb_reserve(nskb, LL_MAX_HEADER);
niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
ip4_dst_hoplimit(skb_dst(nskb)));
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 18c6e79..a4faf30 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1253,7 +1253,7 @@
if (mtu)
return mtu;
- mtu = dst->dev->mtu;
+ mtu = READ_ONCE(dst->dev->mtu);
if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
if (rt->rt_uses_gateway && mtu > 576)
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 0dc6286..f56a668 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -334,6 +334,7 @@
treq = tcp_rsk(req);
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->txhash = net_tx_rndhash();
req->mss = mss;
ireq->ir_num = ntohs(th->dest);
ireq->ir_rmt_port = th->source;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 51ac77e..ccc484a 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1010,7 +1010,7 @@
.data = &init_net.ipv4.sysctl_tcp_notsent_lowat,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_douintvec,
},
#ifdef CONFIG_IP_ROUTE_MULTIPATH
{
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
index 0ea66c2..cb8db34 100644
--- a/net/ipv4/tcp_bbr.c
+++ b/net/ipv4/tcp_bbr.c
@@ -83,7 +83,8 @@
cwnd_gain:10, /* current gain for setting cwnd */
full_bw_cnt:3, /* number of rounds without large bw gains */
cycle_idx:3, /* current index in pacing_gain cycle array */
- unused_b:6;
+ has_seen_rtt:1, /* have we seen an RTT sample yet? */
+ unused_b:5;
u32 prior_cwnd; /* prior cwnd upon entering loss recovery */
u32 full_bw; /* recent bw, to estimate if pipe is full */
};
@@ -182,6 +183,35 @@
return rate >> BW_SCALE;
}
+/* Convert a BBR bw and gain factor to a pacing rate in bytes per second. */
+static u32 bbr_bw_to_pacing_rate(struct sock *sk, u32 bw, int gain)
+{
+ u64 rate = bw;
+
+ rate = bbr_rate_bytes_per_sec(sk, rate, gain);
+ rate = min_t(u64, rate, sk->sk_max_pacing_rate);
+ return rate;
+}
+
+/* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
+static void bbr_init_pacing_rate_from_rtt(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct bbr *bbr = inet_csk_ca(sk);
+ u64 bw;
+ u32 rtt_us;
+
+ if (tp->srtt_us) { /* any RTT sample yet? */
+ rtt_us = max(tp->srtt_us >> 3, 1U);
+ bbr->has_seen_rtt = 1;
+ } else { /* no RTT sample yet */
+ rtt_us = USEC_PER_MSEC; /* use nominal default RTT */
+ }
+ bw = (u64)tp->snd_cwnd * BW_UNIT;
+ do_div(bw, rtt_us);
+ sk->sk_pacing_rate = bbr_bw_to_pacing_rate(sk, bw, bbr_high_gain);
+}
+
/* Pace using current bw estimate and a gain factor. In order to help drive the
* network toward lower queues while maintaining high utilization and low
* latency, the average pacing rate aims to be slightly (~1%) lower than the
@@ -191,12 +221,13 @@
*/
static void bbr_set_pacing_rate(struct sock *sk, u32 bw, int gain)
{
+ struct tcp_sock *tp = tcp_sk(sk);
struct bbr *bbr = inet_csk_ca(sk);
- u64 rate = bw;
+ u32 rate = bbr_bw_to_pacing_rate(sk, bw, gain);
- rate = bbr_rate_bytes_per_sec(sk, rate, gain);
- rate = min_t(u64, rate, sk->sk_max_pacing_rate);
- if (bbr->mode != BBR_STARTUP || rate > sk->sk_pacing_rate)
+ if (unlikely(!bbr->has_seen_rtt && tp->srtt_us))
+ bbr_init_pacing_rate_from_rtt(sk);
+ if (bbr_full_bw_reached(sk) || rate > sk->sk_pacing_rate)
sk->sk_pacing_rate = rate;
}
@@ -769,7 +800,6 @@
{
struct tcp_sock *tp = tcp_sk(sk);
struct bbr *bbr = inet_csk_ca(sk);
- u64 bw;
bbr->prior_cwnd = 0;
bbr->tso_segs_goal = 0; /* default segs per skb until first ACK */
@@ -785,11 +815,8 @@
minmax_reset(&bbr->bw, bbr->rtt_cnt, 0); /* init max bw to 0 */
- /* Initialize pacing rate to: high_gain * init_cwnd / RTT. */
- bw = (u64)tp->snd_cwnd * BW_UNIT;
- do_div(bw, (tp->srtt_us >> 3) ? : USEC_PER_MSEC);
- sk->sk_pacing_rate = 0; /* force an update of sk_pacing_rate */
- bbr_set_pacing_rate(sk, bw, bbr_high_gain);
+ bbr->has_seen_rtt = 0;
+ bbr_init_pacing_rate_from_rtt(sk);
bbr->restore_cwnd = 0;
bbr->round_start = 0;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3d980d6..491b03a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2561,8 +2561,8 @@
return;
/* Reset cwnd to ssthresh in CWR or Recovery (unless it's undone) */
- if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR ||
- (tp->undo_marker && tp->snd_ssthresh < TCP_INFINITE_SSTHRESH)) {
+ if (tp->snd_ssthresh < TCP_INFINITE_SSTHRESH &&
+ (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || tp->undo_marker)) {
tp->snd_cwnd = tp->snd_ssthresh;
tp->snd_cwnd_stamp = tcp_time_stamp;
}
@@ -3037,8 +3037,7 @@
/* delta may not be positive if the socket is locked
* when the retrans timer fires and is rescheduled.
*/
- if (delta > 0)
- rto = delta;
+ rto = max(delta, 1);
}
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
TCP_RTO_MAX);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e6bf011..a835716 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3344,6 +3344,9 @@
struct sk_buff *buff;
int err;
+ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
+ return -EHOSTUNREACH; /* Routing failure or similar. */
+
tcp_connect_init(sk);
if (unlikely(tp->repair)) {
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 732060d..d3d3ef6 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -686,7 +686,8 @@
goto death;
}
- if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE)
+ if (!sock_flag(sk, SOCK_KEEPOPEN) ||
+ ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)))
goto out;
elapsed = keepalive_time_when(tp);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fe24424..7c1f5f6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -818,7 +818,7 @@
if (is_udplite) /* UDP-Lite */
csum = udplite_csum(skb);
- else if (sk->sk_no_check_tx) { /* UDP csum disabled */
+ else if (sk->sk_no_check_tx && !skb_is_gso(skb)) { /* UDP csum off */
skb->ip_summed = CHECKSUM_NONE;
goto send;
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index b2be1d9..6de016f 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -232,7 +232,7 @@
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
/* If there is no outer header we can fake a checksum offload
* due to the fact that we have already done the checksum in
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 4345ee3..ff38959 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -897,6 +897,8 @@
}
nsiblings = iter->rt6i_nsiblings;
fib6_purge_rt(iter, fn, info->nl_net);
+ if (fn->rr_ptr == iter)
+ fn->rr_ptr = NULL;
rt6_release(iter);
if (nsiblings) {
@@ -909,6 +911,8 @@
if (rt6_qualify_for_ecmp(iter)) {
*ins = iter->dst.rt6_next;
fib6_purge_rt(iter, fn, info->nl_net);
+ if (fn->rr_ptr == iter)
+ fn->rr_ptr = NULL;
rt6_release(iter);
nsiblings--;
} else {
@@ -997,7 +1001,7 @@
/* Create subtree root node */
sfn = node_alloc();
if (!sfn)
- goto st_failure;
+ goto failure;
sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
@@ -1013,12 +1017,12 @@
if (IS_ERR(sn)) {
/* If it is failed, discard just allocated
- root, and then (in st_failure) stale node
+ root, and then (in failure) stale node
in main tree.
*/
node_free(sfn);
err = PTR_ERR(sn);
- goto st_failure;
+ goto failure;
}
/* Now link new subtree to main tree */
@@ -1032,7 +1036,7 @@
if (IS_ERR(sn)) {
err = PTR_ERR(sn);
- goto st_failure;
+ goto failure;
}
}
@@ -1074,22 +1078,22 @@
atomic_inc(&pn->leaf->rt6i_ref);
}
#endif
- if (!(rt->dst.flags & DST_NOCACHE))
- dst_free(&rt->dst);
+ goto failure;
}
return err;
-#ifdef CONFIG_IPV6_SUBTREES
- /* Subtree creation failed, probably main tree node
- is orphan. If it is, shoot it.
+failure:
+ /* fn->leaf could be NULL if fn is an intermediate node and we
+ * failed to add the new route to it in both subtree creation
+ * failure and fib6_add_rt2node() failure case.
+ * In both cases, fib6_repair_tree() should be called to fix
+ * fn->leaf.
*/
-st_failure:
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
fib6_repair_tree(info->nl_net, fn);
if (!(rt->dst.flags & DST_NOCACHE))
dst_free(&rt->dst);
return err;
-#endif
}
/*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4403260..821aa0b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -671,8 +671,6 @@
*prevhdr = NEXTHDR_FRAGMENT;
tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
if (!tmp_hdr) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
goto fail;
}
@@ -791,8 +789,6 @@
frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
hroom + troom, GFP_ATOMIC);
if (!frag) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
goto fail;
}
@@ -1384,11 +1380,12 @@
*/
cork->length += length;
- if ((((length + fragheaderlen) > mtu) ||
- (skb && skb_is_gso(skb))) &&
+ if ((skb && skb_is_gso(skb)) ||
+ (((length + fragheaderlen) > mtu) &&
+ (skb_queue_len(queue) <= 1) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
- (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
+ (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk))) {
err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
hh_len, fragheaderlen, exthdrlen,
transhdrlen, mtu, flags, fl6);
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
index 1009040..eedee5d 100644
--- a/net/ipv6/netfilter/nf_reject_ipv6.c
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -157,6 +157,7 @@
fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source;
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
+ fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) {
@@ -180,6 +181,8 @@
skb_dst_set(nskb, dst);
+ nskb->mark = fl6.flowi6_mark;
+
skb_reserve(nskb, hh_len + dst->header_len);
ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
ip6_dst_hoplimit(dst));
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index e9065b8..abb2c30 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -78,7 +78,7 @@
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
- u16 offset = sizeof(struct ipv6hdr);
+ unsigned int offset = sizeof(struct ipv6hdr);
unsigned int packet_len = skb_tail_pointer(skb) -
skb_network_header(skb);
int found_rhdr = 0;
@@ -86,6 +86,7 @@
while (offset <= packet_len) {
struct ipv6_opt_hdr *exthdr;
+ unsigned int len;
switch (**nexthdr) {
@@ -111,7 +112,10 @@
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
offset);
- offset += ipv6_optlen(exthdr);
+ len = ipv6_optlen(exthdr);
+ if (len + offset >= IPV6_MAXPLEN)
+ return -EINVAL;
+ offset += len;
*nexthdr = &exthdr->nexthdr;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 97830a6..a67174e 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -209,6 +209,7 @@
treq->snt_synack.v64 = 0;
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;
+ treq->txhash = net_tx_rndhash();
/*
* We need to lookup the dst_entry to get the correct window size.
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c925fd9..c43ef0c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -915,6 +915,7 @@
*/
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
+ csum = skb->csum;
skb->ip_summed = CHECKSUM_NONE;
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index a2267f8..e7d378c 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -72,7 +72,7 @@
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
/* If there is no outer header we can fake a checksum offload
* due to the fact that we have already done the checksum in
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 391c3cb..101ed6c 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2223,7 +2223,7 @@
{
struct sock *sk = sock->sk;
struct irda_sock *self = irda_sk(sk);
- struct irda_device_list list;
+ struct irda_device_list list = { 0 };
struct irda_device_info *discoveries;
struct irda_ias_set * ias_opt; /* IAS get/query params */
struct ias_object * ias_obj; /* Object in IAS */
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 2e1050e..94bf810 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -228,7 +228,7 @@
#define BROADCAST_ONE 1
#define BROADCAST_REGISTERED 2
#define BROADCAST_PROMISC_ONLY 4
-static int pfkey_broadcast(struct sk_buff *skb,
+static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
int broadcast_flags, struct sock *one_sk,
struct net *net)
{
@@ -278,7 +278,7 @@
rcu_read_unlock();
if (one_sk != NULL)
- err = pfkey_broadcast_one(skb, &skb2, GFP_KERNEL, one_sk);
+ err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
kfree_skb(skb2);
kfree_skb(skb);
@@ -311,7 +311,7 @@
hdr = (struct sadb_msg *) pfk->dump.skb->data;
hdr->sadb_msg_seq = 0;
hdr->sadb_msg_errno = rc;
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = NULL;
}
@@ -355,7 +355,7 @@
hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
sizeof(uint64_t));
- pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+ pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk));
return 0;
}
@@ -1396,7 +1396,7 @@
xfrm_state_put(x);
- pfkey_broadcast(resp_skb, BROADCAST_ONE, sk, net);
+ pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net);
return 0;
}
@@ -1483,7 +1483,7 @@
hdr->sadb_msg_seq = c->seq;
hdr->sadb_msg_pid = c->portid;
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, xs_net(x));
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x));
return 0;
}
@@ -1596,7 +1596,7 @@
out_hdr->sadb_msg_reserved = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, BROADCAST_ONE, sk, sock_net(sk));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
return 0;
}
@@ -1701,8 +1701,8 @@
return -ENOBUFS;
}
- pfkey_broadcast(supp_skb, BROADCAST_REGISTERED, sk, sock_net(sk));
-
+ pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk,
+ sock_net(sk));
return 0;
}
@@ -1720,7 +1720,8 @@
hdr->sadb_msg_errno = (uint8_t) 0;
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk,
+ sock_net(sk));
}
static int key_notify_sa_flush(const struct km_event *c)
@@ -1741,7 +1742,7 @@
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
hdr->sadb_msg_reserved = 0;
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, c->net);
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
return 0;
}
@@ -1798,7 +1799,7 @@
out_hdr->sadb_msg_pid = pfk->dump.msg_portid;
if (pfk->dump.skb)
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = out_skb;
@@ -1886,7 +1887,7 @@
new_hdr->sadb_msg_errno = 0;
}
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, sock_net(sk));
+ pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk));
return 0;
}
@@ -2219,7 +2220,7 @@
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = c->seq;
out_hdr->sadb_msg_pid = c->portid;
- pfkey_broadcast(out_skb, BROADCAST_ALL, NULL, xp_net(xp));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp));
return 0;
}
@@ -2439,7 +2440,7 @@
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp));
err = 0;
out:
@@ -2695,7 +2696,7 @@
out_hdr->sadb_msg_pid = pfk->dump.msg_portid;
if (pfk->dump.skb)
- pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+ pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk, sock_net(&pfk->sk));
pfk->dump.skb = out_skb;
@@ -2752,7 +2753,7 @@
hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
hdr->sadb_msg_reserved = 0;
- pfkey_broadcast(skb_out, BROADCAST_ALL, NULL, c->net);
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
return 0;
}
@@ -2814,7 +2815,7 @@
void *ext_hdrs[SADB_EXT_MAX];
int err;
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL),
+ pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
BROADCAST_PROMISC_ONLY, NULL, sock_net(sk));
memset(ext_hdrs, 0, sizeof(ext_hdrs));
@@ -3036,7 +3037,8 @@
out_hdr->sadb_msg_seq = 0;
out_hdr->sadb_msg_pid = 0;
- pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
return 0;
}
@@ -3226,7 +3228,8 @@
xfrm_ctx->ctx_len);
}
- return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
}
static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
@@ -3424,7 +3427,8 @@
n_port->sadb_x_nat_t_port_port = sport;
n_port->sadb_x_nat_t_port_reserved = 0;
- return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+ return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+ xs_net(x));
}
#ifdef CONFIG_NET_KEY_MIGRATE
@@ -3616,7 +3620,7 @@
}
/* broadcast migrate message to sockets */
- pfkey_broadcast(skb, BROADCAST_ALL, NULL, &init_net);
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net);
return 0;
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index 02bcf00..008299b 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -53,7 +53,11 @@
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[id]);
- BUG_ON(t == NULL);
+ if (!t) {
+ rcu_read_unlock();
+ return NULL;
+ }
+
off = ALIGN(sizeof(struct nf_ct_ext), t->align);
len = off + t->len + var_alloc_len;
alloc_size = t->alloc_size + var_alloc_len;
@@ -88,7 +92,10 @@
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[id]);
- BUG_ON(t == NULL);
+ if (!t) {
+ rcu_read_unlock();
+ return NULL;
+ }
newoff = ALIGN(old->len, t->align);
newlen = newoff + t->len + var_alloc_len;
@@ -175,6 +182,6 @@
RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
update_alloc_size(type);
mutex_unlock(&nf_ct_ext_type_mutex);
- rcu_barrier(); /* Wait for completion of call_rcu()'s */
+ synchronize_rcu();
}
EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 5b9c884..dde64c4 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -225,20 +225,21 @@
.tuple = tuple,
.zone = zone
};
- struct rhlist_head *hl;
+ struct rhlist_head *hl, *h;
hl = rhltable_lookup(&nf_nat_bysource_table, &key,
nf_nat_bysource_params);
- if (!hl)
- return 0;
- ct = container_of(hl, typeof(*ct), nat_bysource);
+ rhl_for_each_entry_rcu(ct, h, hl, nat_bysource) {
+ nf_ct_invert_tuplepr(result,
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ result->dst = tuple->dst;
- nf_ct_invert_tuplepr(result,
- &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- result->dst = tuple->dst;
+ if (in_range(l3proto, l4proto, result, range))
+ return 1;
+ }
- return in_range(l3proto, l4proto, result, range);
+ return 0;
}
/* For [FUTURE] fragmentation handling, we want the least-used
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 1fbe4b6..ade9306 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1597,14 +1597,6 @@
if (sk) {
MT_DEBUG("qtaguid: %p->sk_proto=%u "
"->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
- /*
- * When in TCP_TIME_WAIT the sk is not a "struct sock" but
- * "struct inet_timewait_sock" which is missing fields.
- */
- if (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT) {
- sock_gen_put(sk);
- sk = NULL;
- }
}
return sk;
}
@@ -1697,10 +1689,25 @@
*/
sk = qtaguid_find_sk(skb, par);
/*
- * If we got the socket from the find_sk(), we will need to put
- * it back, as nf_tproxy_get_sock_v4() got it.
+ * TCP_NEW_SYN_RECV are not "struct sock" but "struct request_sock"
+ * where we can get a pointer to a full socket to retrieve uid/gid.
+ * When in TCP_TIME_WAIT, sk is a struct inet_timewait_sock
+ * which is missing fields and does not contain any reference
+ * to a full socket, so just ignore the socket.
*/
- got_sock = sk;
+ if (sk && sk->sk_state == TCP_NEW_SYN_RECV) {
+ sock_gen_put(sk);
+ sk = sk_to_full_sk(sk);
+ } else if (sk && (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT)) {
+ sock_gen_put(sk);
+ sk = NULL;
+ } else {
+ /*
+ * If we got the socket from the find_sk(), we will need to put
+ * it back, as nf_tproxy_get_sock_v4() got it.
+ */
+ got_sock = sk;
+ }
if (sk)
atomic64_inc(&qtu_events.match_found_sk_in_ct);
else
@@ -1710,18 +1717,9 @@
}
MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
- if (sk != NULL) {
- set_sk_callback_lock = true;
- read_lock_bh(&sk->sk_callback_lock);
- MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
- par->hooknum, sk, sk->sk_socket,
- sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
- filp = sk->sk_socket ? sk->sk_socket->file : NULL;
- MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
- par->hooknum, filp ? from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
- }
- if (sk == NULL || sk->sk_socket == NULL) {
+
+ if (sk == NULL) {
/*
* Here, the qtaguid_find_sk() using connection tracking
* couldn't find the owner, so for now we just count them
@@ -1734,9 +1732,7 @@
*/
if (!(info->match & XT_QTAGUID_UID))
account_for_uid(skb, sk, 0, par);
- MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
- par->hooknum,
- sk ? sk->sk_socket : NULL);
+ MT_DEBUG("qtaguid[%d]: leaving (sk=NULL)\n", par->hooknum);
res = (info->match ^ info->invert) == 0;
atomic64_inc(&qtu_events.match_no_sk);
goto put_sock_ret_res;
@@ -1744,16 +1740,7 @@
res = false;
goto put_sock_ret_res;
}
- filp = sk->sk_socket->file;
- if (filp == NULL) {
- MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
- account_for_uid(skb, sk, 0, par);
- res = ((info->match ^ info->invert) &
- (XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
- atomic64_inc(&qtu_events.match_no_sk_file);
- goto put_sock_ret_res;
- }
- sock_uid = filp->f_cred->fsuid;
+ sock_uid = sk->sk_uid;
/*
* TODO: unhack how to force just accounting.
* For now we only do iface stats when the uid-owner is not requested
@@ -1771,8 +1758,8 @@
kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max);
- if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
- uid_lte(filp->f_cred->fsuid, uid_max)) ^
+ if ((uid_gte(sk->sk_uid, uid_min) &&
+ uid_lte(sk->sk_uid, uid_max)) ^
!(info->invert & XT_QTAGUID_UID)) {
MT_DEBUG("qtaguid[%d]: leaving uid not matching\n",
par->hooknum);
@@ -1783,7 +1770,19 @@
if (info->match & XT_QTAGUID_GID) {
kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
-
+ set_sk_callback_lock = true;
+ read_lock_bh(&sk->sk_callback_lock);
+ MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
+ par->hooknum, sk, sk->sk_socket,
+ sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
+ filp = sk->sk_socket ? sk->sk_socket->file : NULL;
+ if (!filp) {
+ res = ((info->match ^ info->invert) & XT_QTAGUID_GID) == 0;
+ atomic64_inc(&qtu_events.match_no_sk_gid);
+ goto put_sock_ret_res;
+ }
+ MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
+ par->hooknum, filp ? from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
gid_lte(filp->f_cred->fsgid, gid_max)) ^
!(info->invert & XT_QTAGUID_GID)) {
@@ -1955,7 +1954,7 @@
"match_found_sk_in_ct=%llu "
"match_found_no_sk_in_ct=%llu "
"match_no_sk=%llu "
- "match_no_sk_file=%llu\n",
+ "match_no_sk_gid=%llu\n",
(u64)atomic64_read(&qtu_events.sockets_tagged),
(u64)atomic64_read(&qtu_events.sockets_untagged),
(u64)atomic64_read(&qtu_events.counter_set_changes),
@@ -1967,7 +1966,7 @@
(u64)atomic64_read(&qtu_events.match_found_sk_in_ct),
(u64)atomic64_read(&qtu_events.match_found_no_sk_in_ct),
(u64)atomic64_read(&qtu_events.match_no_sk),
- (u64)atomic64_read(&qtu_events.match_no_sk_file));
+ (u64)atomic64_read(&qtu_events.match_no_sk_gid));
/* Count the following as part of the last item_index. No need
* to lock the sock_tag_list here since it is already locked when
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
index 8178fbd..c705270 100644
--- a/net/netfilter/xt_qtaguid_internal.h
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -289,10 +289,10 @@
*/
atomic64_t match_no_sk;
/*
- * The file ptr in the sk_socket wasn't there.
+ * The file ptr in the sk_socket wasn't there and we couldn't get GID.
* This might happen for traffic while the socket is being closed.
*/
- atomic64_t match_no_sk_file;
+ atomic64_t match_no_sk_gid;
};
/* Track the set active_set for the given tag. */
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 2b0f0ac..5a58f9f 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -209,6 +209,11 @@
}
create_info = (struct hci_create_pipe_resp *)skb->data;
+ if (create_info->pipe >= NFC_HCI_MAX_PIPES) {
+ status = NFC_HCI_ANY_E_NOK;
+ goto exit;
+ }
+
/* Save the new created pipe and bind with local gate,
* the description for skb->data[3] is destination gate id
* but since we received this cmd from host controller, we
@@ -232,6 +237,11 @@
}
delete_info = (struct hci_delete_pipe_noti *)skb->data;
+ if (delete_info->pipe >= NFC_HCI_MAX_PIPES) {
+ status = NFC_HCI_ANY_E_NOK;
+ goto exit;
+ }
+
hdev->pipes[delete_info->pipe].gate = NFC_HCI_INVALID_GATE;
hdev->pipes[delete_info->pipe].dest_host = NFC_HCI_INVALID_HOST;
break;
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 4e03f64..05d9f42 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1240,6 +1240,7 @@
goto out;
}
+ OVS_CB(skb)->acts_origlen = acts->orig_len;
err = do_execute_actions(dp, skb, key,
acts->actions, acts->actions_len);
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 48386bf..b28e45b 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -1088,8 +1088,8 @@
nla_for_each_nested(a, attr, rem) {
int type = nla_type(a);
- int maxlen = ovs_ct_attr_lens[type].maxlen;
- int minlen = ovs_ct_attr_lens[type].minlen;
+ int maxlen;
+ int minlen;
if (type > OVS_CT_ATTR_MAX) {
OVS_NLERR(log,
@@ -1097,6 +1097,9 @@
type, OVS_CT_ATTR_MAX);
return -EINVAL;
}
+
+ maxlen = ovs_ct_attr_lens[type].maxlen;
+ minlen = ovs_ct_attr_lens[type].minlen;
if (nla_len(a) < minlen || nla_len(a) > maxlen) {
OVS_NLERR(log,
"Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)",
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 4d67ea8..453f806 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -383,7 +383,7 @@
}
static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
- unsigned int hdrlen)
+ unsigned int hdrlen, int actions_attrlen)
{
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
@@ -400,7 +400,7 @@
/* OVS_PACKET_ATTR_ACTIONS */
if (upcall_info->actions_len)
- size += nla_total_size(upcall_info->actions_len);
+ size += nla_total_size(actions_attrlen);
/* OVS_PACKET_ATTR_MRU */
if (upcall_info->mru)
@@ -467,7 +467,8 @@
else
hlen = skb->len;
- len = upcall_msg_size(upcall_info, hlen - cutlen);
+ len = upcall_msg_size(upcall_info, hlen - cutlen,
+ OVS_CB(skb)->acts_origlen);
user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index ab85c1c..e19ace4 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -100,12 +100,14 @@
* @input_vport: The original vport packet came in on. This value is cached
* when a packet is received by OVS.
* @mru: The maximum received fragement size; 0 if the packet is not
+ * @acts_origlen: The netlink size of the flow actions applied to this skb.
* @cutlen: The number of bytes from the packet end to be removed.
* fragmented.
*/
struct ovs_skb_cb {
struct vport *input_vport;
u16 mru;
+ u16 acts_origlen;
u32 cutlen;
};
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6a563e6..ae7bfd2 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3698,14 +3698,19 @@
if (optlen != sizeof(val))
return -EINVAL;
- if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
- return -EBUSY;
if (copy_from_user(&val, optval, sizeof(val)))
return -EFAULT;
if (val > INT_MAX)
return -EINVAL;
- po->tp_reserve = val;
- return 0;
+ lock_sock(sk);
+ if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+ ret = -EBUSY;
+ } else {
+ po->tp_reserve = val;
+ ret = 0;
+ }
+ release_sock(sk);
+ return ret;
}
case PACKET_LOSS:
{
@@ -4322,7 +4327,7 @@
register_prot_hook(sk);
}
spin_unlock(&po->bind_lock);
- if (closing && (po->tp_version > TPACKET_V2)) {
+ if (pg_vec && (po->tp_version > TPACKET_V2)) {
/* Because we don't support block-based V3 on tx-ring */
if (!tx_ring)
prb_shutdown_retire_blk_timer(po, rb_queue);
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 378c1c9..5003051 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -41,6 +41,7 @@
{
struct xt_tgchk_param par;
struct xt_target *target;
+ struct ipt_entry e = {};
int ret = 0;
target = xt_request_find_target(AF_INET, t->u.user.name,
@@ -49,8 +50,9 @@
return PTR_ERR(target);
t->u.kernel.target = target;
+ memset(&par, 0, sizeof(par));
par.table = table;
- par.entryinfo = NULL;
+ par.entryinfo = &e;
par.target = target;
par.targinfo = t->data;
par.hook_mask = hook;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index daf6624..a74d32e 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -277,9 +277,6 @@
void qdisc_hash_add(struct Qdisc *q)
{
if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
- struct Qdisc *root = qdisc_dev(q)->qdisc;
-
- WARN_ON_ONCE(root == &noop_qdisc);
ASSERT_RTNL();
hash_add_rcu(qdisc_dev(q)->qdisc_hash, &q->hash, q->handle);
}
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index bc5e995..ea8a56f 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -434,6 +434,7 @@
qdisc_drop(head, sch, to_free);
slot_queue_add(slot, skb);
+ qdisc_tree_reduce_backlog(sch, 0, delta);
return NET_XMIT_CN;
}
@@ -465,8 +466,10 @@
/* Return Congestion Notification only if we dropped a packet
* from this flow.
*/
- if (qlen != slot->qlen)
+ if (qlen != slot->qlen) {
+ qdisc_tree_reduce_backlog(sch, 0, dropped - qdisc_pkt_len(skb));
return NET_XMIT_CN;
+ }
/* As we dropped a packet, better let upper stack know this */
qdisc_tree_reduce_backlog(sch, 1, dropped);
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 0c09060..ca4a63e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -512,7 +512,9 @@
{
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
+ addr->v6.sin6_flowinfo = 0;
addr->v6.sin6_addr = *saddr;
+ addr->v6.sin6_scope_id = 0;
}
/* Compare addresses exactly.
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a4bc982..266a30c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -408,6 +408,9 @@
dprintk("svc: socket %p(inet %p), busy=%d\n",
svsk, sk,
test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_odata(sk);
if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
svc_xprt_enqueue(&svsk->sk_xprt);
@@ -424,6 +427,9 @@
if (svsk) {
dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_owspace(sk);
svc_xprt_enqueue(&svsk->sk_xprt);
}
@@ -748,8 +754,12 @@
dprintk("svc: socket %p TCP (listen) state change %d\n",
sk, sk->sk_state);
- if (svsk)
+ if (svsk) {
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_odata(sk);
+ }
+
/*
* This callback may called twice when a new connection
* is established as a child socket inherits everything
@@ -782,6 +792,8 @@
if (!svsk)
printk("svc: socket %p: no user data\n", sk);
else {
+ /* Refer to svc_setup_socket() for details. */
+ rmb();
svsk->sk_ostate(sk);
if (sk->sk_state != TCP_ESTABLISHED) {
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@ -1368,12 +1380,18 @@
return ERR_PTR(err);
}
- inet->sk_user_data = svsk;
svsk->sk_sock = sock;
svsk->sk_sk = inet;
svsk->sk_ostate = inet->sk_state_change;
svsk->sk_odata = inet->sk_data_ready;
svsk->sk_owspace = inet->sk_write_space;
+ /*
+ * This barrier is necessary in order to prevent race condition
+ * with svc_data_ready(), svc_listen_data_ready() and others
+ * when calling callbacks above.
+ */
+ wmb();
+ inet->sk_user_data = svsk;
/* Initialize the socket */
if (sock->type == SOCK_DGRAM)
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 1fd4647..aedc476 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -258,13 +258,15 @@
arg = nlmsg_new(0, GFP_KERNEL);
if (!arg) {
kfree_skb(msg->rep);
+ msg->rep = NULL;
return -ENOMEM;
}
err = __tipc_nl_compat_dumpit(cmd, msg, arg);
- if (err)
+ if (err) {
kfree_skb(msg->rep);
-
+ msg->rep = NULL;
+ }
kfree_skb(arg);
return err;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index cf7063a..c40f3de 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -221,13 +221,7 @@
union {
struct cfg80211_connect_resp_params cr;
- struct {
- const u8 *req_ie;
- const u8 *resp_ie;
- size_t req_ie_len;
- size_t resp_ie_len;
- struct cfg80211_bss *bss;
- } rm;
+ struct cfg80211_roam_info rm;
struct {
const u8 *ie;
size_t ie_len;
@@ -385,9 +379,7 @@
struct net_device *dev, u16 reason,
bool wextev);
void __cfg80211_roamed(struct wireless_dev *wdev,
- struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len);
+ struct cfg80211_roam_info *info);
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 413deff..cad82a4 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -223,17 +223,16 @@
(5490 - 5710 @ 160), (30), DFS
country BZ:
- (2402 - 2482 @ 40), (36)
- (5170 - 5330 @ 160), (27)
- (5490 - 5730 @ 160), (36)
- (5735 - 5835 @ 80), (36)
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5330 @ 160), (23)
+ (5490 - 5730 @ 160), (30)
+ (5735 - 5835 @ 80), (30)
country CA: DFS-FCC
(2402 - 2472 @ 40), (30)
(5170 - 5250 @ 80), (24), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
- (5490 - 5590 @ 80), (24), DFS
- (5650 - 5730 @ 80), (24), DFS
+ (5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
# 60 gHz band channels 1-3
(57240 - 63720 @ 2160), (40)
@@ -682,7 +681,13 @@
country IN:
(2402 - 2482 @ 40), (20)
(5170 - 5330 @ 160), (23)
- (5735 - 5835 @ 80), (30)
+ (5735 - 5835 @ 80), (33)
+
+country IQ: DFS-ETSI
+ (2402 - 2482 @ 40), (20)
+ (5170 - 5250 @ 80), (23), AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5490 - 5710 @ 160), (30), DFS
country IS: DFS-ETSI
(2402 - 2482 @ 40), (20)
@@ -736,7 +741,6 @@
country JP: DFS-JP
(2402 - 2482 @ 40), (20)
- (2474 - 2494 @ 20), (20), NO-OFDM
(5170 - 5250 @ 80), (20), AUTO-BW, NO-OUTDOOR
(5250 - 5330 @ 80), (20), DFS, AUTO-BW, NO-OUTDOOR
(5490 - 5710 @ 160), (20), DFS
@@ -758,7 +762,7 @@
country KN: DFS-FCC
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
- (5250 - 5330 @ 80), (23), DFS, AUTO-BW
+ (5250 - 5330 @ 80), (30), DFS, AUTO-BW
(5490 - 5710 @ 160), (30), DFS
(5735 - 5815 @ 80), (30)
@@ -1009,7 +1013,7 @@
(5170 - 5250 @ 80), (24), AUTO-BW
(5250 - 5330 @ 80), (24), DFS, AUTO-BW
(5490 - 5650 @ 160), (24), DFS
- (5735 - 5815 @ 80), (24)
+ (5735 - 5835 @ 80), (24)
# 60 gHz band channels 1-3
(57240 - 63720 @ 2160), (40)
@@ -1089,7 +1093,7 @@
(5490 - 5710 @ 160), (30), DFS
country PA:
- (2402 - 2472 @ 40), (30)
+ (2402 - 2472 @ 40), (36)
(5170 - 5250 @ 80), (23), AUT0-BW
(5250 - 5330 @ 80), (30), AUTO-BW
(5735 - 5835 @ 80), (36)
@@ -1374,9 +1378,9 @@
country TT:
(2402 - 2482 @ 40), (20)
- (5170 - 5330 @ 160), (27)
- (5490 - 5730 @ 160), (36)
- (5735 - 5835 @ 80), (36)
+ (5170 - 5330 @ 160), (24)
+ (5490 - 5730 @ 160), (24)
+ (5735 - 5835 @ 80), (30)
# 60 gHz band channels 1-3, FCC
(57240 - 63720 @ 2160), (40)
@@ -1450,7 +1454,7 @@
country UZ: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
- (5250 - 5330 @ 80), (20), DFS, AUTO-BW
+ (5250 - 5330 @ 80), (23), DFS, AUTO-BW
country VC: DFS-ETSI
(2402 - 2482 @ 40), (20)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ebd9a4b..adf7d03 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13415,14 +13415,14 @@
}
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+ struct net_device *netdev,
+ struct cfg80211_roam_info *info, gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
+ const u8 *bssid = info->bss ? info->bss->bssid : info->bssid;
- msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
+ msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len, gfp);
if (!msg)
return;
@@ -13435,10 +13435,14 @@
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) ||
- (req_ie &&
- nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
- (resp_ie &&
- nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ (info->req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len,
+ info->req_ie)) ||
+ (info->resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
+ info->resp_ie)) ||
+ (info->authorized &&
+ nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2a84d18..c9d4805 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -59,9 +59,8 @@
struct cfg80211_connect_resp_params *params,
gfp_t gfp);
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+ struct net_device *netdev,
+ struct cfg80211_roam_info *info, gfp_t gfp);
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u16 reason,
const u8 *ie, size_t ie_len, bool from_ap);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d7e6abc..bb7f5be 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -5,6 +5,7 @@
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009 Intel Corporation. All rights reserved.
+ * Copyright 2017 Intel Deutschland GmbH
*/
#include <linux/etherdevice.h>
@@ -893,9 +894,7 @@
/* Consumes bss object one way or another */
void __cfg80211_roamed(struct wireless_dev *wdev,
- struct cfg80211_bss *bss,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len)
+ struct cfg80211_roam_info *info)
{
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
@@ -913,97 +912,85 @@
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
- cfg80211_hold_bss(bss_from_pub(bss));
- wdev->current_bss = bss_from_pub(bss);
+ if (WARN_ON(!info->bss))
+ return;
+
+ cfg80211_hold_bss(bss_from_pub(info->bss));
+ wdev->current_bss = bss_from_pub(info->bss);
nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
- wdev->netdev, bss->bssid,
- req_ie, req_ie_len, resp_ie, resp_ie_len,
- GFP_KERNEL);
+ wdev->netdev, info, GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
- if (req_ie) {
+ if (info->req_ie) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = req_ie_len;
+ wrqu.data.length = info->req_ie_len;
wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
- &wrqu, req_ie);
+ &wrqu, info->req_ie);
}
- if (resp_ie) {
+ if (info->resp_ie) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = resp_ie_len;
+ wrqu.data.length = info->resp_ie_len;
wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
- &wrqu, resp_ie);
+ &wrqu, info->resp_ie);
}
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- memcpy(wdev->wext.prev_bssid, bss->bssid, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN);
+ memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN);
wdev->wext.prev_bssid_valid = true;
wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
#endif
return;
out:
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, info->bss);
}
-void cfg80211_roamed(struct net_device *dev,
- struct ieee80211_channel *channel,
- const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_bss *bss;
-
- bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
- wdev->ssid_len,
- wdev->conn_bss_type, IEEE80211_PRIVACY_ANY);
- if (WARN_ON(!bss))
- return;
-
- cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie,
- resp_ie_len, gfp);
-}
-EXPORT_SYMBOL(cfg80211_roamed);
-
-/* Consumes bss object one way or another */
-void cfg80211_roamed_bss(struct net_device *dev,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, gfp_t gfp)
+/* Consumes info->bss object one way or another */
+void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
+ gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
- if (WARN_ON(!bss))
+ if (!info->bss) {
+ info->bss = cfg80211_get_bss(wdev->wiphy, info->channel,
+ info->bssid, wdev->ssid,
+ wdev->ssid_len,
+ wdev->conn_bss_type,
+ IEEE80211_PRIVACY_ANY);
+ }
+
+ if (WARN_ON(!info->bss))
return;
- ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len, gfp);
if (!ev) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, info->bss);
return;
}
ev->type = EVENT_ROAMED;
ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
- ev->rm.req_ie_len = req_ie_len;
- memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
- ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
- ev->rm.resp_ie_len = resp_ie_len;
- memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
- ev->rm.bss = bss;
+ ev->rm.req_ie_len = info->req_ie_len;
+ memcpy((void *)ev->rm.req_ie, info->req_ie, info->req_ie_len);
+ ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + info->req_ie_len;
+ ev->rm.resp_ie_len = info->resp_ie_len;
+ memcpy((void *)ev->rm.resp_ie, info->resp_ie, info->resp_ie_len);
+ ev->rm.bss = info->bss;
+ ev->rm.authorized = info->authorized;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
queue_work(cfg80211_wq, &rdev->event_work);
}
-EXPORT_SYMBOL(cfg80211_roamed_bss);
+EXPORT_SYMBOL(cfg80211_roamed);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8ac413f..a4ab20a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -953,9 +953,7 @@
ev->cr.status == WLAN_STATUS_SUCCESS);
break;
case EVENT_ROAMED:
- __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
- ev->rm.req_ie_len, ev->rm.resp_ie,
- ev->rm.resp_ie_len);
+ __cfg80211_roamed(wdev, &ev->rm);
break;
case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e26b515..8ce5711 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3308,9 +3308,15 @@
struct xfrm_state *x_new[XFRM_MAX_DEPTH];
struct xfrm_migrate *mp;
+ /* Stage 0 - sanity checks */
if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
goto out;
+ if (dir >= XFRM_POLICY_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+
/* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a7e27e1..b2bba35 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1695,6 +1695,10 @@
struct sk_buff *skb;
int err;
+ err = verify_policy_dir(dir);
+ if (err)
+ return ERR_PTR(err);
+
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOMEM);
@@ -2216,6 +2220,10 @@
int n = 0;
struct net *net = sock_net(skb->sk);
+ err = verify_policy_dir(pi->dir);
+ if (err)
+ return err;
+
if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL;
@@ -2331,6 +2339,11 @@
{
struct net *net = &init_net;
struct sk_buff *skb;
+ int err;
+
+ err = verify_policy_dir(dir);
+ if (err)
+ return err;
skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
if (skb == NULL)
@@ -2985,6 +2998,11 @@
static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
{
+ int err;
+
+ err = verify_policy_dir(dir);
+ if (err)
+ return err;
switch (c->event) {
case XFRM_MSG_NEWPOLICY:
diff --git a/sound/core/control.c b/sound/core/control.c
index fb096cb..995cde4 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1156,7 +1156,7 @@
mutex_lock(&ue->card->user_ctl_lock);
change = ue->tlv_data_size != size;
if (!change)
- change = memcmp(ue->tlv_data, new_data, size);
+ change = memcmp(ue->tlv_data, new_data, size) != 0;
kfree(ue->tlv_data);
ue->tlv_data = new_data;
ue->tlv_data_size = size;
diff --git a/sound/core/info.c b/sound/core/info.c
index 2ffa3fa..08558ae 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -735,8 +735,11 @@
INIT_LIST_HEAD(&entry->children);
INIT_LIST_HEAD(&entry->list);
entry->parent = parent;
- if (parent)
+ if (parent) {
+ mutex_lock(&parent->access);
list_add_tail(&entry->list, &parent->children);
+ mutex_unlock(&parent->access);
+ }
return entry;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index f3b1d7f..67c4c68 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1502,16 +1502,11 @@
static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
{
struct snd_seq_queue_info *info = arg;
- int result;
struct snd_seq_queue *q;
- result = snd_seq_queue_alloc(client->number, info->locked, info->flags);
- if (result < 0)
- return result;
-
- q = queueptr(result);
- if (q == NULL)
- return -EINVAL;
+ q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
info->queue = q->queue;
info->locked = q->locked;
@@ -1521,7 +1516,7 @@
if (!info->name[0])
snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
strlcpy(q->name, info->name, sizeof(q->name));
- queuefree(q);
+ snd_use_lock_free(&q->use_lock);
return 0;
}
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 450c518..79e0c56 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -184,22 +184,26 @@
static void queue_use(struct snd_seq_queue *queue, int client, int use);
/* allocate a new queue -
- * return queue index value or negative value for error
+ * return pointer to new queue or ERR_PTR(-errno) for error
+ * The new queue's use_lock is set to 1. It is the caller's responsibility to
+ * call snd_use_lock_free(&q->use_lock).
*/
-int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
{
struct snd_seq_queue *q;
q = queue_new(client, locked);
if (q == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
q->info_flags = info_flags;
queue_use(q, client, 1);
+ snd_use_lock_use(&q->use_lock);
if (queue_list_add(q) < 0) {
+ snd_use_lock_free(&q->use_lock);
queue_delete(q);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- return q->queue;
+ return q;
}
/* delete a queue - queue must be owned by the client */
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 30c8111..7190934 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -71,7 +71,7 @@
/* create new queue (constructor) */
-int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
+struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int flags);
/* delete queue (destructor) */
int snd_seq_queue_delete(int client, int queueid);
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
index f0e4d50..066b5df 100644
--- a/sound/firewire/iso-resources.c
+++ b/sound/firewire/iso-resources.c
@@ -210,9 +210,14 @@
*/
void fw_iso_resources_free(struct fw_iso_resources *r)
{
- struct fw_card *card = fw_parent_device(r->unit)->card;
+ struct fw_card *card;
int bandwidth, channel;
+ /* Not initialized. */
+ if (r->unit == NULL)
+ return;
+ card = fw_parent_device(r->unit)->card;
+
mutex_lock(&r->mutex);
if (r->allocated) {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c15c51b..f2e4e99 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -854,6 +854,7 @@
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bb1aad3..6f337f0 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2233,6 +2233,7 @@
SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 10c2a564..1ac96ef 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3833,6 +3833,9 @@
}
}
+ regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
+ RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
+
if (rt5645->pdata.jd_invert) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index be6290d..bd8f34a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -212,6 +212,7 @@
pr_debug("%s Don't close BE\n", __func__);
continue;
}
+
snd_soc_dapm_stream_event(be, dir, event);
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 9e7861a..6c3d62f 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -554,6 +554,8 @@
if (size < sizeof(scale))
return -ENOMEM;
+ if (cval->min_mute)
+ scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
scale[2] = cval->dBmin;
scale[3] = cval->dBmax;
if (copy_to_user(_tlv, scale, sizeof(scale)))
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3417ef3..2b4b067 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -64,6 +64,7 @@
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
+ u8 min_mute;
void *private_data;
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 04991b0..5d2fc5f 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -1873,6 +1873,12 @@
if (unitid == 7 && cval->control == UAC_FU_VOLUME)
snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
break;
+ /* lowest playback value is muted on C-Media devices */
+ case USB_ID(0x0d8c, 0x000c):
+ case USB_ID(0x0d8c, 0x0014):
+ if (strstr(kctl->id.name, "Playback"))
+ cval->min_mute = 1;
+ break;
}
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index eb4b9f7..286efc3 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1142,6 +1142,7 @@
case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */
case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
@@ -1308,10 +1309,13 @@
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(20);
- /* Zoom R16/24 needs a tiny delay here, otherwise requests like
- * get/set frequency return as failed despite actually succeeding.
+ /* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here,
+ * otherwise requests like get/set frequency return as failed despite
+ * actually succeeding.
*/
- if (chip->usb_id == USB_ID(0x1686, 0x00dd) &&
+ if ((chip->usb_id == USB_ID(0x1686, 0x00dd) ||
+ chip->usb_id == USB_ID(0x046d, 0x0a46) ||
+ chip->usb_id == USB_ID(0x0b0e, 0x0349)) &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
mdelay(1);
}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6c50d9f..6a6f44d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -163,7 +163,7 @@
/* A file path -- this is an offline module */
if (module && strchr(module, '/'))
- return machine__findnew_module_map(host_machine, 0, module);
+ return dso__new_map(module);
if (!module)
module = "kernel";
@@ -173,6 +173,7 @@
if (strncmp(pos->dso->short_name + 1, module,
pos->dso->short_name_len - 2) == 0 &&
module[pos->dso->short_name_len - 2] == '\0') {
+ map__get(pos);
return pos;
}
}
@@ -188,15 +189,6 @@
return kernel_get_module_map(target);
}
-static void put_target_map(struct map *map, bool user)
-{
- if (map && user) {
- /* Only the user map needs to be released */
- map__put(map);
- }
-}
-
-
static int convert_exec_to_group(const char *exec, char **result)
{
char *ptr1, *ptr2, *exec_copy;
@@ -412,7 +404,7 @@
}
out:
- put_target_map(map, uprobes);
+ map__put(map);
return ret;
}
@@ -2944,7 +2936,7 @@
}
out:
- put_target_map(map, pev->uprobes);
+ map__put(map);
free(syms);
return ret;
@@ -3437,10 +3429,7 @@
return ret;
/* Get a symbol map */
- if (user)
- map = dso__new_map(target);
- else
- map = kernel_get_module_map(target);
+ map = get_target_map(target, user);
if (!map) {
pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
return -EINVAL;
@@ -3472,9 +3461,7 @@
}
end:
- if (user) {
- map__put(map);
- }
+ map__put(map);
exit_probe_symbol_maps();
return ret;
diff --git a/tools/testing/selftests/ntb/ntb_test.sh b/tools/testing/selftests/ntb/ntb_test.sh
index a676d3e..b3c48fc 100755
--- a/tools/testing/selftests/ntb/ntb_test.sh
+++ b/tools/testing/selftests/ntb/ntb_test.sh
@@ -305,7 +305,7 @@
echo "Running remote perf test $WITH DMA"
write_file "" $REMOTE_PERF/run
echo -n " "
- read_file $LOCAL_PERF/run
+ read_file $REMOTE_PERF/run
echo " Passed"
_modprobe -r ntb_perf
@@ -326,6 +326,10 @@
link_test $LOCAL_TOOL $REMOTE_TOOL
link_test $REMOTE_TOOL $LOCAL_TOOL
+ #Ensure the link is up on both sides before continuing
+ write_file Y $LOCAL_TOOL/link_event
+ write_file Y $REMOTE_TOOL/link_event
+
for PEER_TRANS in $(ls $LOCAL_TOOL/peer_trans*); do
PT=$(basename $PEER_TRANS)
write_file $MW_SIZE $LOCAL_TOOL/$PT