Merge "msm: mdss: fix wb memory registration optimization"
diff --git a/Documentation/arm/msm/msm_ipc_logging.txt b/Documentation/arm/msm/msm_ipc_logging.txt
index cb330b0..9d42200 100644
--- a/Documentation/arm/msm/msm_ipc_logging.txt
+++ b/Documentation/arm/msm/msm_ipc_logging.txt
@@ -66,34 +66,71 @@
Log Space
----------
-Each context will have an associated log space, which is dynamically
-allocated from the kernel memory-space. The log space is organized as a
-list of kernel memory pages. Each page contains header information which
-is used to differentiate the log kernel page from the other kernel pages.
+Each context (Figure 1) has an associated log space, which is dynamically
+allocated from the kernel memory-space. The log space is organized as a list of
+1 or more kernel memory pages. Each page (Figure 2) contains header information
+which is used to differentiate the log kernel page from the other kernel pages.
- 0 ---------------------------------
- | magic_no = 0x52784425 |
- ---------------------------------
- | nmagic_no = 0xAD87BBDA |
- ---------------------------------
- | log_id |
- ---------------------------------
- | page_num |
- ---------------------------------
- | read_offset | write_offset |
- ---------------------------------
- | next/prev page |
- ---------------------------------
- | |
- | Data |
- | . |
- | . |
- | . |
- | |
- --------------------------------- PAGE_SIZE - 1
-This approach will support extracting the logs either from the memory dumps
-or from the live targets using DEBUGFS.
+ 0 ---------------------------------
+ | magic_no = 0x25874452 |
+ ---------------------------------
+ | nmagic_no = 0x52784425 |
+ ---------------------------------
+ | version |
+ ---------------------------------
+ | user_version |
+ ---------------------------------
+ | log_id |
+ ---------------------------------
+ | header_size |
+ ---------------------------------
+ | |
+ | |
+ | name [20 chars] |
+ | |
+ | |
+ ---------------------------------
+ | run-time data structures |
+ ---------------------------------
+ Figure 1 - Log Context Structure
+
+
+ 31 0
+ 0 ---------------------------------
+ | magic_no = 0x52784425 |
+ ---------------------------------
+ | nmagic_no = 0xAD87BBDA |
+ ---------------------------------
+ |1| page_num |
+ ---------------------------------
+ | read_offset | write_offset |
+ ---------------------------------
+ | log_id |
+ ---------------------------------
+ | start_time low word |
+ | start_time high word |
+ ---------------------------------
+ | end_time low word |
+ | end_time high word |
+ ---------------------------------
+ | context offset |
+ ---------------------------------
+ | run-time data structures |
+ . . . . .
+ ---------------------------------
+ | |
+ | Log Data |
+ . . .
+ . . .
+ | |
+ --------------------------------- PAGE_SIZE - 1
+ Figure 2 - Log Page Structure
+
+In addition to extracting logs at runtime through DebugFS, IPC Logging has been
+designed to allow extraction of logs from a memory dump. The magic numbers,
+timestamps, and context offset are all added to support the memory-dump
+extraction use case.
Design
======
@@ -149,6 +186,7 @@
*
* @max_num_pages: Number of pages of logging space required (max. 10)
* @mod_name : Name of the directory entry under DEBUGFS
+ * @user_version : Version number of user-defined message formats
*
* returns reference to context on success, NULL on failure
*/
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 8078abf..8c91db0 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -19,7 +19,7 @@
- qcom,max-current : maximum current that the LED can sustain in mA
- linux,name : name of the led that is used in led framework
-Optional properties for each child node, WLED, Flash, MPP and RGB:
+Optional properties for each child node, WLED, Flash, MPP, RGB and KPDBL:
- qcom,in-order-command-processing : specify if user space requests leds in order
WLED is primarily used as display backlight. Display subsystem uses
@@ -121,6 +121,7 @@
for vph_pwr.
- qcom,row-src-en: specify to enable row source
- qcom,always-on: specify if the module has to be always on
+- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 8eb9b64..2cb528c 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -27,6 +27,10 @@
should be performed during boot up.
- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
using a smaller count for this buffer will reduce the memory usage.
+=======
+- qcom,is-pronto-v3: boolean flag to determine the pronto hardware version
+in use. subsequently correct workqueue will be used by DXE engine to push frames
+in TX data path.
- qcom,wcnss-pm : <Core rail LDO#, PA rail LDO#, XO settling time,
RPM power collapse enabled, standalone power collapse enabled>
Power manager related parameter for LDO configuration.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index b7413cb..87fb3e9 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -360,6 +360,8 @@
[stack:1001] = the stack of the thread with tid 1001
[vdso] = the "virtual dynamic shared object",
the kernel system call handler
+ [anon:<name>] = an anonymous mapping that has been
+ named by userspace
or if empty, the mapping is anonymous.
@@ -409,6 +411,7 @@
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 374 kB
+Name: name from userspace
The first of these lines shows the same information as is displayed for the
mapping in /proc/PID/maps. The remaining lines show the size of the mapping
@@ -424,6 +427,9 @@
"Swap" shows how much would-be-anonymous memory is also used, but out on
swap.
+The "Name" field will only be present on a mapping that has been named by
+userspace, and will show the name passed in by userspace.
+
This file is only present if the CONFIG_MMU kernel configuration option is
enabled.
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 2d4a6db..4af5946 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -22,6 +22,13 @@
min_pmtu - INTEGER
default 552 - minimum discovered Path MTU
+fwmark_reflect - BOOLEAN
+ Controls the fwmark of kernel-generated IPv4 reply packets that are not
+ associated with a socket for example, TCP RSTs or ICMP echo replies).
+ If unset, these packets have a fwmark of zero. If set, they have the
+ fwmark of the packet they are replying to.
+ Default: 0
+
route/max_size - INTEGER
Maximum number of routes allowed in the kernel. Increase
this when using large numbers of interfaces and/or routes.
@@ -1048,6 +1055,13 @@
2 NDP packets are sent to userspace, where a userspace proxy
can be implemented
+fwmark_reflect - BOOLEAN
+ Controls the fwmark of kernel-generated IPv6 reply packets that are not
+ associated with a socket for example, TCP RSTs or ICMPv6 echo replies).
+ If unset, these packets have a fwmark of zero. If set, they have the
+ fwmark of the packet they are replying to.
+ Default: 0
+
conf/interface/*:
Change special settings per interface.
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index a227802..dc5324b 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -38,42 +38,6 @@
qcom,cci-master = <0>;
};
- qcom,camera@90 {
- compatible = "qcom,mt9m114";
- reg = <0x90 0x0>;
- qcom,slave-id = <0x90 0x0 0x2481>;
- qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <1>;
- qcom,mount-angle = <90>;
- qcom,sensor-name = "mt9m114";
- cam_vdig-supply = <&pm8226_l5>;
- cam_vana-supply = <&pm8226_l19>;
- cam_vio-supply = <&pm8226_lvs1>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
- qcom,cam-vreg-type = <0 1 0>;
- qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
- qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
- qcom,cam-vreg-op-mode = <200000 0 80000>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 26 0>,
- <&msmgpio 28 0>,
- <&msmgpio 35 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET",
- "CAM_STANDBY";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x3>;
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- };
qcom,camera@0 {
cell-index = <0>;
compatible = "qcom,camera";
@@ -139,4 +103,159 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@6f {
+ compatible = "qcom,ov8825";
+ reg = <0x6f>;
+ qcom,slave-id = <0x6c 0x300a 0x8825>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,mount-angle = <180>;
+ qcom,sensor-name = "ov8825";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1f>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@20 {
+ compatible = "qcom,imx135";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0016 0x0135>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator1>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "imx135";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,sensor-type = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@6d {
+ compatible = "qcom,ov9724";
+ reg = <0x6d>;
+ qcom,slave-id = <0x20 0x0 0x9724>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "ov9724";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 6b305a5..1631bd6 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -98,4 +98,80 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@6f {
+ compatible = "qcom,ov8825";
+ reg = <0x6f>;
+ qcom,slave-id = <0x6c 0x300a 0x8825>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "ov8825";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1f>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6d {
+ compatible = "qcom,ov9724";
+ reg = <0x6d>;
+ qcom,slave-id = <0x20 0x0 0x9724>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "ov9724";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 36 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 4115959..317633b 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -104,6 +104,45 @@
qcom,cam-power-seq-delay = <1 1 5 5 10>;
};
+ qcom,camera@6f {
+ compatible = "qcom,ov8825";
+ reg = <0x6f>;
+ qcom,slave-id = <0x6c 0x300a 0x8825>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "ov8825";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1f>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
actuator1: qcom,actuator@18 {
cell-index = <4>;
reg = <0x18>;
@@ -360,4 +399,129 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@6c {
+ compatible = "qcom,ov12830";
+ reg = <0x6c>;
+ qcom,slave-id = <0x20 0x300a 0xc830>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,actuator-src = <&actuator1>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "skuf_ov12830_p12v01c";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <120000 0 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>,
+ <&msmgpio 22 0>,
+ <&msmgpio 34 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-af-pwdm = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY",
+ "CAM_VDIG",
+ "CAM_AF_PWDM";
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1f>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6d {
+ compatible = "qcom,ov9724";
+ reg = <0x6d>;
+ qcom,slave-id = <0x20 0x0 0x9724>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "ov9724";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@6a {
+ compatible = "ovti,ov5648";
+ reg = <0x6a>;
+ qcom,slave-id = <0x6c 0x300a 0x5648>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,eeprom-src = <&eeprom2>;
+ qcom,mount-angle = <270>;
+ qcom,sensor-name = "skuf_ov5648_p5v23c";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-type = <0 1 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 35 0>,
+ <&msmgpio 21 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET",
+ "CAM_STANDBY",
+ "CAM_VDIG";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 06abbd8..4be97d8 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -138,21 +138,31 @@
qcom,row-id = <0>;
qcom,row-src-en;
qcom,always-on;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
};
qcom,kpdbl2 {
label = "kpdbl";
- linux,name = "kpdbl-lut-2";
- qcom,mode = "lpg";
+ linux,name = "kpdbl-pwm-2";
+ qcom,mode = "pwm";
qcom,pwm-channel = <9>;
qcom,pwm-us = <1000>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
qcom,id = <7>;
qcom,max-current = <20>;
qcom,row-id = <1>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
qcom,kpdbl3 {
@@ -165,6 +175,13 @@
qcom,max-current = <20>;
qcom,row-id = <2>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
qcom,kpdbl4 {
@@ -177,6 +194,13 @@
qcom,max-current = <20>;
qcom,row-id = <3>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
};
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 99dbec8..495117f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -214,7 +214,7 @@
interrupts = <0 44 0>;
vdd-supply = <&gdsc_venus>;
qcom,hfi = "venus";
- qcom,has-ocmem;
+ qcom,ocmem-size = <524288>; /* 512 * 1024*/
qcom,max-hw-load = <1216800>; /* 3840 x 2160 @ 30 + 1080p @ 30*/
};
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b618cd4..89df8ed 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -2578,7 +2578,8 @@
}
#endif
- bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux");
+ bam_ipc_log_txt = ipc_log_context_create(BAM_IPC_LOG_PAGES, "bam_dmux",
+ 0);
if (!bam_ipc_log_txt) {
pr_err("%s : unable to create IPC Logging Context", __func__);
}
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index b3bf07c..82d7785 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -48,10 +48,12 @@
*
* @max_num_pages: Number of pages of logging space required (max. 10)
* @mod_name : Name of the directory entry under DEBUGFS
+ * @user_version : Version number of user-defined message formats
*
* returns context id on success, NULL on failure
*/
-void *ipc_log_context_create(int max_num_pages, const char *modname);
+void *ipc_log_context_create(int max_num_pages, const char *modname,
+ uint16_t user_version);
/*
* msg_encode_start: Start encoding a log message
@@ -208,7 +210,7 @@
#else
static inline void *ipc_log_context_create(int max_num_pages,
- const char *modname)
+ const char *modname, uint16_t user_version)
{ return NULL; }
static inline void msg_encode_start(struct encode_context *ectxt,
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
index bad861d..e76c95c 100644
--- a/arch/arm/mach-msm/ipc_logging.c
+++ b/arch/arm/mach-msm/ipc_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -31,9 +31,11 @@
#include "ipc_logging.h"
+#define LOG_PAGE_DATA_SIZE sizeof(((struct ipc_log_page *)0)->data)
+#define LOG_PAGE_FLAG (1 << 31)
+
static LIST_HEAD(ipc_log_context_list);
-DEFINE_RWLOCK(ipc_log_context_list_lock);
-static atomic_t next_log_id = ATOMIC_INIT(0);
+static DEFINE_RWLOCK(context_list_lock_lha1);
static void *get_deserialization_func(struct ipc_log_context *ilctxt,
int type);
@@ -50,6 +52,68 @@
return pg;
}
+/**
+ * is_nd_read_empty - Returns true if no data is available to read in log
+ *
+ * @ilctxt: logging context
+ * @returns: > 1 if context is empty; 0 if not empty; <0 for failure
+ *
+ * This is for the debugfs read pointer which allows for a non-destructive read.
+ * There may still be data in the log, but it may have already been read.
+ */
+static int is_nd_read_empty(struct ipc_log_context *ilctxt)
+{
+ if (!ilctxt)
+ return -EINVAL;
+
+ return ((ilctxt->nd_read_page == ilctxt->write_page) &&
+ (ilctxt->nd_read_page->hdr.nd_read_offset ==
+ ilctxt->write_page->hdr.write_offset));
+}
+
+/**
+ * is_read_empty - Returns true if no data is available in log
+ *
+ * @ilctxt: logging context
+ * @returns: > 1 if context is empty; 0 if not empty; <0 for failure
+ *
+ * This is for the actual log contents. If it is empty, then there
+ * is no data at all in the log.
+ */
+static int is_read_empty(struct ipc_log_context *ilctxt)
+{
+ if (!ilctxt)
+ return -EINVAL;
+
+ return ((ilctxt->read_page == ilctxt->write_page) &&
+ (ilctxt->read_page->hdr.read_offset ==
+ ilctxt->write_page->hdr.write_offset));
+}
+
+/**
+ * is_nd_read_equal_read - Return true if the non-destructive read is equal to
+ * the destructive read
+ *
+ * @ilctxt: logging context
+ * @returns: true if nd read is equal to read; false otherwise
+ */
+static bool is_nd_read_equal_read(struct ipc_log_context *ilctxt)
+{
+ uint16_t read_offset;
+ uint16_t nd_read_offset;
+
+ if (ilctxt->nd_read_page == ilctxt->read_page) {
+ read_offset = ilctxt->read_page->hdr.read_offset;
+ nd_read_offset = ilctxt->nd_read_page->hdr.nd_read_offset;
+
+ if (read_offset == nd_read_offset)
+ return true;
+ }
+
+ return false;
+}
+
+
static struct ipc_log_page *get_next_page(struct ipc_log_context *ilctxt,
struct ipc_log_page *cur_pg)
{
@@ -69,64 +133,150 @@
return pg;
}
-/* If data == NULL, drop the log of size data_size*/
+/**
+ * ipc_log_read - do non-destructive read of the log
+ *
+ * @ilctxt: Logging context
+ * @data: Data pointer to receive the data
+ * @data_size: Number of bytes to read (must be <= bytes available in log)
+ *
+ * This read will update a runtime read pointer, but will not affect the actual
+ * contents of the log which allows for reading the logs continuously while
+ * debugging and if the system crashes, then the full logs can still be
+ * extracted.
+ */
static void ipc_log_read(struct ipc_log_context *ilctxt,
void *data, int data_size)
{
int bytes_to_read;
- bytes_to_read = MIN(((PAGE_SIZE - sizeof(struct ipc_log_page_header))
- - ilctxt->read_page->hdr.read_offset),
+ bytes_to_read = MIN(LOG_PAGE_DATA_SIZE
+ - ilctxt->nd_read_page->hdr.nd_read_offset,
+ data_size);
+
+ memcpy(data, (ilctxt->nd_read_page->data +
+ ilctxt->nd_read_page->hdr.nd_read_offset), bytes_to_read);
+
+ if (bytes_to_read != data_size) {
+ /* not enough space, wrap read to next page */
+ ilctxt->nd_read_page->hdr.nd_read_offset = 0;
+ ilctxt->nd_read_page = get_next_page(ilctxt,
+ ilctxt->nd_read_page);
+ BUG_ON(ilctxt->nd_read_page == NULL);
+
+ memcpy((data + bytes_to_read),
+ (ilctxt->nd_read_page->data +
+ ilctxt->nd_read_page->hdr.nd_read_offset),
+ (data_size - bytes_to_read));
+ bytes_to_read = (data_size - bytes_to_read);
+ }
+ ilctxt->nd_read_page->hdr.nd_read_offset += bytes_to_read;
+}
+
+/**
+ * ipc_log_drop - do destructive read of the log
+ *
+ * @ilctxt: Logging context
+ * @data: Data pointer to receive the data (or NULL)
+ * @data_size: Number of bytes to read (must be <= bytes available in log)
+ */
+static void ipc_log_drop(struct ipc_log_context *ilctxt, void *data,
+ int data_size)
+{
+ int bytes_to_read;
+ bool push_nd_read;
+
+ bytes_to_read = MIN(LOG_PAGE_DATA_SIZE
+ - ilctxt->read_page->hdr.read_offset,
data_size);
if (data)
memcpy(data, (ilctxt->read_page->data +
ilctxt->read_page->hdr.read_offset), bytes_to_read);
+
if (bytes_to_read != data_size) {
- ilctxt->read_page->hdr.read_offset = 0xFFFF;
- ilctxt->read_page = get_next_page(ilctxt, ilctxt->read_page);
+ /* not enough space, wrap read to next page */
+ push_nd_read = is_nd_read_equal_read(ilctxt);
+
ilctxt->read_page->hdr.read_offset = 0;
+ if (push_nd_read) {
+ ilctxt->read_page->hdr.nd_read_offset = 0;
+ ilctxt->read_page = get_next_page(ilctxt,
+ ilctxt->read_page);
+ BUG_ON(ilctxt->read_page == NULL);
+ ilctxt->nd_read_page = ilctxt->read_page;
+ } else {
+ ilctxt->read_page = get_next_page(ilctxt,
+ ilctxt->read_page);
+ BUG_ON(ilctxt->read_page == NULL);
+ }
+
if (data)
memcpy((data + bytes_to_read),
- (ilctxt->read_page->data +
+ (ilctxt->read_page->data +
ilctxt->read_page->hdr.read_offset),
- (data_size - bytes_to_read));
+ (data_size - bytes_to_read));
+
bytes_to_read = (data_size - bytes_to_read);
}
+
+ /* update non-destructive read pointer if necessary */
+ push_nd_read = is_nd_read_equal_read(ilctxt);
ilctxt->read_page->hdr.read_offset += bytes_to_read;
ilctxt->write_avail += data_size;
+
+ if (push_nd_read)
+ ilctxt->nd_read_page->hdr.nd_read_offset += bytes_to_read;
}
-/*
- * Reads a message.
+/**
+ * msg_read - Reads a message.
*
- * If a message is read successfully, then the the message context
+ * If a message is read successfully, then the message context
* will be set to:
* .hdr message header .size and .type values
* .offset beginning of message data
*
- * @ectxt Message context and if NULL, drops the message.
+ * @ilctxt Logging context
+ * @ectxt Message context
*
- * @returns 0 - no message available
- * 1 - message read
+ * @returns 0 - no message available; >0 message size; <0 error
*/
-int msg_read(struct ipc_log_context *ilctxt,
+static int msg_read(struct ipc_log_context *ilctxt,
struct encode_context *ectxt)
{
struct tsv_header hdr;
+ if (!ectxt)
+ return -EINVAL;
+
+ if (is_nd_read_empty(ilctxt))
+ return 0;
+
ipc_log_read(ilctxt, &hdr, sizeof(hdr));
- if (ectxt) {
- ectxt->hdr.type = hdr.type;
- ectxt->hdr.size = hdr.size;
- ectxt->offset = sizeof(hdr);
- ipc_log_read(ilctxt, (ectxt->buff + ectxt->offset),
- (int)hdr.size);
- } else {
- ipc_log_read(ilctxt, NULL, (int)hdr.size);
- }
+ ectxt->hdr.type = hdr.type;
+ ectxt->hdr.size = hdr.size;
+ ectxt->offset = sizeof(hdr);
+ ipc_log_read(ilctxt, (ectxt->buff + ectxt->offset),
+ (int)hdr.size);
+
return sizeof(hdr) + (int)hdr.size;
}
+/**
+ * msg_drop - Drops a message.
+ *
+ * @ilctxt Logging context
+ */
+static void msg_drop(struct ipc_log_context *ilctxt)
+{
+ struct tsv_header hdr;
+
+ if (!is_read_empty(ilctxt)) {
+ ipc_log_drop(ilctxt, &hdr, sizeof(hdr));
+ ipc_log_drop(ilctxt, NULL, (int)hdr.size);
+ }
+}
+
/*
* Commits messages to the FIFO. If the FIFO is full, then enough
* messages are dropped to create space for the new message.
@@ -142,21 +292,28 @@
return;
}
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
- while (ilctxt->write_avail < ectxt->offset)
- msg_read(ilctxt, NULL);
+ read_lock_irqsave(&context_list_lock_lha1, flags);
+ spin_lock(&ilctxt->context_lock_lhb1);
+ while (ilctxt->write_avail <= ectxt->offset)
+ msg_drop(ilctxt);
- bytes_to_write = MIN(((PAGE_SIZE - sizeof(struct ipc_log_page_header))
- - ilctxt->write_page->hdr.write_offset),
+ bytes_to_write = MIN(LOG_PAGE_DATA_SIZE
+ - ilctxt->write_page->hdr.write_offset,
ectxt->offset);
memcpy((ilctxt->write_page->data +
ilctxt->write_page->hdr.write_offset),
ectxt->buff, bytes_to_write);
+
if (bytes_to_write != ectxt->offset) {
- ilctxt->write_page->hdr.write_offset = 0xFFFF;
+ uint64_t t_now = sched_clock();
+
+ ilctxt->write_page->hdr.write_offset += bytes_to_write;
+ ilctxt->write_page->hdr.end_time = t_now;
+
ilctxt->write_page = get_next_page(ilctxt, ilctxt->write_page);
+ BUG_ON(ilctxt->write_page == NULL);
ilctxt->write_page->hdr.write_offset = 0;
+ ilctxt->write_page->hdr.start_time = t_now;
memcpy((ilctxt->write_page->data +
ilctxt->write_page->hdr.write_offset),
(ectxt->buff + bytes_to_write),
@@ -166,8 +323,8 @@
ilctxt->write_page->hdr.write_offset += bytes_to_write;
ilctxt->write_avail -= ectxt->offset;
complete(&ilctxt->read_avail);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ spin_unlock(&ilctxt->context_lock_lhb1);
+ read_unlock_irqrestore(&context_list_lock_lha1, flags);
}
EXPORT_SYMBOL(ipc_log_write);
@@ -254,7 +411,7 @@
int tsv_timestamp_write(struct encode_context *ectxt)
{
int ret;
- unsigned long long t_now = sched_clock();
+ uint64_t t_now = sched_clock();
ret = tsv_write_header(ectxt, TSV_TYPE_TIMESTAMP, sizeof(t_now));
if (ret)
@@ -370,27 +527,27 @@
dctxt.output_format = OUTPUT_DEBUGFS;
dctxt.buff = buff;
dctxt.size = size;
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
+ read_lock_irqsave(&context_list_lock_lha1, flags);
+ spin_lock(&ilctxt->context_lock_lhb1);
while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
- !is_ilctxt_empty(ilctxt)) {
+ !is_nd_read_empty(ilctxt)) {
msg_read(ilctxt, &ectxt);
deserialize_func = get_deserialization_func(ilctxt,
ectxt.hdr.type);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ spin_unlock(&ilctxt->context_lock_lhb1);
+ read_unlock_irqrestore(&context_list_lock_lha1, flags);
if (deserialize_func)
deserialize_func(&ectxt, &dctxt);
else
pr_err("%s: unknown message 0x%x\n",
__func__, ectxt.hdr.type);
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
+ read_lock_irqsave(&context_list_lock_lha1, flags);
+ spin_lock(&ilctxt->context_lock_lhb1);
}
if ((size - dctxt.size) == 0)
- init_completion(&ilctxt->read_avail);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ INIT_COMPLETION(ilctxt->read_avail);
+ spin_unlock(&ilctxt->context_lock_lhb1);
+ read_unlock_irqrestore(&context_list_lock_lha1, flags);
return size - dctxt.size;
}
EXPORT_SYMBOL(ipc_log_extract);
@@ -436,7 +593,7 @@
struct decode_context *dctxt, const char *format)
{
struct tsv_header hdr;
- unsigned long long val;
+ uint64_t val;
unsigned long nanosec_rem;
tsv_read_header(ectxt, &hdr);
@@ -526,13 +683,13 @@
if (!df_info)
return -ENOSPC;
- read_lock_irqsave(&ipc_log_context_list_lock, flags);
- spin_lock(&ilctxt->ipc_log_context_lock);
+ read_lock_irqsave(&context_list_lock_lha1, flags);
+ spin_lock(&ilctxt->context_lock_lhb1);
df_info->type = type;
df_info->dfunc = dfunc;
list_add_tail(&df_info->list, &ilctxt->dfunc_info_list);
- spin_unlock(&ilctxt->ipc_log_context_lock);
- read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ spin_unlock(&ilctxt->context_lock_lhb1);
+ read_unlock_irqrestore(&context_list_lock_lha1, flags);
return 0;
}
EXPORT_SYMBOL(add_deserialization_func);
@@ -552,12 +709,22 @@
return NULL;
}
+/**
+ * ipc_log_context_create: Create a debug log context
+ * Should not be called from atomic context
+ *
+ * @max_num_pages: Number of pages of logging space required (max. 10)
+ * @mod_name : Name of the directory entry under DEBUGFS
+ * @user_version : Version number of user-defined message formats
+ *
+ * returns context id on success, NULL on failure
+ */
void *ipc_log_context_create(int max_num_pages,
- const char *mod_name)
+ const char *mod_name, uint16_t user_version)
{
struct ipc_log_context *ctxt;
struct ipc_log_page *pg = NULL;
- int page_cnt, local_log_id;
+ int page_cnt;
unsigned long flags;
ctxt = kzalloc(sizeof(struct ipc_log_context), GFP_KERNEL);
@@ -566,41 +733,50 @@
return 0;
}
- local_log_id = atomic_add_return(1, &next_log_id);
init_completion(&ctxt->read_avail);
INIT_LIST_HEAD(&ctxt->page_list);
INIT_LIST_HEAD(&ctxt->dfunc_info_list);
- spin_lock_init(&ctxt->ipc_log_context_lock);
+ spin_lock_init(&ctxt->context_lock_lhb1);
for (page_cnt = 0; page_cnt < max_num_pages; page_cnt++) {
pg = kzalloc(sizeof(struct ipc_log_page), GFP_KERNEL);
if (!pg) {
pr_err("%s: cannot create ipc_log_page\n", __func__);
goto release_ipc_log_context;
}
+ pg->hdr.log_id = (uint64_t)(uintptr_t)ctxt;
+ pg->hdr.page_num = LOG_PAGE_FLAG | page_cnt;
+ pg->hdr.ctx_offset = (int64_t)((uint64_t)(uintptr_t)ctxt -
+ (uint64_t)(uintptr_t)&pg->hdr);
+
+ /* set magic last to signal that page init is complete */
pg->hdr.magic = IPC_LOGGING_MAGIC_NUM;
pg->hdr.nmagic = ~(IPC_LOGGING_MAGIC_NUM);
- pg->hdr.log_id = (uint32_t)local_log_id;
- pg->hdr.page_num = page_cnt;
- pg->hdr.read_offset = 0xFFFF;
- pg->hdr.write_offset = 0xFFFF;
- spin_lock_irqsave(&ctxt->ipc_log_context_lock, flags);
+
+ spin_lock_irqsave(&ctxt->context_lock_lhb1, flags);
list_add_tail(&pg->hdr.list, &ctxt->page_list);
- spin_unlock_irqrestore(&ctxt->ipc_log_context_lock, flags);
+ spin_unlock_irqrestore(&ctxt->context_lock_lhb1, flags);
}
+
+ ctxt->log_id = (uint64_t)(uintptr_t)ctxt;
+ ctxt->version = IPC_LOG_VERSION;
+ strlcpy(ctxt->name, mod_name, IPC_LOG_MAX_CONTEXT_NAME_LEN);
+ ctxt->user_version = user_version;
ctxt->first_page = get_first_page(ctxt);
ctxt->last_page = pg;
ctxt->write_page = ctxt->first_page;
ctxt->read_page = ctxt->first_page;
- ctxt->write_page->hdr.write_offset = 0;
- ctxt->read_page->hdr.read_offset = 0;
- ctxt->write_avail = max_num_pages * (PAGE_SIZE -
- sizeof(struct ipc_log_page_header));
-
+ ctxt->nd_read_page = ctxt->first_page;
+ ctxt->write_avail = max_num_pages * LOG_PAGE_DATA_SIZE;
+ ctxt->header_size = sizeof(struct ipc_log_page_header);
create_ctx_debugfs(ctxt, mod_name);
- write_lock_irqsave(&ipc_log_context_list_lock, flags);
+ /* set magic last to signal context init is complete */
+ ctxt->magic = IPC_LOG_CONTEXT_MAGIC_NUM;
+ ctxt->nmagic = ~(IPC_LOG_CONTEXT_MAGIC_NUM);
+
+ write_lock_irqsave(&context_list_lock_lha1, flags);
list_add_tail(&ctxt->list, &ipc_log_context_list);
- write_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ write_unlock_irqrestore(&context_list_lock_lha1, flags);
return (void *)ctxt;
release_ipc_log_context:
@@ -634,9 +810,9 @@
kfree(pg);
}
- write_lock_irqsave(&ipc_log_context_list_lock, flags);
+ write_lock_irqsave(&context_list_lock_lha1, flags);
list_del(&ilctxt->list);
- write_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+ write_unlock_irqrestore(&context_list_lock_lha1, flags);
kfree(ilctxt);
return 0;
diff --git a/arch/arm/mach-msm/ipc_logging.h b/arch/arm/mach-msm/ipc_logging.h
index ddf194b..a765a83 100644
--- a/arch/arm/mach-msm/ipc_logging.h
+++ b/arch/arm/mach-msm/ipc_logging.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -15,32 +15,109 @@
#include <mach/msm_ipc_logging.h>
+#define IPC_LOG_VERSION 0x0001
+#define IPC_LOG_MAX_CONTEXT_NAME_LEN 20
+
+/**
+ * struct ipc_log_page_header - Individual log page header
+ *
+ * @magic: Magic number (used for log extraction)
+ * @nmagic: Inverse of magic number (used for log extraction)
+ * @page_num: Index of page (0.. N - 1) (note top bit is always set)
+ * @read_offset: Read offset in page
+ * @write_offset: Write offset in page (or 0xFFFF if full)
+ * @log_id: ID of logging context that owns this page
+ * @start_time: Scheduler clock for first write time in page
+ * @end_time: Scheduler clock for last write time in page
+ * @ctx_offset: Signed offset from page to the logging context. Used to
+ * optimize ram-dump extraction.
+ *
+ * @list: Linked list of pages that make up a log
+ * @nd_read_offset: Non-destructive read offset used for debugfs
+ *
+ * The first part of the structure defines data that is used to extract the
+ * logs from a memory dump and elements in this section should not be changed
+ * or re-ordered. New local data structures can be added to the end of the
+ * structure since they will be ignored by the extraction tool.
+ */
struct ipc_log_page_header {
uint32_t magic;
- uint32_t nmagic; /* inverse of magic number */
- uint32_t log_id; /* owner of log */
+ uint32_t nmagic;
uint32_t page_num;
uint16_t read_offset;
uint16_t write_offset;
+ uint64_t log_id;
+ uint64_t start_time;
+ uint64_t end_time;
+ int64_t ctx_offset;
+
+ /* add local data structures after this point */
struct list_head list;
+ uint16_t nd_read_offset;
};
+/**
+ * struct ipc_log_page - Individual log page
+ *
+ * @hdr: Log page header
+ * @data: Log data
+ *
+ * Each log consists of 1 to N log pages. Data size is adjusted to always fit
+ * the structure into a single kernel page.
+ */
struct ipc_log_page {
struct ipc_log_page_header hdr;
char data[PAGE_SIZE - sizeof(struct ipc_log_page_header)];
};
+/**
+ * struct ipc_log_context - main logging context
+ *
+ * @magic: Magic number (used for log extraction)
+ * @nmagic: Inverse of magic number (used for log extraction)
+ * @version: IPC Logging version of log format
+ * @user_version: Version number for user-defined messages
+ * @header_size: Size of the log header which is used to determine the offset
+ * of ipc_log_page::data
+ * @log_id: Log ID (assigned when log is created)
+ * @name: Name of the log used to uniquely identify the log during extraction
+ *
+ * @list: List of log contexts (struct ipc_log_context)
+ * @page_list: List of log pages (struct ipc_log_page)
+ * @first_page: First page in list of logging pages
+ * @last_page: Last page in list of logging pages
+ * @write_page: Current write page
+ * @read_page: Current read page (for internal reads)
+ * @nd_read_page: Current debugfs extraction page (non-destructive)
+ *
+ * @write_avail: Number of bytes available to write in all pages
+ * @dent: Debugfs node for run-time log extraction
+ * @dfunc_info_list: List of deserialization functions
+ * @context_lock_lhb1: Lock for entire structure
+ * @read_avail: Completed when new data is added to the log
+ */
struct ipc_log_context {
+ uint32_t magic;
+ uint32_t nmagic;
+ uint32_t version;
+ uint16_t user_version;
+ uint16_t header_size;
+ uint64_t log_id;
+ char name[IPC_LOG_MAX_CONTEXT_NAME_LEN];
+
+ /* add local data structures after this point */
struct list_head list;
struct list_head page_list;
struct ipc_log_page *first_page;
struct ipc_log_page *last_page;
struct ipc_log_page *write_page;
struct ipc_log_page *read_page;
+ struct ipc_log_page *nd_read_page;
+
uint32_t write_avail;
struct dentry *dent;
struct list_head dfunc_info_list;
- spinlock_t ipc_log_context_lock;
+ spinlock_t context_lock_lhb1;
struct completion read_avail;
};
@@ -62,27 +139,13 @@
OUTPUT_DEBUGFS,
};
+#define IPC_LOG_CONTEXT_MAGIC_NUM 0x25874452
#define IPC_LOGGING_MAGIC_NUM 0x52784425
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define IS_MSG_TYPE(x) (((x) > TSV_TYPE_MSG_START) && \
((x) < TSV_TYPE_MSG_END))
#define MAX_MSG_DECODED_SIZE (MAX_MSG_SIZE*4)
-extern rwlock_t ipc_log_context_list_lock;
-
-extern int msg_read(struct ipc_log_context *ilctxt,
- struct encode_context *ectxt);
-
-static inline int is_ilctxt_empty(struct ipc_log_context *ilctxt)
-{
- if (!ilctxt)
- return -EINVAL;
-
- return ((ilctxt->read_page == ilctxt->write_page) &&
- (ilctxt->read_page->hdr.read_offset ==
- ilctxt->write_page->hdr.write_offset));
-}
-
#if (defined(CONFIG_DEBUG_FS))
void check_and_create_debugfs(void);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6bb4011..fa95469 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -3330,7 +3330,7 @@
msm_ipc_router_debug_mask |= SMEM_LOG;
ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
- "ipc_router");
+ "ipc_router", 0);
if (!ipc_rtr_log_ctxt)
pr_err("%s: Unable to create IPC logging for IPC RTR",
__func__);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 5aa6c93..77943e3 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -626,13 +626,13 @@
{
ipc_req_resp_log_txt =
ipc_log_context_create(REQ_RESP_IPC_LOG_PAGES,
- "ipc_rtr_req_resp");
+ "ipc_rtr_req_resp", 0);
if (!ipc_req_resp_log_txt) {
pr_err("%s: Unable to create IPC logging for Req/Resp",
__func__);
}
ipc_ind_log_txt =
- ipc_log_context_create(IND_IPC_LOG_PAGES, "ipc_rtr_ind");
+ ipc_log_context_create(IND_IPC_LOG_PAGES, "ipc_rtr_ind", 0);
if (!ipc_ind_log_txt) {
pr_err("%s: Unable to create IPC logging for Indications",
__func__);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 32f9b3b..33fae19 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -3340,13 +3340,13 @@
if (registered)
return 0;
- smd_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smd");
+ smd_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smd", 0);
if (!smd_log_ctx) {
pr_err("%s: unable to create SMD logging context\n", __func__);
msm_smd_debug_mask = 0;
}
- smsm_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smsm");
+ smsm_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smsm", 0);
if (!smsm_log_ctx) {
pr_err("%s: unable to create SMSM logging context\n", __func__);
msm_smd_debug_mask = 0;
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 1c44f9a..c6001a6 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2014, 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
@@ -101,8 +101,6 @@
SMD_PKT_STATUS = 1U << 0,
SMD_PKT_READ = 1U << 1,
SMD_PKT_WRITE = 1U << 2,
- SMD_PKT_READ_DUMP_BUFFER = 1U << 3,
- SMD_PKT_WRITE_DUMP_BUFFER = 1U << 4,
SMD_PKT_POLL = 1U << 5,
};
@@ -116,18 +114,6 @@
ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: "x); \
} while (0)
-#define SMD_PKT_LOG_BUF(buf, cnt) \
-do { \
- char log_buf[128]; \
- int i; \
- if (smd_pkt_ilctxt) { \
- i = cnt < 16 ? cnt : 16; \
- hex_dump_to_buffer(buf, i, 16, 1, log_buf, \
- sizeof(log_buf), false); \
- ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: %s", log_buf); \
- } \
-} while (0)
-
#define D_STATUS(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
@@ -149,24 +135,6 @@
SMD_PKT_LOG_STRING(x); \
} while (0)
-#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_smd_pkt_debug_mask & SMD_PKT_READ_DUMP_BUFFER) \
- print_hex_dump(KERN_INFO, prestr, \
- DUMP_PREFIX_NONE, 16, 1, \
- buf, cnt, 1); \
- SMD_PKT_LOG_BUF(buf, cnt); \
-} while (0)
-
-#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE_DUMP_BUFFER) \
- print_hex_dump(KERN_INFO, prestr, \
- DUMP_PREFIX_NONE, 16, 1, \
- buf, cnt, 1); \
- SMD_PKT_LOG_BUF(buf, cnt); \
-} while (0)
-
#define D_POLL(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
@@ -184,8 +152,6 @@
#define D_STATUS(x...) do {} while (0)
#define D_READ(x...) do {} while (0)
#define D_WRITE(x...) do {} while (0)
-#define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
#define D_POLL(x...) do {} while (0)
#define E_SMD_PKT_SSR(x) do {} while (0)
#endif
@@ -432,7 +398,6 @@
return notify_reset(smd_pkt_devp);
}
} while (pkt_size != bytes_read);
- D_READ_DUMP_BUFFER("Read: ", (bytes_read > 16 ? 16 : bytes_read), buf);
mutex_unlock(&smd_pkt_devp->rx_lock);
mutex_lock(&smd_pkt_devp->ch_lock);
@@ -540,8 +505,6 @@
} while (bytes_written != count);
smd_write_end(smd_pkt_devp->ch);
mutex_unlock(&smd_pkt_devp->tx_lock);
- D_WRITE_DUMP_BUFFER("Write: ",
- (bytes_written > 16 ? 16 : bytes_written), buf);
D_WRITE("Finished %s on smd_pkt_dev id:%d %d bytes\n",
__func__, smd_pkt_devp->i, count);
@@ -1123,7 +1086,7 @@
INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
smd_pkt_ilctxt = ipc_log_context_create(SMD_PKT_IPC_LOG_PAGE_CNT,
- "smd_pkt");
+ "smd_pkt", 0);
D_STATUS("SMD Packet Port Driver Initialized.\n");
return 0;
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index e1c5162..6c3232c 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_tty.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -740,7 +740,7 @@
static void smd_tty_log_init(void)
{
smd_tty_log_ctx = ipc_log_context_create(SMD_TTY_LOG_PAGES,
- "smd_tty");
+ "smd_tty", 0);
if (!smd_tty_log_ctx)
pr_err("%s: Unable to create IPC log", __func__);
}
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 3c7cbeb..032f8b1 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -1370,7 +1370,7 @@
registered = true;
- smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem");
+ smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem", 0);
if (!smem_ipc_log_ctx) {
pr_err("%s: unable to create logging context\n", __func__);
msm_smem_debug_mask = 0;
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 5574eae..22eb799 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/smp2p.c
*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -1829,7 +1829,7 @@
in_list[i].smem_edge_in = NULL;
}
- log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smp2p");
+ log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smp2p", 0);
if (!log_ctx)
SMP2P_ERR("%s: unable to create log context\n", __func__);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ed1ee8d..a4bd163 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -358,6 +358,10 @@
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_ABS) },
+ /* assumption: MT_.._X & MT_.._Y are in the same long */
+ .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
+ BIT_MASK(ABS_MT_POSITION_X) |
+ BIT_MASK(ABS_MT_POSITION_Y) },
},
{ },
};
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index ce559ca..059e488 100755
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -434,6 +434,7 @@
* @always_on - always on row
* @lut_params - lut parameters to be used by pwm driver
* @duty_cycles - duty cycles for lut
+ * @pwm_mode - pwm mode in use
*/
struct kpdbl_config_data {
struct pwm_config_data *pwm_cfg;
@@ -443,6 +444,7 @@
bool always_on;
struct pwm_duty_cycles *duty_cycles;
struct lut_params lut_params;
+ u8 pwm_mode;
};
/**
@@ -1835,7 +1837,7 @@
struct spmi_device *spmi_dev,
const char *name)
{
- int rc, start_idx, idx_len;
+ int rc, start_idx, idx_len, lut_max_size;
if (pwm_cfg->pwm_channel != -1) {
pwm_cfg->pwm_dev =
@@ -1857,14 +1859,18 @@
idx_len =
pwm_cfg->duty_cycles->num_duty_pcts;
- if (idx_len >= PWM_LUT_MAX_SIZE &&
- start_idx) {
+ if (strnstr(name, "kpdbl", sizeof("kpdbl")))
+ lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
+ else
+ lut_max_size = PWM_LUT_MAX_SIZE;
+
+ if (idx_len >= lut_max_size && start_idx) {
dev_err(&spmi_dev->dev,
"Wrong LUT size or index\n");
return -EINVAL;
}
- if ((start_idx + idx_len) >
- PWM_LUT_MAX_SIZE) {
+
+ if ((start_idx + idx_len) > lut_max_size) {
dev_err(&spmi_dev->dev,
"Exceed LUT limit\n");
return -EINVAL;
@@ -1914,6 +1920,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pwm_us\n");
@@ -1966,6 +1975,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause lo\n");
@@ -2018,6 +2030,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause hi\n");
@@ -2070,6 +2085,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for start idx\n");
@@ -2123,6 +2141,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for ramp step\n");
@@ -2175,6 +2196,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for lut flags\n");
@@ -2231,6 +2255,10 @@
pwm_cfg = led->rgb_cfg->pwm_cfg;
max_duty_pcts = PWM_LUT_MAX_SIZE;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ max_duty_pcts = PWM_GPLED_LUT_MAX_SIZE;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for duty pcts\n");
@@ -2300,12 +2328,17 @@
pwm_cfg->blinking = true;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = LPG_MODE;
+ else if (led->id == QPNP_ID_KPDBL)
+ led->kpdbl_cfg->pwm_mode = LPG_MODE;
pwm_cfg->mode = LPG_MODE;
} else {
pwm_cfg->blinking = false;
pwm_cfg->mode = pwm_cfg->default_mode;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = pwm_cfg->default_mode;
+ else if (led->id == QPNP_ID_KPDBL)
+ led->kpdbl_cfg->pwm_mode =
+ pwm_cfg->default_mode;
}
pwm_free(pwm_cfg->pwm_dev);
qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
@@ -2320,6 +2353,11 @@
if (rc < 0)
dev_err(&led->spmi_dev->dev,
"MPP set brightness failed (%d)\n", rc);
+ } else if (led->id == QPNP_ID_KPDBL) {
+ rc = qpnp_kpdbl_set(led);
+ if (rc < 0)
+ dev_err(&led->spmi_dev->dev,
+ "KPDBL set brightness failed (%d)\n", rc);
}
}
mutex_unlock(&led->lock);
@@ -2349,6 +2387,9 @@
case QPNP_ID_RGB_BLUE:
led_blink(led, led->rgb_cfg->pwm_cfg);
break;
+ case QPNP_ID_KPDBL:
+ led_blink(led, led->kpdbl_cfg->pwm_cfg);
+ break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED id type for blink\n");
return -EINVAL;
@@ -3003,9 +3044,10 @@
struct device_node *node)
{
struct property *prop;
- int rc, i;
+ int rc, i, lut_max_size;
u32 val;
u8 *temp_cfg;
+ const char *led_label;
rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
if (!rc)
@@ -3049,9 +3091,22 @@
goto bad_lpg_params;
}
+ rc = of_property_read_string(node, "label", &led_label);
+
+ if (rc < 0) {
+ dev_err(&spmi_dev->dev,
+ "Failure reading label, rc = %d\n", rc);
+ return rc;
+ }
+
+ if (strcmp(led_label, "kpdbl") == 0)
+ lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
+ else
+ lut_max_size = PWM_LUT_MAX_SIZE;
+
pwm_cfg->duty_cycles->duty_pcts =
devm_kzalloc(&spmi_dev->dev,
- sizeof(int) * PWM_LUT_MAX_SIZE,
+ sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->duty_cycles->duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -3062,7 +3117,7 @@
pwm_cfg->old_duty_pcts =
devm_kzalloc(&spmi_dev->dev,
- sizeof(int) * PWM_LUT_MAX_SIZE,
+ sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->old_duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -3570,6 +3625,29 @@
if (rc)
goto fail_id_check;
}
+ } else if (led->id == QPNP_ID_KPDBL) {
+ if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &pwm_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
+ if (led->kpdbl_cfg->pwm_cfg->use_blink) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &blink_attr_group);
+ if (rc)
+ goto fail_id_check;
+
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ } else if (led->kpdbl_cfg->pwm_cfg->mode == LPG_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
}
/* configure default state */
@@ -3659,6 +3737,20 @@
sysfs_remove_group(&led_array[i].cdev.dev->\
kobj, &lpg_attr_group);
break;
+ case QPNP_ID_KPDBL:
+ if (led_array[i].kpdbl_cfg->pwm_cfg->mode == PWM_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &pwm_attr_group);
+ if (led_array[i].kpdbl_cfg->pwm_cfg->use_blink) {
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &lpg_attr_group);
+ } else if (led_array[i].kpdbl_cfg->pwm_cfg->mode
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &lpg_attr_group);
+ break;
default:
dev_err(&led_array[i].spmi_dev->dev,
"Invalid LED(%d)\n",
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index c5da40b..56775d7 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -4,7 +4,7 @@
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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 Lesser General Public License
@@ -2117,6 +2117,11 @@
struct dmxdev_events_queue *events;
int ret;
+ if (!dmxdevfilter) {
+ pr_err("%s: NULL demux filter object!\n", __func__);
+ return -ENODEV;
+ }
+
if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) {
src = &dmxdevfilter->buffer;
events = &dmxdevfilter->events;
@@ -2170,10 +2175,18 @@
int required_space)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
- struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
- struct dmxdev_events_queue *events = &dmxdevfilter->events;
+ struct dvb_ringbuffer *src;
+ struct dmxdev_events_queue *events;
int ret;
+ if (!dmxdevfilter) {
+ pr_err("%s: NULL demux filter object!\n", __func__);
+ return -ENODEV;
+ }
+
+ src = &dmxdevfilter->buffer;
+ events = &dmxdevfilter->events;
+
do {
ret = 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 65387ba..bd22e73 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,7 +5,7 @@
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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 Lesser General Public License
@@ -2574,7 +2574,7 @@
feed->state = DMX_STATE_FREE;
feed->filter->state = DMX_STATE_FREE;
-
+ ts_feed->priv = NULL;
dvb_demux_feed_del(feed);
feed->pid = 0xffff;
@@ -2836,6 +2836,7 @@
f->next = f->next->next;
}
+ filter->priv = NULL;
dvbdmxfilter->state = DMX_STATE_FREE;
spin_unlock_irq(&dvbdmx->lock);
mutex_unlock(&dvbdmx->mutex);
@@ -2975,7 +2976,7 @@
dvbdmxfeed->buffer = NULL;
#endif
dvbdmxfeed->state = DMX_STATE_FREE;
-
+ feed->priv = NULL;
dvb_demux_feed_del(dvbdmxfeed);
dvbdmxfeed->pid = 0xffff;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index c92b29d..f20a99a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1198,14 +1198,19 @@
msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28);
msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C);
/* Clear IRQ Status*/
- msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
- msm_camera_io_w(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
- init_completion(&vfe_dev->halt_complete);
- msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
+ msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
+ msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
+ msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
if (blocking) {
+ init_completion(&vfe_dev->halt_complete);
+ /* Halt AXI Bus Bridge */
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->halt_complete, msecs_to_jiffies(500));
+ } else {
+ /* Halt AXI Bus Bridge */
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
}
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index b4196e9..aa0d88b 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -298,10 +298,8 @@
return buff->map_info.phy_addr;
QUEUE_BUFF_ERROR2:
- ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
- cpp_dev->domain_num, 0);
-QUEUE_BUFF_ERROR1:
ion_free(cpp_dev->client, buff->map_info.ion_handle);
+QUEUE_BUFF_ERROR1:
buff->map_info.ion_handle = NULL;
kzfree(buff);
@@ -1675,14 +1673,6 @@
kfree(k_stream_buff_info.buffer_info);
kfree(u_stream_buff_info);
if (cpp_dev->stream_cnt == 0) {
- rc = msm_isp_update_bandwidth(ISP_CPP, 981345600,
- 1066680000);
- if (rc < 0) {
- pr_err("Bandwidth Set Failed!\n");
- msm_isp_update_bandwidth(ISP_CPP, 0, 0);
- mutex_unlock(&cpp_dev->mutex);
- return -EINVAL;
- }
cpp_dev->state = CPP_STATE_ACTIVE;
msm_cpp_clear_timer(cpp_dev);
msm_cpp_clean_queue(cpp_dev);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 22498a4..270fb38 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -217,8 +217,7 @@
cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
delay = i2c_cmd->delay;
data[i++] = CCI_I2C_WRITE_CMD;
- if (i2c_cmd->reg_addr)
- reg_addr = i2c_cmd->reg_addr;
+ reg_addr = i2c_cmd->reg_addr;
/* either byte or word addr */
if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
data[i++] = reg_addr;
@@ -227,22 +226,21 @@
data[i++] = reg_addr & 0x00FF;
}
/* max of 10 data bytes */
- do {
- if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
- data[i++] = i2c_cmd->reg_data;
- reg_addr++;
- } else {
- if ((i + 1) <= 10) {
- data[i++] = (i2c_cmd->reg_data &
- 0xFF00) >> 8; /* MSB */
- data[i++] = i2c_cmd->reg_data &
- 0x00FF; /* LSB */
- reg_addr += 2;
- } else
- break;
- }
- i2c_cmd++;
- } while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10));
+ if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+ data[i++] = i2c_cmd->reg_data;
+ reg_addr++;
+ } else {
+ if ((i + 1) <= 10) {
+ data[i++] = (i2c_cmd->reg_data &
+ 0xFF00) >> 8; /* MSB */
+ data[i++] = i2c_cmd->reg_data &
+ 0x00FF; /* LSB */
+ reg_addr += 2;
+ } else
+ break;
+ }
+ i2c_cmd++;
+ --cmd_size;
data[0] |= ((i-1) << 4);
len = ((i-1)/4) + 1;
rc = msm_cci_validate_queue(cci_dev, len, master, queue);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index df21c26..ba17820 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1552,7 +1552,7 @@
dprintk(VIDC_WARN,
"Failed to scale DDR bus. Performance might be impacted\n");
}
- if (core->resources.has_ocmem) {
+ if (core->resources.ocmem_size) {
if (msm_comm_scale_bus(core, inst->session_type,
OCMEM_MEM))
dprintk(VIDC_WARN,
@@ -1560,52 +1560,6 @@
}
}
-static inline unsigned long get_ocmem_requirement(u32 height, u32 width)
-{
- int num_mbs = 0;
- num_mbs = GET_NUM_MBS(height, width);
- /*TODO: This should be changes once the numbers are
- * available from firmware*/
- return 512 * 1024;
-}
-
-static int msm_comm_unset_ocmem(struct msm_vidc_core *core)
-{
- int rc = 0;
- struct hfi_device *hdev;
-
- if (!core || !core->device) {
- dprintk(VIDC_ERR, "%s invalid parameters", __func__);
- return -EINVAL;
- }
- hdev = core->device;
-
- if (core->state == VIDC_CORE_INVALID) {
- dprintk(VIDC_ERR,
- "Core is in bad state. Cannot unset ocmem\n");
- return -EIO;
- }
-
- init_completion(
- &core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
-
- rc = call_hfi_op(hdev, unset_ocmem, hdev->hfi_device_data);
- if (rc) {
- dprintk(VIDC_INFO, "Failed to unset OCMEM on driver\n");
- goto release_ocmem_failed;
- }
- rc = wait_for_completion_timeout(
- &core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
- msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
- if (!rc) {
- dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
- __func__, SYS_MSG_INDEX(RELEASE_RESOURCE_DONE));
- rc = -EIO;
- }
-release_ocmem_failed:
- return rc;
-}
-
static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core = inst->core;
@@ -1899,10 +1853,8 @@
struct msm_vidc_inst *inst)
{
int rc = 0;
- u32 ocmem_sz = 0;
struct hfi_device *hdev;
int num_mbs_per_sec = 0;
- int height, width;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1939,31 +1891,7 @@
inst, inst->state);
goto exit;
}
- if (inst->core->resources.has_ocmem) {
- height = max(inst->prop.height[CAPTURE_PORT],
- inst->prop.height[OUTPUT_PORT]);
- width = max(inst->prop.width[CAPTURE_PORT],
- inst->prop.width[OUTPUT_PORT]);
- ocmem_sz = get_ocmem_requirement(
- height, width);
- rc = msm_comm_scale_bus(inst->core, inst->session_type,
- OCMEM_MEM);
- if (!rc) {
- mutex_lock(&inst->core->lock);
- rc = call_hfi_op(hdev, alloc_ocmem,
- hdev->hfi_device_data,
- ocmem_sz);
- mutex_unlock(&inst->core->lock);
- if (rc) {
- dprintk(VIDC_WARN,
- "Failed to allocate OCMEM. Performance will be impacted\n");
- msm_comm_unvote_buses(inst->core, OCMEM_MEM);
- }
- } else {
- dprintk(VIDC_WARN,
- "Failed to vote for OCMEM BW. Performance will be impacted\n");
- }
- }
+
rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -3711,12 +3639,6 @@
if (list_empty(&core->instances) &&
core->state != VIDC_CORE_UNINIT) {
if (core->state > VIDC_CORE_INIT) {
- if (core->resources.has_ocmem) {
- if (core->state != VIDC_CORE_INVALID)
- msm_comm_unset_ocmem(core);
- call_hfi_op(hdev, free_ocmem,
- hdev->hfi_device_data);
- }
dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
rc = call_hfi_op(hdev, core_release,
hdev->hfi_device_data);
@@ -3732,7 +3654,7 @@
call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
dprintk(VIDC_DBG, "Firmware unloaded\n");
- if (core->resources.has_ocmem)
+ if (core->resources.ocmem_size)
msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
else
msm_comm_unvote_buses(core, DDR_MEM);
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 ecfff85..10f3797 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -348,7 +348,7 @@
goto err_mem_alloc;
}
for (i = 0; i < num_bus_pdata; i++) {
- if (!res->has_ocmem &&
+ if (!res->ocmem_size &&
(!strcmp(bus_pdata_config_vector[i].name,
"qcom,enc-ocmem-ab-ib")
|| !strcmp(bus_pdata_config_vector[i].name,
@@ -567,9 +567,11 @@
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res->irq = kres ? kres->start : -1;
- res->has_ocmem = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-ocmem");
-
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,ocmem-size", &res->ocmem_size);
+ if (rc) {
+ dprintk(VIDC_INFO, "Failed to read ocmem size: %d\n", rc);
+ }
rc = msm_vidc_load_freq_table(res);
if (rc) {
dprintk(VIDC_ERR, "Failed to load freq table: %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 e75b410..87d4d42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -74,7 +74,7 @@
struct msm_bus_scale_pdata *bus_pdata;
struct iommu_set iommu_group_set;
struct buffer_usage_set buffer_usage_set;
- bool has_ocmem;
+ uint32_t ocmem_size;
uint32_t max_load;
struct platform_device *pdev;
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
old mode 100755
new mode 100644
index 52bbe12..4bc534c
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1186,14 +1186,6 @@
return 0;
}
-static int q6_hfi_unset_ocmem(void *dev)
-{
- (void)dev;
-
- /* Q6 does not support ocmem */
- return -EINVAL;
-}
-
static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
u32 buffer_type, int *domain, int *partition)
{
@@ -1374,7 +1366,6 @@
hdev->session_flush = q6_hfi_session_flush;
hdev->session_set_property = q6_hfi_session_set_property;
hdev->session_get_property = q6_hfi_session_get_property;
- hdev->unset_ocmem = q6_hfi_unset_ocmem;
hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
old mode 100755
new mode 100644
index fb27511..f5587fc
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -904,115 +904,59 @@
return rc;
}
-static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, int locked)
-{
- struct vidc_resource_hdr rhdr;
- struct venus_hfi_device *device = dev;
- int rc = 0;
- if (!device || !ocmem) {
- dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
- device, ocmem);
- return -EINVAL;
- }
- rhdr.resource_id = VIDC_RESOURCE_OCMEM;
- rhdr.resource_handle = (u32) &device->resources.ocmem;
- rhdr.size = ocmem->len;
- rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
- goto ocmem_set_failed;
- }
- dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
- ocmem->addr, ocmem->len);
-ocmem_set_failed:
- return rc;
-}
+static DECLARE_COMPLETION(pc_prep_done);
+static DECLARE_COMPLETION(release_resources_done);
-static int venus_hfi_unset_ocmem(void *dev)
-{
- struct vidc_resource_hdr rhdr;
- struct venus_hfi_device *device = dev;
- int rc = 0;
-
- if (!device) {
- dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
- __func__, device);
- rc = -EINVAL;
- goto ocmem_unset_failed;
- }
- if (!device->resources.ocmem.buf) {
- dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set",
- __func__);
- rc = -EINVAL;
- goto ocmem_unset_failed;
- }
- rhdr.resource_id = VIDC_RESOURCE_OCMEM;
- rhdr.resource_handle = (u32) &device->resources.ocmem;
- rc = venus_hfi_core_release_resource(device, &rhdr);
- if (rc)
- dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
-ocmem_unset_failed:
- return rc;
-}
-
-static int __alloc_ocmem(void *dev, unsigned long size, int locked)
+static int __alloc_ocmem(struct venus_hfi_device *device)
{
int rc = 0;
struct ocmem_buf *ocmem_buffer;
- struct venus_hfi_device *device = dev;
+ unsigned long size;
- if (!device || !size) {
- dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
- __func__, device, size);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
return -EINVAL;
}
+
+ size = device->res->ocmem_size;
+ if (!size)
+ return rc;
+
ocmem_buffer = device->resources.ocmem.buf;
- if (!ocmem_buffer ||
- ocmem_buffer->len < size) {
+ if (!ocmem_buffer || ocmem_buffer->len < size) {
ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
if (IS_ERR_OR_NULL(ocmem_buffer)) {
dprintk(VIDC_ERR,
- "ocmem_allocate_nb failed: %d\n",
- (u32) ocmem_buffer);
+ "ocmem_allocate failed: %lu\n",
+ (unsigned long)ocmem_buffer);
rc = -ENOMEM;
+ device->resources.ocmem.buf = NULL;
goto ocmem_alloc_failed;
}
device->resources.ocmem.buf = ocmem_buffer;
- rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
- goto ocmem_set_failed;
- }
- device->ocmem_size = size;
- } else
+ } else {
dprintk(VIDC_DBG,
"OCMEM is enough. reqd: %lu, available: %lu\n",
size, ocmem_buffer->len);
-
- return rc;
-ocmem_set_failed:
- ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
- device->resources.ocmem.buf = NULL;
+ }
ocmem_alloc_failed:
return rc;
}
-static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
+static int __free_ocmem(struct venus_hfi_device *device)
{
- return __alloc_ocmem(dev, size, true);
-}
-
-static int venus_hfi_free_ocmem(void *dev)
-{
- struct venus_hfi_device *device = dev;
int rc = 0;
- if (!device) {
- dprintk(VIDC_ERR, "%s invalid device handle %p",
- __func__, device);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
return -EINVAL;
}
+ if (!device->res->ocmem_size)
+ return rc;
+
if (device->resources.ocmem.buf) {
rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
if (rc)
@@ -1022,6 +966,147 @@
return rc;
}
+static int __set_ocmem(struct venus_hfi_device *device, bool locked)
+{
+ struct vidc_resource_hdr rhdr;
+ int rc = 0;
+ struct on_chip_mem *ocmem;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ ocmem = &device->resources.ocmem;
+ if (!ocmem->buf) {
+ dprintk(VIDC_ERR, "Invalid params, ocmem_buffer: 0x%p\n",
+ ocmem->buf);
+ return -EINVAL;
+ }
+
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ /*
+ * This handle is just used as a cookie and not(cannot be)
+ * accessed by fw
+ */
+ rhdr.resource_handle = (u32)(unsigned long)ocmem;
+ rhdr.size = ocmem->buf->len;
+ rc = venus_hfi_core_set_resource(device, &rhdr, ocmem->buf, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
+ goto ocmem_set_failed;
+ }
+ dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
+ ocmem->buf->addr, ocmem->buf->len);
+ocmem_set_failed:
+ return rc;
+}
+
+static int __unset_ocmem(struct venus_hfi_device *device)
+{
+ struct vidc_resource_hdr rhdr;
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ rc = -EINVAL;
+ goto ocmem_unset_failed;
+ }
+
+ if (!device->resources.ocmem.buf) {
+ dprintk(VIDC_INFO,
+ "%s Trying to unset OCMEM which is not allocated\n",
+ __func__);
+ rc = -EINVAL;
+ goto ocmem_unset_failed;
+ }
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ /*
+ * This handle is just used as a cookie and not(cannot be)
+ * accessed by fw
+ */
+ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
+ rc = venus_hfi_core_release_resource(device, &rhdr);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
+ocmem_unset_failed:
+ return rc;
+}
+
+static int __alloc_set_ocmem(struct venus_hfi_device *device, bool locked)
+{
+ int rc = 0;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ if (!device->res->ocmem_size)
+ return rc;
+
+ rc = __alloc_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate ocmem: %d\n", rc);
+ goto ocmem_alloc_failed;
+ }
+ rc = __set_ocmem(device, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
+ goto ocmem_set_failed;
+ }
+ return rc;
+ocmem_set_failed:
+ __free_ocmem(device);
+ocmem_alloc_failed:
+ return rc;
+}
+
+static int __unset_free_ocmem(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ if (!device->res->ocmem_size)
+ return rc;
+
+ init_completion(&release_resources_done);
+ rc = __unset_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
+ goto ocmem_unset_failed;
+ }
+ rc = wait_for_completion_timeout(&release_resources_done,
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
+ rc);
+ rc = -EIO;
+ goto release_resources_failed;
+ }
+
+ rc = __free_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
+ goto ocmem_free_failed;
+ }
+ return rc;
+
+ocmem_free_failed:
+ __set_ocmem(device, true);
+release_resources_failed:
+ocmem_unset_failed:
+ return rc;
+}
+
static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
{
struct tzbsp_video_set_state_req cmd = {0};
@@ -1135,9 +1220,6 @@
--device->clk_cnt;
}
-static DECLARE_COMPLETION(pc_prep_done);
-static DECLARE_COMPLETION(release_resources_done);
-
static int venus_hfi_halt_axi(struct venus_hfi_device *device)
{
u32 reg;
@@ -1201,7 +1283,7 @@
dprintk(VIDC_ERR, "Failed to disable GDSC, %d", rc);
return rc;
}
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
else
venus_hfi_unvote_buses(device, DDR_MEM);
@@ -1221,7 +1303,7 @@
return -EINVAL;
}
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
rc = venus_hfi_scale_buses(device, DDR_MEM|OCMEM_MEM);
else
rc = venus_hfi_scale_buses(device, DDR_MEM);
@@ -1292,7 +1374,7 @@
* of alloc_ocmem
*/
WARN_ON(!mutex_is_locked(&device->write_lock));
- rc = __alloc_ocmem(device, device->ocmem_size, false);
+ rc = __alloc_set_ocmem(device, false);
if (rc) {
dprintk(VIDC_ERR, "Failed to allocate OCMEM");
goto err_alloc_ocmem;
@@ -1311,7 +1393,7 @@
err_enable_clk:
regulator_disable(device->gdsc);
err_enable_gdsc:
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
else
venus_hfi_unvote_buses(device, DDR_MEM);
@@ -1934,13 +2016,26 @@
dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
-
if (dev->hal_client) {
mutex_lock(&dev->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
if (rc) {
dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&dev->clk_pwr_lock);
+ return -EIO;
+ }
+ mutex_unlock(&dev->clk_pwr_lock);
+ rc = __unset_free_ocmem(dev);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to unset and free OCMEM in core release, rc : %d\n",
+ rc);
+ mutex_lock(&dev->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
mutex_unlock(&dev->clk_pwr_lock);
return -EIO;
}
@@ -1951,6 +2046,7 @@
dev->intr_status = 0;
mutex_unlock(&dev->clk_pwr_lock);
}
+
VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
dprintk(VIDC_INFO, "HAL exited\n");
@@ -2743,45 +2839,6 @@
return rc;
}
-static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device)
-{
- int rc = 0;
-
- if (!device) {
- dprintk(VIDC_ERR, "Invalid param: %p\n", device);
- return -EINVAL;
- }
-
- init_completion(&release_resources_done);
- rc = venus_hfi_unset_ocmem(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
- goto ocmem_unset_failed;
- }
- rc = wait_for_completion_timeout(&release_resources_done,
- msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
- if (!rc) {
- dprintk(VIDC_ERR,
- "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
- rc);
- rc = -EIO;
- goto release_resources_failed;
- }
-
- rc = venus_hfi_free_ocmem(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
- goto ocmem_free_failed;
- }
- return rc;
-
-ocmem_free_failed:
- venus_hfi_alloc_ocmem(device, device->ocmem_size);
-release_resources_failed:
-ocmem_unset_failed:
- return rc;
-}
-
static int venus_hfi_prepare_pc(struct venus_hfi_device *device)
{
int rc = 0;
@@ -2819,18 +2876,20 @@
}
mutex_unlock(&device->clk_pwr_lock);
- rc = venus_hfi_unset_free_ocmem(device);
+ rc = __unset_free_ocmem(device);
if (rc) {
dprintk(VIDC_ERR,
- "Failed to unset and free OCMEM for PC %d\n",
- rc);
+ "Failed to unset and free OCMEM for PC, rc : %d\n", rc);
return;
}
rc = venus_hfi_prepare_pc(device);
if (rc) {
- dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
- venus_hfi_alloc_ocmem(device, device->ocmem_size);
+ dprintk(VIDC_ERR, "Failed to prepare for PC, rc : %d\n", rc);
+ rc = __alloc_set_ocmem(device, true);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to re-allocate OCMEM. Performance will be impacted\n");
return;
}
@@ -2926,6 +2985,14 @@
dprintk(VIDC_DBG,
"Received HFI_MSG_SYS_RELEASE_RESOURCE\n");
complete(&release_resources_done);
+ } else if (rc == HFI_MSG_SYS_INIT_DONE) {
+ int ret = 0;
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_INIT_DONE\n");
+ ret = __alloc_set_ocmem(device, true);
+ if (ret)
+ dprintk(VIDC_WARN,
+ "Failed to allocate OCMEM. Performance will be impacted\n");
}
}
while (!venus_hfi_iface_dbgq_read(device, packet)) {
@@ -3058,7 +3125,7 @@
strlcpy(clock[VCODEC_AXI_CLK].name, "bus_clk",
sizeof(clock[VCODEC_AXI_CLK].name));
- if (res->has_ocmem) {
+ if (res->ocmem_size) {
strlcpy(clock[VCODEC_OCMEM_CLK].name, "mem_clk",
sizeof(clock[VCODEC_OCMEM_CLK].name));
}
@@ -3081,7 +3148,7 @@
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !res->ocmem_size)
continue;
cl = &device->resources.clock[i];
if (!cl->clk) {
@@ -3097,7 +3164,7 @@
if (i < VCODEC_MAX_CLKS) {
for (--i; i >= VCODEC_CLK; i--) {
- if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !res->ocmem_size)
continue;
cl = &device->resources.clock[i];
clk_put(cl->clk);
@@ -3116,7 +3183,7 @@
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
clk_put(device->resources.clock[i].clk);
}
@@ -3135,7 +3202,7 @@
WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
if (device->clk_state == ENABLED_PREPARED) {
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
usleep(100);
@@ -3154,7 +3221,7 @@
}
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
clk_unprepare(cl->clk);
@@ -3181,7 +3248,7 @@
return 0;
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
rc = clk_prepare_enable(cl->clk);
@@ -3329,7 +3396,7 @@
goto err_init_bus;
}
- if (device->res->has_ocmem) {
+ if (device->res->ocmem_size) {
bus_info->ocmem_handle[MSM_VIDC_ENCODER] =
msm_bus_scale_register_client(
&device->res->bus_pdata[BUS_IDX_ENC_OCMEM]);
@@ -3355,59 +3422,6 @@
return -EINVAL;
}
-static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
- unsigned long event, void *data)
-{
- struct ocmem_buf *buff = data;
- struct venus_hfi_device *device;
- struct venus_resources *resources;
- struct on_chip_mem *ocmem;
- int rc = NOTIFY_DONE;
- if (event == OCMEM_ALLOC_GROW) {
- ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
- if (!ocmem) {
- dprintk(VIDC_ERR, "Wrong handler passed\n");
- rc = NOTIFY_BAD;
- goto err_ocmem_notify;
- }
- resources = container_of(ocmem,
- struct venus_resources, ocmem);
- device = container_of(resources,
- struct venus_hfi_device, resources);
- if (venus_hfi_set_ocmem(device, buff, 1)) {
- dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
- goto err_ocmem_notify;
- }
- rc = NOTIFY_OK;
- }
-
-err_ocmem_notify:
- return rc;
-}
-
-static void venus_hfi_ocmem_init(struct venus_hfi_device *device)
-{
- struct on_chip_mem *ocmem;
-
- ocmem = &device->resources.ocmem;
- ocmem->vidc_ocmem_nb.notifier_call = venus_hfi_ocmem_notify_handler;
- ocmem->handle =
- ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
- if (IS_ERR_OR_NULL(ocmem->handle)) {
- dprintk(VIDC_WARN,
- "Failed to register OCMEM notifier. Performance might be impacted\n");
- ocmem->handle = NULL;
- }
-}
-
-static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device)
-{
- if (device->resources.ocmem.handle)
- ocmem_notifier_unregister(device->resources.ocmem.handle,
- &device->resources.ocmem.vidc_ocmem_nb);
-}
-
-
static int venus_hfi_init_resources(struct venus_hfi_device *device,
struct msm_vidc_platform_resources *res)
{
@@ -3445,9 +3459,6 @@
goto err_register_iommu_domain;
}
- if (res->has_ocmem)
- venus_hfi_ocmem_init(device);
-
return rc;
err_register_iommu_domain:
@@ -3461,8 +3472,6 @@
static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
{
- if (device->res->has_ocmem)
- venus_hfi_deinit_ocmem(device);
venus_hfi_deregister_iommu_domains(device);
venus_hfi_deinit_bus(device);
venus_hfi_deinit_clocks(device);
@@ -3660,10 +3669,6 @@
return -EINVAL;
}
- rc = venus_hfi_free_ocmem(device);
- if (rc)
- dprintk(VIDC_WARN, "%s - failed to free ocmem\n", __func__);
-
rc = venus_hfi_core_release(device);
if (rc) {
dprintk(VIDC_ERR, "%s - failed to release venus core rc = %d\n",
@@ -3929,9 +3934,6 @@
hdev->scale_clocks = venus_hfi_scale_clocks;
hdev->scale_bus = venus_hfi_scale_bus;
hdev->unvote_bus = venus_hfi_unvote_bus;
- hdev->unset_ocmem = venus_hfi_unset_ocmem;
- hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
- hdev->free_ocmem = venus_hfi_free_ocmem;
hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 9169355..05d7b6a 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -196,7 +196,6 @@
u32 device_id;
u32 clk_load;
u32 bus_load[MSM_VIDC_MAX_DEVICES];
- unsigned long ocmem_size;
enum clock_state clk_state;
bool power_enabled;
enum vidc_clocks clk_gating_level;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
old mode 100755
new mode 100644
index 8484bb2..6cc4dee
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1156,9 +1156,6 @@
enum session_type type, enum mem_type mtype);
int (*unvote_bus)(void *dev, enum session_type type,
enum mem_type mtype);
- int (*unset_ocmem)(void *dev);
- int (*alloc_ocmem)(void *dev, unsigned long size);
- int (*free_ocmem)(void *dev);
int (*iommu_get_domain_partition)(void *dev, u32 flags, u32 buffer_type,
int *domain_num, int *partition_num);
int (*load_fw)(void *dev);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index cfdaa58..3a93469 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -616,6 +616,25 @@
return ret;
}
+static int qseecom_perf_enable(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ ret = qsee_vote_for_clock(data, CLK_DFAB);
+ if (ret) {
+ pr_err("Failed to vote for DFAB clock with err %d\n", ret);
+ goto perf_enable_exit;
+ }
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ pr_err("Failed to vote for SFPB clock with err %d\n", ret);
+ goto perf_enable_exit;
+ }
+
+perf_enable_exit:
+ return ret;
+}
+
static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
void __user *argp)
{
@@ -631,10 +650,29 @@
pr_err("Invalid bandwidth mode (%d)\n", req_mode);
return ret;
}
- mutex_lock(&qsee_bw_mutex);
- ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
- mutex_unlock(&qsee_bw_mutex);
+ /*
+ * Register bus bandwidth needs if bus scaling feature is enabled;
+ * otherwise, qseecom enable/disable clocks for the client directly.
+ */
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ pr_debug("Bus scaling feature is NOT enabled\n");
+ pr_debug("request bandwidth mode %d for the client\n",
+ req_mode);
+ if (req_mode != INACTIVE) {
+ ret = qseecom_perf_enable(data);
+ if (ret)
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ } else {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+ }
return ret;
}
@@ -1294,15 +1332,9 @@
return ret;
}
} else {
- ret = qsee_vote_for_clock(data, CLK_DFAB);
+ ret = qseecom_perf_enable(data);
if (ret) {
- pr_err("Failed to vote for DFAB clock%d\n", ret);
- return ret;
- }
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret) {
- qsee_disable_clock_vote(data, CLK_DFAB);
- pr_err("Failed to vote for SFPB clock%d\n", ret);
+ pr_err("Failed to vote for clocks with err %d\n", ret);
goto exit;
}
}
@@ -1872,7 +1904,6 @@
ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
- kzfree(img_data);
ret = -EIO;
goto loadfw_err;
}
@@ -1882,7 +1913,6 @@
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_app_ireq),
&resp, sizeof(resp));
- kzfree(img_data);
if (ret) {
pr_err("scm_call to load failed : ret %d\n", ret);
ret = -EIO;
@@ -1910,6 +1940,7 @@
}
loadfw_err:
+ kzfree(img_data);
__qseecom_disable_clk_scale_down(data);
if (qseecom.support_bus_scaling) {
mutex_lock(&qsee_bw_mutex);
@@ -2288,6 +2319,7 @@
int ret = 0;
struct qseecom_send_cmd_req req = {0, 0, 0, 0};
struct qseecom_dev_handle *data;
+ bool perf_enabled = false;
if (handle == NULL) {
pr_err("Handle is not initialized\n");
@@ -2311,11 +2343,35 @@
return ret;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ return -EINVAL;
+ }
+ perf_enabled = true;
+ }
+
ret = __qseecom_send_cmd(data, &req);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
@@ -2344,16 +2400,10 @@
if (ret)
pr_err("Failed to scale bus (med) %d\n", ret);
} else {
- ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
+ ret = qseecom_perf_enable(handle->dev);
if (ret)
- pr_err("Failed to vote for DFAB clock%d\n",
- ret);
- ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
- if (ret) {
- pr_err("Failed to vote for SFPB clock%d\n",
- ret);
- qsee_disable_clock_vote(handle->dev, CLK_DFAB);
- }
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
}
} else {
if (!qseecom.support_bus_scaling) {
@@ -3420,6 +3470,7 @@
int ret = 0;
struct qseecom_dev_handle *data = file->private_data;
void __user *argp = (void __user *) arg;
+ bool perf_enabled = false;
if (!data) {
pr_err("Invalid/uninitialized device handle\n");
@@ -3493,11 +3544,33 @@
break;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3531,11 +3604,33 @@
break;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3665,12 +3760,9 @@
__qseecom_register_bus_bandwidth_needs(data, HIGH);
mutex_unlock(&qsee_bw_mutex);
} else {
- ret = qsee_vote_for_clock(data, CLK_DFAB);
+ ret = qseecom_perf_enable(data);
if (ret)
- pr_err("Fail to vote for DFAB clock%d\n", ret);
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret)
- pr_err("Fail to vote for SFPB clock%d\n", ret);
+ pr_err("Fail to vote for clocks %d\n", ret);
}
atomic_dec(&data->ioctl_count);
break;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index da62cb0..939379f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -616,8 +616,10 @@
(host->areq->cmd_flags & REQ_FUA))
return false;
+ mmc_host_clk_hold(host);
remainder = (host->ops->get_xfer_remain) ?
host->ops->get_xfer_remain(host) : -1;
+ mmc_host_clk_release(host);
return (remainder > 0);
}
@@ -642,6 +644,7 @@
mmc_hostname(host));
return -ENOTSUPP;
}
+ mmc_host_clk_hold(host);
err = host->ops->stop_request(host);
if (err) {
pr_err("%s: Call to host->ops->stop_request() failed (%d)\n",
@@ -676,6 +679,7 @@
goto out;
}
out:
+ mmc_host_clk_release(host);
return err;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index c066acd..9c65a63 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -236,6 +236,18 @@
cpu_relax();
iris_reg = readl_relaxed(iris_read_reg);
+ pr_info("wcnss: IRIS Reg: %08x\n", iris_reg);
+ if (iris_reg == PRONTO_IRIS_REG_CHIP_ID) {
+ pr_info("wcnss: IRIS Card not Preset\n");
+ auto_detect = WCNSS_XO_INVALID;
+ /* Reset iris read bit */
+ reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
+ /* Clear XO_MODE[b2:b1] bits.
+ Clear implies 19.2 MHz TCXO
+ */
+ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+ goto xo_configure;
+ }
auto_detect = xo_auto_detect(iris_reg);
/* Reset iris read bit */
@@ -258,6 +270,7 @@
*iris_xo_set = WCNSS_XO_48MHZ;
}
+xo_configure:
writel_relaxed(reg, pmu_conf_reg);
/* Reset IRIS */
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 90cf441..4a4a88c 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -1241,6 +1241,14 @@
}
EXPORT_SYMBOL(wcnss_get_wlan_config);
+int wcnss_is_hw_pronto_ver3(void)
+{
+ if (penv && penv->pdev)
+ return penv->wlan_config.is_pronto_v3;
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_is_hw_pronto_ver3);
+
int wcnss_device_ready(void)
{
if (penv && penv->pdev && penv->nv_downloaded &&
@@ -2316,10 +2324,14 @@
unsigned long wcnss_phys_addr;
int size = 0;
struct resource *res;
+ int is_pronto_v3;
int pil_retry = 0;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
"qcom,has-pronto-hw");
+ is_pronto_v3 = of_property_read_bool(pdev->dev.of_node,
+ "qcom,is-pronto-v3");
+
if (of_property_read_u32(pdev->dev.of_node,
"qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
@@ -2342,6 +2354,7 @@
}
penv->wcnss_hw_type = (has_pronto_hw) ? WCNSS_PRONTO_HW : WCNSS_RIVA_HW;
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
+ penv->wlan_config.is_pronto_v3 = is_pronto_v3;
if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index b4c88cd..85e8842 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1293,7 +1293,7 @@
/* Create IPC log context */
dev->ipc_slimbus_log = ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES,
- dev_name(dev->dev));
+ dev_name(dev->dev), 0);
if (!dev->ipc_slimbus_log)
dev_err(&pdev->dev, "error creating ipc_logging context\n");
else {
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index e36806f..ffcfe52 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1,6 +1,6 @@
/* drivers/tty/n_smux.c
*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -3905,7 +3905,7 @@
return ret;
}
- log_ctx = ipc_log_context_create(1, "smux");
+ log_ctx = ipc_log_context_create(1, "smux", 0);
if (!log_ctx) {
SMUX_ERR("%s: unable to create log context\n", __func__);
disable_ipc_logging = 1;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index ad1ecff..8545ce9 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3095,7 +3095,7 @@
int ret;
ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
- "msm_serial_hs");
+ "msm_serial_hs", 0);
if (!ipc_msm_hs_log_ctxt)
MSM_HS_WARN("%s: error creating logging context", __func__);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index b13e8e5..fe0b20f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1240,7 +1240,7 @@
* upon set config#1. Call set_alt for non-zero
* alternate setting.
*/
- if (!w_value && cdev->config) {
+ if (!w_value && cdev->config && !f->get_alt) {
value = 0;
break;
}
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index aee7b58..e58d33f 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -421,6 +421,8 @@
if (atomic_inc_return(&rndis->notify_count) != 1)
return;
+ if (!rndis->notify->driver_data)
+ return;
/* Send RNDIS RESPONSE_AVAILABLE notification; a
* USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
*
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 63a842d..7d6d448 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -493,6 +493,11 @@
c[1] = cmap->blue;
c[2] = cmap->red;
+ if (cmap->start > MDP_HIST_LUT_SIZE || cmap->len > MDP_HIST_LUT_SIZE ||
+ (cmap->start + cmap->len > MDP_HIST_LUT_SIZE)) {
+ pr_err("mdp_lut_hw_update invalid arguments\n");
+ return -EINVAL;
+ }
for (i = 0; i < cmap->len; i++) {
if (copy_from_user(&r, cmap->red++, sizeof(r)) ||
copy_from_user(&g, cmap->green++, sizeof(g)) ||
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index a25c2c7..8c5d771 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -953,7 +953,7 @@
PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
- if (dstW > src->roi.width || dstW > src->roi.height)
+ if (dstW > src->roi.width || dstH > src->roi.height)
ppp_load_up_lut();
if (mdp_blur)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index bf91a29..edde3e3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -44,6 +44,7 @@
#include <linux/file.h>
#include <linux/memory_alloc.h>
#include <linux/kthread.h>
+#include <linux/of_address.h>
#include <mach/board.h>
#include <mach/memory.h>
@@ -87,7 +88,10 @@
static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma);
+static int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd,
+ size_t size);
static void mdss_fb_release_fences(struct msm_fb_data_type *mfd);
static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
unsigned long val, void *data);
@@ -1070,31 +1074,258 @@
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
-/*
- * Custom Framebuffer mmap() function for MSM driver.
- * Differs from standard mmap() function by allowing for customized
- * page-protection.
+/* Set VM page protection */
+static inline void __mdss_fb_set_page_protection(struct vm_area_struct *vma,
+ struct msm_fb_data_type *mfd)
+{
+ if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+ vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+
+}
+
+static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd)
+{
+ mfd->fb_ion_client = msm_ion_client_create(-1 , "mdss_fb_iclient");
+ if (IS_ERR_OR_NULL(mfd->fb_ion_client)) {
+ pr_err("Err:client not created, val %d\n",
+ PTR_RET(mfd->fb_ion_client));
+ mfd->fb_ion_client = NULL;
+ return PTR_RET(mfd->fb_ion_client);
+ }
+ return 0;
+}
+
+void mdss_fb_free_fb_ion_memory(struct msm_fb_data_type *mfd)
+{
+ if (!mfd) {
+ pr_err("no mfd\n");
+ return;
+ }
+
+ if (!mfd->fbi->screen_base)
+ return;
+
+ if (!mfd->fb_ion_client || !mfd->fb_ion_handle) {
+ pr_err("invalid input parameters for fb%d\n", mfd->index);
+ return;
+ }
+
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_start = 0;
+
+ ion_unmap_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ mfd->fb_ion_handle = NULL;
+}
+
+int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size)
+{
+ unsigned long buf_size;
+ int rc;
+ void *vaddr;
+
+ if (!mfd) {
+ pr_err("Invalid input param - no mfd");
+ return -EINVAL;
+ }
+
+ if (!mfd->fb_ion_client) {
+ rc = mdss_fb_create_ion_client(mfd);
+ if (rc < 0) {
+ pr_err("fb ion client couldn't be created - %d\n", rc);
+ return rc;
+ }
+ }
+
+ pr_debug("size for mmap = %zu", fb_size);
+ mfd->fb_ion_handle = ion_alloc(mfd->fb_ion_client, fb_size, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(mfd->fb_ion_handle)) {
+ pr_err("unable to alloc fbmem from ion - %ld\n",
+ PTR_ERR(mfd->fb_ion_handle));
+ return PTR_ERR(mfd->fb_ion_handle);
+ }
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ rc = ion_map_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0, SZ_4K, 0,
+ &mfd->iova, &buf_size, 0, 0);
+ if (rc) {
+ pr_err("Cannot map fb_mem to IOMMU. rc=%d\n", rc);
+ goto fb_mmap_failed;
+ }
+ } else {
+ pr_err("No IOMMU Domain");
+ goto fb_mmap_failed;
+
+ }
+
+ vaddr = ion_map_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR_OR_NULL(vaddr)) {
+ pr_err("ION memory mapping failed - %ld\n", PTR_ERR(vaddr));
+ rc = PTR_ERR(vaddr);
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+ goto fb_mmap_failed;
+ }
+
+ pr_debug("alloc 0x%zuB vaddr = %p (%pa iova) for fb%d\n", fb_size,
+ vaddr, &mfd->iova, mfd->index);
+
+ mfd->fbi->screen_base = (char *) vaddr;
+ mfd->fbi->fix.smem_start = (unsigned int) mfd->iova;
+ mfd->fbi->fix.smem_len = fb_size;
+
+ return rc;
+
+fb_mmap_failed:
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ return rc;
+}
+
+/**
+ * mdss_fb_fbmem_ion_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function by
+ * allowing for customized page-protection and dynamically allocate framebuffer
+ * memory from system heap and map to iommu virtual address.
+ *
+ * Return: virtual address is returned through vma
*/
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ int rc = 0;
+ size_t req_size, fb_size;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+
+ if (!mfd || !mfd->pdev || !mfd->pdev->dev.of_node) {
+ pr_err("Invalid device node\n");
+ return -ENODEV;
+ }
+
+ req_size = vma->vm_end - vma->vm_start;
+ fb_size = mfd->fbi->fix.smem_len;
+ if (req_size > fb_size) {
+ pr_warn("requested map is greater than framebuffer");
+ return -EOVERFLOW;
+ }
+
+ if (!mfd->fbi->screen_base) {
+ rc = mdss_fb_alloc_fb_ion_memory(mfd, fb_size);
+ if (rc < 0) {
+ pr_err("fb mmap failed!!!!");
+ return rc;
+ }
+ }
+
+ table = ion_sg_table(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR(table)) {
+ pr_err("Unable to get sg_table from ion:%ld\n", PTR_ERR(table));
+ mfd->fbi->screen_base = NULL;
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("sg_list is NULL\n");
+ mfd->fbi->screen_base = NULL;
+ return -EINVAL;
+ }
+
+ page = sg_page(table->sgl);
+ if (page) {
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg->length;
+
+ page = sg_page(sg);
+
+ if (offset >= sg->length) {
+ offset -= sg->length;
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len = sg->length - offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+
+ __mdss_fb_set_page_protection(vma, mfd);
+
+ pr_debug("vma=%p, addr=%x len=%ld",
+ vma, (unsigned int)addr, len);
+ pr_cont("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+
+ io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ break;
+ }
+ } else {
+ pr_err("PAGE is null\n");
+ mdss_fb_free_fb_ion_memory(mfd);
+ return -ENOMEM;
+ }
+
+ return rc;
+}
+
+/*
+ * mdss_fb_physical_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function as
+ * map to framebuffer memory from the CMA memory which is allocated during
+ * bootup.
+ *
+ * Return: virtual address is returned through vma
+ */
+static int mdss_fb_physical_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
{
/* Get frame buffer memory range. */
unsigned long start = info->fix.smem_start;
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret = 0;
if (!start) {
- pr_warn("No framebuffer memory is allocated.\n");
+ pr_warn("No framebuffer memory is allocated\n");
return -ENOMEM;
}
- ret = mdss_fb_pan_idle(mfd);
- if (ret) {
- pr_err("Shutdown pending. Aborting operation\n");
- return ret;
- }
-
/* Set VM flags. */
start &= PAGE_MASK;
if ((vma->vm_end <= vma->vm_start) ||
@@ -1106,22 +1337,7 @@
return -EINVAL;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- /* Set VM page protection */
- if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
- vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
- vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
- vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO;
/* Remap the frame buffer I/O range */
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
@@ -1132,6 +1348,22 @@
return 0;
}
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int rc = 0;
+
+ if (!info->fix.smem_start && !mfd->fb_ion_handle)
+ rc = mdss_fb_fbmem_ion_mmap(info, vma);
+ else
+ rc = mdss_fb_physical_mmap(info, vma);
+
+ if (rc < 0)
+ pr_err("fb mmap failed with rc = %d", rc);
+
+ return rc;
+}
+
static struct fb_ops mdss_fb_ops = {
.owner = THIS_MODULE,
.fb_open = mdss_fb_open,
@@ -1141,48 +1373,66 @@
.fb_blank = mdss_fb_blank, /* blank display */
.fb_pan_display = mdss_fb_pan_display, /* pan display */
.fb_ioctl = mdss_fb_ioctl, /* perform fb specific ioctl */
+#ifdef CONFIG_COMPAT
+ .fb_compat_ioctl = mdss_fb_compat_ioctl,
+#endif
.fb_mmap = mdss_fb_mmap,
};
static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
{
void *virt = NULL;
- unsigned long phys = 0;
+ phys_addr_t phys = 0;
size_t size = 0;
struct platform_device *pdev = mfd->pdev;
+ int rc = 0;
+ struct device_node *fbmem_pnode = NULL;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
return -ENODEV;
}
- if (of_property_read_u32(pdev->dev.of_node,
- "qcom,memory-reservation-size",
- &size) || !size) {
+ fbmem_pnode = of_parse_phandle(pdev->dev.of_node,
+ "linux,contiguous-region", 0);
+ if (!fbmem_pnode) {
+ pr_debug("fbmem is not reserved for %s\n", pdev->name);
mfd->fbi->screen_base = NULL;
mfd->fbi->fix.smem_start = 0;
- mfd->fbi->fix.smem_len = 0;
return 0;
+ } else {
+ const u32 *addr;
+ u64 len;
+
+ addr = of_get_address(fbmem_pnode, 0, &len, NULL);
+ if (!addr) {
+ pr_err("fbmem size is not specified\n");
+ of_node_put(fbmem_pnode);
+ return -EINVAL;
+ }
+ size = (size_t)len;
+ of_node_put(fbmem_pnode);
}
- pr_info("%s frame buffer reserve_size=0x%x\n", __func__, size);
+ pr_debug("%s frame buffer reserve_size=0x%zx\n", __func__, size);
if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
mfd->fbi->var.yres_virtual))
pr_warn("reserve size is smaller than framebuffer size\n");
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ virt = dma_alloc_coherent(&pdev->dev, size, &phys, GFP_KERNEL);
if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
+ pr_err("unable to alloc fbmem size=%zx\n", size);
return -ENOMEM;
}
- phys = memory_pool_node_paddr(virt);
-
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ rc = msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
&mfd->iova);
- pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
+ if (rc)
+ pr_warn("Cannot map fb_mem %pa to IOMMU. rc=%d\n", &phys, rc);
+
+ pr_debug("alloc 0x%zxB @ (%pa phys) (0x%p virt) (%pa iova) for fb%d\n",
+ size, &phys, virt, &mfd->iova, mfd->index);
mfd->fbi->screen_base = virt;
mfd->fbi->fix.smem_start = phys;
@@ -1194,9 +1444,9 @@
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- if (mfd->mdp.fb_mem_alloc_fnc)
+ if (mfd->mdp.fb_mem_alloc_fnc) {
return mfd->mdp.fb_mem_alloc_fnc(mfd);
- else if (mfd->mdp.fb_mem_get_iommu_domain) {
+ } else if (mfd->mdp.fb_mem_get_iommu_domain) {
int dom = mfd->mdp.fb_mem_get_iommu_domain();
if (dom >= 0)
return mdss_fb_alloc_fbmem_iommu(mfd, dom);
@@ -1374,8 +1624,14 @@
var->hsync_len = panel_info->lcdc.h_pulse_width;
var->pixclock = panel_info->clk_rate / 1000;
- /* id field for fb app */
+ /*
+ * Populate smem length here for uspace to get the
+ * Framebuffer size when FBIO_FSCREENINFO ioctl is
+ * called.
+ */
+ fix->smem_len = PAGE_ALIGN(fix->line_length * var->yres) * mfd->fb_page;
+ /* id field for fb app */
id = (int *)&mfd->panel;
snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
@@ -1390,10 +1646,8 @@
mdss_fb_parse_dt(mfd);
- if (mdss_fb_alloc_fbmem(mfd)) {
- pr_err("unable to allocate framebuffer memory\n");
- return -ENOMEM;
- }
+ if (mdss_fb_alloc_fbmem(mfd))
+ pr_warn("unable to allocate fb memory in fb register\n");
mfd->op_enable = true;
@@ -1430,9 +1684,8 @@
return -EPERM;
}
- pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
- mfd->index, fbi->var.xres, fbi->var.yres,
- fbi->fix.smem_len);
+ pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,
+ fbi->var.xres, fbi->var.yres);
return 0;
}
@@ -1606,6 +1859,16 @@
mfd->disp_thread = NULL;
}
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, true);
+ if (ret)
+ pr_err("error fb%d release process %s pid=%d\n",
+ mfd->index, task->comm, pid);
+ }
+
+ if (mfd->fb_ion_handle)
+ mdss_fb_free_fb_ion_memory(mfd);
+
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
@@ -2181,6 +2444,8 @@
else
mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+ mfd->fbi->fix.smem_len = mfd->fbi->fix.line_length *
+ mfd->fbi->var.yres_virtual;
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 1ab0fb7..8e6be01 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -229,6 +229,8 @@
u32 dcm_state;
struct list_head proc_list;
u32 wait_for_kickoff;
+ struct ion_client *fb_ion_client;
+ struct ion_handle *fb_ion_handle;
};
static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f286de5..cff668d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1731,7 +1731,7 @@
return;
if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
- mdp5_data->borderfill_enable) {
+ mdp5_data->borderfill_enable) {
mfd->mdp.kickoff_fnc(mfd, NULL);
return;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index fbc187a..a87b0ab 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -565,6 +565,7 @@
{
struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_wb_data *node = NULL;
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret;
if (!wb) {
@@ -572,6 +573,11 @@
return -ENODEV;
}
+ if (!ctl) {
+ pr_err("unable to dequeue, ctl is not initialized\n");
+ return -ENODEV;
+ }
+
ret = wait_event_interruptible(wb->wait_q, is_buffer_ready(wb));
if (ret) {
pr_err("failed to get dequeued buffer\n");
@@ -581,6 +587,7 @@
mutex_lock(&wb->lock);
if (wb->state == WB_STOPING) {
pr_debug("wfd stopped\n");
+ mdss_mdp_display_wait4comp(ctl);
wb->state = WB_STOP;
ret = -ENOBUFS;
} else if (!list_empty(&wb->busy_queue)) {
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 83b20fc..6b23a96 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -164,16 +164,20 @@
* ext4_journal_callback_del: delete a registered callback
* @handle: active journal transaction handle on which callback was registered
* @jce: registered journal callback entry to unregister
+ * Return true if object was sucessfully removed
*/
-static inline void ext4_journal_callback_del(handle_t *handle,
+static inline bool ext4_journal_callback_try_del(handle_t *handle,
struct ext4_journal_cb_entry *jce)
{
+ bool deleted;
struct ext4_sb_info *sbi =
EXT4_SB(handle->h_transaction->t_journal->j_private);
spin_lock(&sbi->s_md_lock);
+ deleted = !list_empty(&jce->jce_list);
list_del_init(&jce->jce_list);
spin_unlock(&sbi->s_md_lock);
+ return deleted;
}
int
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 99ab428..1372135 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4435,11 +4435,11 @@
node = rb_prev(new_node);
if (node) {
entry = rb_entry(node, struct ext4_free_data, efd_node);
- if (can_merge(entry, new_entry)) {
+ if (can_merge(entry, new_entry) &&
+ ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
new_entry->efd_start_cluster = entry->efd_start_cluster;
new_entry->efd_count += entry->efd_count;
rb_erase(node, &(db->bb_free_root));
- ext4_journal_callback_del(handle, &entry->efd_jce);
kmem_cache_free(ext4_free_data_cachep, entry);
}
}
@@ -4447,10 +4447,10 @@
node = rb_next(new_node);
if (node) {
entry = rb_entry(node, struct ext4_free_data, efd_node);
- if (can_merge(new_entry, entry)) {
+ if (can_merge(new_entry, entry) &&
+ ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
new_entry->efd_count += entry->efd_count;
rb_erase(node, &(db->bb_free_root));
- ext4_journal_callback_del(handle, &entry->efd_jce);
kmem_cache_free(ext4_free_data_cachep, entry);
}
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 6577ae3..feb8265 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -438,10 +438,13 @@
struct super_block *sb = journal->j_private;
struct ext4_sb_info *sbi = EXT4_SB(sb);
int error = is_journal_aborted(journal);
- struct ext4_journal_cb_entry *jce, *tmp;
+ struct ext4_journal_cb_entry *jce;
+ BUG_ON(txn->t_state == T_FINISHED);
spin_lock(&sbi->s_md_lock);
- list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) {
+ while (!list_empty(&txn->t_private_list)) {
+ jce = list_entry(txn->t_private_list.next,
+ struct ext4_journal_cb_entry, jce_list);
list_del_init(&jce->jce_list);
spin_unlock(&sbi->s_md_lock);
jce->jce_func(sb, jce, error);
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 840f70f..a0dcbd62 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -325,7 +325,7 @@
int space_left = 0;
int first_tag = 0;
int tag_flag;
- int i, to_free = 0;
+ int i;
int tag_bytes = journal_tag_bytes(journal);
struct buffer_head *cbh = NULL; /* For transactional checksums */
__u32 crc32_sum = ~0;
@@ -1044,7 +1044,7 @@
journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
spin_unlock(&journal->j_history_lock);
- commit_transaction->t_state = T_FINISHED;
+ commit_transaction->t_state = T_COMMIT_CALLBACK;
J_ASSERT(commit_transaction == journal->j_committing_transaction);
journal->j_commit_sequence = commit_transaction->t_tid;
journal->j_committing_transaction = NULL;
@@ -1059,38 +1059,44 @@
journal->j_average_commit_time*3) / 4;
else
journal->j_average_commit_time = commit_time;
+
write_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL &&
- commit_transaction->t_checkpoint_io_list == NULL) {
- __jbd2_journal_drop_transaction(journal, commit_transaction);
- to_free = 1;
+ if (journal->j_checkpoint_transactions == NULL) {
+ journal->j_checkpoint_transactions = commit_transaction;
+ commit_transaction->t_cpnext = commit_transaction;
+ commit_transaction->t_cpprev = commit_transaction;
} else {
- if (journal->j_checkpoint_transactions == NULL) {
- journal->j_checkpoint_transactions = commit_transaction;
- commit_transaction->t_cpnext = commit_transaction;
- commit_transaction->t_cpprev = commit_transaction;
- } else {
- commit_transaction->t_cpnext =
- journal->j_checkpoint_transactions;
- commit_transaction->t_cpprev =
- commit_transaction->t_cpnext->t_cpprev;
- commit_transaction->t_cpnext->t_cpprev =
+ commit_transaction->t_cpnext =
+ journal->j_checkpoint_transactions;
+ commit_transaction->t_cpprev =
+ commit_transaction->t_cpnext->t_cpprev;
+ commit_transaction->t_cpnext->t_cpprev =
+ commit_transaction;
+ commit_transaction->t_cpprev->t_cpnext =
commit_transaction;
- commit_transaction->t_cpprev->t_cpnext =
- commit_transaction;
- }
}
spin_unlock(&journal->j_list_lock);
-
+ /* Drop all spin_locks because commit_callback may be block.
+ * __journal_remove_checkpoint() can not destroy transaction
+ * under us because it is not marked as T_FINISHED yet */
if (journal->j_commit_callback)
journal->j_commit_callback(journal, commit_transaction);
trace_jbd2_end_commit(journal, commit_transaction);
jbd_debug(1, "JBD2: commit %d complete, head %d\n",
journal->j_commit_sequence, journal->j_tail_sequence);
- if (to_free)
- jbd2_journal_free_transaction(commit_transaction);
+ write_lock(&journal->j_state_lock);
+ spin_lock(&journal->j_list_lock);
+ commit_transaction->t_state = T_FINISHED;
+ /* Recheck checkpoint lists after j_list_lock was dropped */
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
+ __jbd2_journal_drop_transaction(journal, commit_transaction);
+ jbd2_journal_free_transaction(commit_transaction);
+ }
+ spin_unlock(&journal->j_list_lock);
+ write_unlock(&journal->j_state_lock);
wake_up(&journal->j_wait_done_commit);
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 2fb663a..1874adb 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -82,6 +82,56 @@
return mm->total_vm;
}
+static void seq_print_vma_name(struct seq_file *m, struct vm_area_struct *vma)
+{
+ const char __user *name = vma_get_anon_name(vma);
+ struct mm_struct *mm = vma->vm_mm;
+
+ unsigned long page_start_vaddr;
+ unsigned long page_offset;
+ unsigned long num_pages;
+ unsigned long max_len = NAME_MAX;
+ int i;
+
+ page_start_vaddr = (unsigned long)name & PAGE_MASK;
+ page_offset = (unsigned long)name - page_start_vaddr;
+ num_pages = DIV_ROUND_UP(page_offset + max_len, PAGE_SIZE);
+
+ seq_puts(m, "[anon:");
+
+ for (i = 0; i < num_pages; i++) {
+ int len;
+ int write_len;
+ const char *kaddr;
+ long pages_pinned;
+ struct page *page;
+
+ pages_pinned = get_user_pages(current, mm, page_start_vaddr,
+ 1, 0, 0, &page, NULL);
+ if (pages_pinned < 1) {
+ seq_puts(m, "<fault>]");
+ return;
+ }
+
+ kaddr = (const char *)kmap(page);
+ len = min(max_len, PAGE_SIZE - page_offset);
+ write_len = strnlen(kaddr + page_offset, len);
+ seq_write(m, kaddr + page_offset, write_len);
+ kunmap(page);
+ put_page(page);
+
+ /* if strnlen hit a null terminator then we're done */
+ if (write_len != len)
+ break;
+
+ max_len -= len;
+ page_offset = 0;
+ page_start_vaddr += PAGE_SIZE;
+ }
+
+ seq_putc(m, ']');
+}
+
static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
{
if (vma && vma != priv->tail_vma) {
@@ -281,6 +331,12 @@
seq_pad(m, ' ');
seq_printf(m, "[stack:%d]", tid);
}
+ goto done;
+ }
+
+ if (vma_get_anon_name(vma)) {
+ seq_pad(m, ' ');
+ seq_print_vma_name(m, vma);
}
}
@@ -513,6 +569,12 @@
(vma->vm_flags & VM_LOCKED) ?
(unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
+ if (vma_get_anon_name(vma)) {
+ seq_puts(m, "Name: ");
+ seq_print_vma_name(m, vma);
+ seq_putc(m, '\n');
+ }
+
if (m->count < m->size) /* vma is copied successfully */
m->version = (vma != get_gate_vma(task->mm))
? vma->vm_start : 0;
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 4effce6..07f5063 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -161,6 +161,7 @@
__s32 accept_ra_rt_info_max_plen;
#endif
#endif
+ __s32 accept_ra_rt_table;
__s32 proxy_ndp;
__s32 accept_source_route;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -215,6 +216,7 @@
DEVCONF_ACCEPT_DAD,
DEVCONF_FORCE_TLLAO,
DEVCONF_ACCEPT_RA_PREFIX_ROUTE,
+ DEVCONF_ACCEPT_RA_RT_TABLE,
DEVCONF_MAX
};
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 2ed66ef..dd6444f 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -470,6 +470,7 @@
T_COMMIT,
T_COMMIT_DFLUSH,
T_COMMIT_JFLUSH,
+ T_COMMIT_CALLBACK,
T_FINISHED
} t_state;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2218ac4..b574c60 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1394,7 +1394,7 @@
extern struct vm_area_struct *vma_merge(struct mm_struct *,
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
- struct mempolicy *);
+ struct mempolicy *, const char __user *);
extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
extern int split_vma(struct mm_struct *,
struct vm_area_struct *, unsigned long addr, int new_below);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b98b4b9..8535cc0 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -216,6 +216,10 @@
* linkage into the address_space->i_mmap prio tree, or
* linkage to the list of like vmas hanging off its node, or
* linkage of vma in the address_space->i_mmap_nonlinear list.
+ *
+ * For private anonymous mappings, a pointer to a null terminated string
+ * in the user process containing the name given to the vma, or NULL
+ * if unnamed.
*/
union {
struct {
@@ -225,6 +229,7 @@
} vm_set;
struct raw_prio_tree_node prio_tree_node;
+ const char __user *anon_name;
} shared;
/*
@@ -392,4 +397,14 @@
return mm->cpu_vm_mask_var;
}
+
+/* Return the name for an anonymous mapping or NULL for a file-backed mapping */
+static inline const char __user *vma_get_anon_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_file)
+ return NULL;
+
+ return vma->shared.anon_name;
+}
+
#endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0b95337..f712fba 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -2636,14 +2636,20 @@
* @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * (if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ * from a probe response, otherwise it may be from the same beacon
+ * that the NL80211_BSS_BEACON_TSF will be from)
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
* raw information elements from the probe response/beacon (bin);
- * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ * different then the IEs here are from a Probe Response frame; otherwise
+ * they are from a Beacon frame.
* However, if the driver does not indicate the source of the IEs, these
* IEs may be from either frame subtype.
+ * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ * data here is known to be from a probe response, without any heuristics.
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
* in mBm (100 * dBm) (s32)
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -2653,6 +2659,12 @@
* @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
* elements from a Beacon frame (bin); not present if no Beacon frame has
* yet been received
+ * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
+ * (u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ * (not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ * @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -2669,6 +2681,9 @@
NL80211_BSS_STATUS,
NL80211_BSS_SEEN_MS_AGO,
NL80211_BSS_BEACON_IES,
+ NL80211_BSS_CHAN_WIDTH,
+ NL80211_BSS_BEACON_TSF,
+ NL80211_BSS_PRESP_DATA,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index e0cfec2..23728f0 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -124,4 +124,13 @@
#define PR_SET_CHILD_SUBREAPER 36
#define PR_GET_CHILD_SUBREAPER 37
+/* Sets the timerslack for arbitrary threads
+ * arg2 slack value, 0 means "use default"
+ * arg3 pid of the thread whose timer slack needs to be set
+ */
+#define PR_SET_TIMERSLACK_PID 41
+
+#define PR_SET_VMA 0x53564d41
+# define PR_SET_VMA_ANON_NAME 0
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index e6c46d1..8bdcfd5 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -28,6 +28,8 @@
struct wcnss_wlan_config {
int use_48mhz_xo;
+ int is_pronto_v3;
+ void __iomem *msm_wcnss_base;
};
enum {
@@ -77,6 +79,7 @@
void wcnss_resume_notify(void);
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
+int wcnss_is_hw_pronto_ver3(void);
int wcnss_device_ready(void);
int wcnss_device_is_shutdown(void);
void wcnss_riva_dump_pmic_regs(void);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 757a176..f080441 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -166,6 +166,8 @@
extern int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
const struct in6_addr *addr);
+u32 addrconf_rt_table(const struct net_device *dev, u32 default_table);
+
/* Device notifier */
extern int register_inet6addr_notifier(struct notifier_block *nb);
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index ae17e13..1eb1829 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -89,6 +89,7 @@
no_srccheck: 1;
kmemcheck_bitfield_end(flags);
struct ip_options_rcu *opt;
+ u32 ir_mark;
};
static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
@@ -96,6 +97,15 @@
return (struct inet_request_sock *)sk;
}
+static inline u32 inet_request_mark(struct sock *sk, struct sk_buff *skb)
+{
+ if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept) {
+ return skb->mark;
+ } else {
+ return sk->sk_mark;
+ }
+}
+
struct inet_cork {
unsigned int flags;
__be32 addr;
diff --git a/include/net/ip.h b/include/net/ip.h
index 53af759..e36ffa1 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -238,6 +238,9 @@
extern void ip_static_sysctl_init(void);
+#define IP4_REPLY_MARK(net, mark) \
+ ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0)
+
static inline bool ip_is_fragment(const struct iphdr *iph)
{
return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index a5a9e4d..2161a39 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -109,6 +109,9 @@
#define IP6_MF 0x0001
+#define IP6_REPLY_MARK(net, mark) \
+ ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0)
+
#include <net/sock.h>
/* sysctls */
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index bbd023a..8869426 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -56,6 +56,8 @@
unsigned int sysctl_ping_group_range[2];
long sysctl_tcp_mem[3];
+ int sysctl_fwmark_reflect;
+ int sysctl_tcp_fwmark_accept;
atomic_t rt_genid;
atomic_t dev_addr_genid;
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 81abfcb..20b76ab 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -25,6 +25,7 @@
int ip6_rt_mtu_expires;
int ip6_rt_min_advmss;
int icmpv6_time;
+ int fwmark_reflect;
};
struct netns_ipv6 {
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index 8ac835c..e3e62c9 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -32,4 +32,6 @@
int q6audio_get_port_id(u16 port_id);
+int q6audio_get_port_id_from_index(u16 port_idx);
+
#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index 39791be..2f95158 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -40,6 +40,9 @@
#include <linux/syscore_ops.h>
#include <linux/version.h>
#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/mempolicy.h>
+#include <linux/sched.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -1821,10 +1824,151 @@
}
#endif
+
+static int prctl_update_vma_anon_name(struct vm_area_struct *vma,
+ struct vm_area_struct **prev,
+ unsigned long start, unsigned long end,
+ const char __user *name_addr)
+{
+ struct mm_struct * mm = vma->vm_mm;
+ int error = 0;
+ pgoff_t pgoff;
+
+ if (name_addr == vma_get_anon_name(vma)) {
+ *prev = vma;
+ goto out;
+ }
+
+ pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma,
+ vma->vm_file, pgoff, vma_policy(vma),
+ name_addr);
+ if (*prev) {
+ vma = *prev;
+ goto success;
+ }
+
+ *prev = vma;
+
+ if (start != vma->vm_start) {
+ error = split_vma(mm, vma, start, 1);
+ if (error)
+ goto out;
+ }
+
+ if (end != vma->vm_end) {
+ error = split_vma(mm, vma, end, 0);
+ if (error)
+ goto out;
+ }
+
+success:
+ if (!vma->vm_file)
+ vma->shared.anon_name = name_addr;
+
+out:
+ if (error == -ENOMEM)
+ error = -EAGAIN;
+ return error;
+}
+
+static int prctl_set_vma_anon_name(unsigned long start, unsigned long end,
+ unsigned long arg)
+{
+ unsigned long tmp;
+ struct vm_area_struct * vma, *prev;
+ int unmapped_error = 0;
+ int error = -EINVAL;
+
+ /*
+ * If the interval [start,end) covers some unmapped address
+ * ranges, just ignore them, but return -ENOMEM at the end.
+ * - this matches the handling in madvise.
+ */
+ vma = find_vma_prev(current->mm, start, &prev);
+ if (vma && start > vma->vm_start)
+ prev = vma;
+
+ for (;;) {
+ /* Still start < end. */
+ error = -ENOMEM;
+ if (!vma)
+ return error;
+
+ /* Here start < (end|vma->vm_end). */
+ if (start < vma->vm_start) {
+ unmapped_error = -ENOMEM;
+ start = vma->vm_start;
+ if (start >= end)
+ return error;
+ }
+
+ /* Here vma->vm_start <= start < (end|vma->vm_end) */
+ tmp = vma->vm_end;
+ if (end < tmp)
+ tmp = end;
+
+ /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
+ error = prctl_update_vma_anon_name(vma, &prev, start, end,
+ (const char __user *)arg);
+ if (error)
+ return error;
+ start = tmp;
+ if (prev && start < prev->vm_end)
+ start = prev->vm_end;
+ error = unmapped_error;
+ if (start >= end)
+ return error;
+ if (prev)
+ vma = prev->vm_next;
+ else /* madvise_remove dropped mmap_sem */
+ vma = find_vma(current->mm, start);
+ }
+}
+
+static int prctl_set_vma(unsigned long opt, unsigned long start,
+ unsigned long len_in, unsigned long arg)
+{
+ struct mm_struct *mm = current->mm;
+ int error;
+ unsigned long len;
+ unsigned long end;
+
+ if (start & ~PAGE_MASK)
+ return -EINVAL;
+ len = (len_in + ~PAGE_MASK) & PAGE_MASK;
+
+ /* Check to see whether len was rounded up from small -ve to zero */
+ if (len_in && !len)
+ return -EINVAL;
+
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+
+ if (end == start)
+ return 0;
+
+ down_write(&mm->mmap_sem);
+
+ switch (opt) {
+ case PR_SET_VMA_ANON_NAME:
+ error = prctl_set_vma_anon_name(start, end, arg);
+ break;
+ default:
+ error = -EINVAL;
+ }
+
+ up_write(&mm->mmap_sem);
+
+ return error;
+}
+
SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
struct task_struct *me = current;
+ struct task_struct *tsk;
unsigned char comm[sizeof(me->comm)];
long error;
@@ -1981,6 +2125,29 @@
error = put_user(me->signal->is_child_subreaper,
(int __user *) arg2);
break;
+ case PR_SET_VMA:
+ error = prctl_set_vma(arg2, arg3, arg4, arg5);
+ break;
+ case PR_SET_TIMERSLACK_PID:
+ if (current->pid != (pid_t)arg3 &&
+ !capable(CAP_SYS_NICE))
+ return -EPERM;
+ rcu_read_lock();
+ tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
+ if (tsk == NULL) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ get_task_struct(tsk);
+ rcu_read_unlock();
+ if (arg2 <= 0)
+ tsk->timer_slack_ns =
+ tsk->default_timer_slack_ns;
+ else
+ tsk->timer_slack_ns = arg2;
+ put_task_struct(tsk);
+ error = 0;
+ break;
default:
error = -EINVAL;
break;
diff --git a/mm/madvise.c b/mm/madvise.c
index 55f645c..b075d1d 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -93,7 +93,8 @@
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
- vma->vm_file, pgoff, vma_policy(vma));
+ vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*prev) {
vma = *prev;
goto success;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b195691..a786980 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -660,7 +660,7 @@
((vmstart - vma->vm_start) >> PAGE_SHIFT);
prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
vma->anon_vma, vma->vm_file, pgoff,
- new_pol);
+ new_pol, vma_get_anon_name(name));
if (prev) {
vma = prev;
next = vma->vm_next;
diff --git a/mm/mlock.c b/mm/mlock.c
index 38c77ab..029f234 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -333,7 +333,8 @@
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
- vma->vm_file, pgoff, vma_policy(vma));
+ vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*prev) {
vma = *prev;
goto success;
diff --git a/mm/mmap.c b/mm/mmap.c
index 9932edb..964223d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -649,7 +649,8 @@
* per-vma resources, so we don't attempt to merge those.
*/
static inline int is_mergeable_vma(struct vm_area_struct *vma,
- struct file *file, unsigned long vm_flags)
+ struct file *file, unsigned long vm_flags,
+ const char __user *anon_name)
{
/* VM_CAN_NONLINEAR may get set later by f_op->mmap() */
if ((vma->vm_flags ^ vm_flags) & ~VM_CAN_NONLINEAR)
@@ -658,6 +659,8 @@
return 0;
if (vma->vm_ops && vma->vm_ops->close)
return 0;
+ if (vma_get_anon_name(vma) != anon_name)
+ return 0;
return 1;
}
@@ -688,9 +691,10 @@
*/
static int
can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
- struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
+ struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
+ const char __user *anon_name)
{
- if (is_mergeable_vma(vma, file, vm_flags) &&
+ if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
if (vma->vm_pgoff == vm_pgoff)
return 1;
@@ -707,9 +711,10 @@
*/
static int
can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
- struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
+ struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
+ const char __user *anon_name)
{
- if (is_mergeable_vma(vma, file, vm_flags) &&
+ if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
pgoff_t vm_pglen;
vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
@@ -720,9 +725,9 @@
}
/*
- * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out
- * whether that can be merged with its predecessor or its successor.
- * Or both (it neatly fills a hole).
+ * Given a mapping request (addr,end,vm_flags,file,pgoff,anon_name),
+ * figure out whether that can be merged with its predecessor or its
+ * successor. Or both (it neatly fills a hole).
*
* In most cases - when called for mmap, brk or mremap - [addr,end) is
* certain not to be mapped by the time vma_merge is called; but when
@@ -752,7 +757,8 @@
struct vm_area_struct *prev, unsigned long addr,
unsigned long end, unsigned long vm_flags,
struct anon_vma *anon_vma, struct file *file,
- pgoff_t pgoff, struct mempolicy *policy)
+ pgoff_t pgoff, struct mempolicy *policy,
+ const char __user *anon_name)
{
pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
struct vm_area_struct *area, *next;
@@ -778,15 +784,15 @@
*/
if (prev && prev->vm_end == addr &&
mpol_equal(vma_policy(prev), policy) &&
- can_vma_merge_after(prev, vm_flags,
- anon_vma, file, pgoff)) {
+ can_vma_merge_after(prev, vm_flags, anon_vma,
+ file, pgoff, anon_name)) {
/*
* OK, it can. Can we now merge in the successor as well?
*/
if (next && end == next->vm_start &&
mpol_equal(policy, vma_policy(next)) &&
- can_vma_merge_before(next, vm_flags,
- anon_vma, file, pgoff+pglen) &&
+ can_vma_merge_before(next, vm_flags, anon_vma,
+ file, pgoff+pglen, anon_name) &&
is_mergeable_anon_vma(prev->anon_vma,
next->anon_vma, NULL)) {
/* cases 1, 6 */
@@ -806,8 +812,8 @@
*/
if (next && end == next->vm_start &&
mpol_equal(policy, vma_policy(next)) &&
- can_vma_merge_before(next, vm_flags,
- anon_vma, file, pgoff+pglen)) {
+ can_vma_merge_before(next, vm_flags, anon_vma,
+ file, pgoff+pglen, anon_name)) {
if (prev && addr < prev->vm_end) /* case 4 */
err = vma_adjust(prev, prev->vm_start,
addr, prev->vm_pgoff, NULL);
@@ -1282,7 +1288,8 @@
/*
* Can we just expand an old mapping?
*/
- vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL);
+ vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff,
+ NULL, NULL);
if (vma)
goto out;
@@ -2232,7 +2239,7 @@
/* Can we just expand an old private anonymous mapping? */
vma = vma_merge(mm, prev, addr, addr + len, flags,
- NULL, NULL, pgoff, NULL);
+ NULL, NULL, pgoff, NULL, NULL);
if (vma)
goto out;
@@ -2382,7 +2389,8 @@
find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
- vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
+ vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (new_vma) {
/*
* Source vma may have been merged into new_vma
diff --git a/mm/mprotect.c b/mm/mprotect.c
index a409926..10add6b 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -179,7 +179,8 @@
*/
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*pprev = vma_merge(mm, *pprev, start, end, newflags,
- vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
+ vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*pprev) {
vma = *pprev;
goto success;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d4c0534..7eefa94 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -657,6 +657,8 @@
int migratetype = 0;
int batch_free = 0;
int to_free = count;
+ int free = 0;
+ int cma_free = 0;
int mt = 0;
spin_lock(&zone->lock);
@@ -687,17 +689,23 @@
do {
page = list_entry(list->prev, struct page, lru);
mt = get_pageblock_migratetype(page);
+ if (likely(mt != MIGRATE_ISOLATE))
+ mt = page_private(page);
+
/* must delete as __free_one_page list manipulates */
list_del(&page->lru);
/* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */
- __free_one_page(page, zone, 0, page_private(page));
- trace_mm_page_pcpu_drain(page, 0, page_private(page));
- if (is_migrate_cma(mt))
- __mod_zone_page_state(zone,
- NR_FREE_CMA_PAGES, 1);
+ __free_one_page(page, zone, 0, mt);
+ trace_mm_page_pcpu_drain(page, 0, mt);
+ if (likely(mt != MIGRATE_ISOLATE)) {
+ free++;
+ if (is_migrate_cma(mt))
+ cma_free++;
+ }
} while (--to_free && --batch_free && !list_empty(list));
}
- __mod_zone_page_state(zone, NR_FREE_PAGES, count);
+ __mod_zone_page_state(zone, NR_FREE_PAGES, free);
+ __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, cma_free);
spin_unlock(&zone->lock);
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 2e109ff..ea63a57 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -335,6 +335,7 @@
struct sock *sk;
struct inet_sock *inet;
__be32 daddr;
+ u32 mark = IP4_REPLY_MARK(net, skb->mark);
if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
return;
@@ -347,6 +348,7 @@
icmp_param->data.icmph.checksum = 0;
inet->tos = ip_hdr(skb)->tos;
+ sk->sk_mark = mark;
daddr = ipc.addr = ip_hdr(skb)->saddr;
ipc.opt = NULL;
ipc.tx_flags = 0;
@@ -358,6 +360,7 @@
memset(&fl4, 0, sizeof(fl4));
fl4.daddr = daddr;
fl4.saddr = rt->rt_spec_dst;
+ fl4.flowi4_mark = mark;
fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
fl4.flowi4_proto = IPPROTO_ICMP;
security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
@@ -376,7 +379,7 @@
struct flowi4 *fl4,
struct sk_buff *skb_in,
const struct iphdr *iph,
- __be32 saddr, u8 tos,
+ __be32 saddr, u8 tos, u32 mark,
int type, int code,
struct icmp_bxm *param)
{
@@ -388,6 +391,7 @@
fl4->daddr = (param->replyopts.opt.opt.srr ?
param->replyopts.opt.opt.faddr : iph->saddr);
fl4->saddr = saddr;
+ fl4->flowi4_mark = mark;
fl4->flowi4_tos = RT_TOS(tos);
fl4->flowi4_proto = IPPROTO_ICMP;
fl4->fl4_icmp_type = type;
@@ -485,6 +489,7 @@
struct flowi4 fl4;
__be32 saddr;
u8 tos;
+ u32 mark;
struct net *net;
struct sock *sk;
@@ -581,6 +586,7 @@
tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
IPTOS_PREC_INTERNETCONTROL) :
iph->tos;
+ mark = IP4_REPLY_MARK(net, skb_in->mark);
if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in))
goto out_unlock;
@@ -597,11 +603,12 @@
icmp_param.skb = skb_in;
icmp_param.offset = skb_network_offset(skb_in);
inet_sk(sk)->tos = tos;
+ sk->sk_mark = mark;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts.opt;
ipc.tx_flags = 0;
- rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
+ rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark,
type, code, &icmp_param);
if (IS_ERR(rt))
goto out_unlock;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index b902d58..fb10d58 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -361,7 +361,7 @@
struct ip_options_rcu *opt = inet_rsk(req)->opt;
struct net *net = sock_net(sk);
- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
+ flowi4_init_output(fl4, sk->sk_bound_dev_if, ireq->ir_mark,
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
sk->sk_protocol, inet_sk_flowi_flags(sk),
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr,
@@ -395,7 +395,7 @@
struct rtable *rt;
fl4 = &newinet->cork.fl.u.ip4;
- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
+ flowi4_init_output(fl4, sk->sk_bound_dev_if, ireq->ir_mark,
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
sk->sk_protocol, inet_sk_flowi_flags(sk),
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr,
@@ -618,6 +618,8 @@
inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port;
newsk->sk_write_space = sk_stream_write_space;
+ newsk->sk_mark = inet_rsk(req)->ir_mark;
+
newicsk->icsk_retransmits = 0;
newicsk->icsk_backoff = 0;
newicsk->icsk_probes_out = 0;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index c8e10a5..6f72f39 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1500,7 +1500,8 @@
daddr = replyopts.opt.opt.faddr;
}
- flowi4_init_output(&fl4, arg->bound_dev_if, 0,
+ flowi4_init_output(&fl4, arg->bound_dev_if,
+ IP4_REPLY_MARK(sock_net(sk), skb->mark),
RT_TOS(arg->tos),
RT_SCOPE_UNIVERSE, sk->sk_protocol,
ip_reply_arg_flowi_flags(arg),
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 7f4dba3..b93b6d3 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -312,6 +312,7 @@
ireq->rmt_port = th->source;
ireq->loc_addr = ip_hdr(skb)->daddr;
ireq->rmt_addr = ip_hdr(skb)->saddr;
+ ireq->ir_mark = inet_request_mark(sk, skb);
ireq->ecn_ok = ecn_ok;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
@@ -347,7 +348,7 @@
* hasn't changed since we received the original syn, but I see
* no easy way to do this.
*/
- flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
+ flowi4_init_output(&fl4, 0, ireq->ir_mark, RT_CONN_FLAGS(sk),
RT_SCOPE_UNIVERSE, IPPROTO_TCP,
inet_sk_flowi_flags(sk),
(opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 6bd622f..7c81e3b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -788,6 +788,20 @@
.mode = 0644,
.proc_handler = ipv4_tcp_mem,
},
+ {
+ .procname = "fwmark_reflect",
+ .data = &init_net.ipv4.sysctl_fwmark_reflect,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "tcp_fwmark_accept",
+ .data = &init_net.ipv4.sysctl_tcp_fwmark_accept,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{ }
};
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 54225b1..9640f6d 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1350,6 +1350,7 @@
ireq->rmt_addr = saddr;
ireq->no_srccheck = inet_sk(sk)->transparent;
ireq->opt = tcp_v4_save_options(sk, skb);
+ ireq->ir_mark = inet_request_mark(sk, skb);
if (security_inet_conn_request(sk, skb, req))
goto drop_and_free;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5bb2847..dffd854 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -195,6 +195,7 @@
.accept_ra_rt_info_max_plen = 0,
#endif
#endif
+ .accept_ra_rt_table = 0,
.proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
@@ -230,6 +231,7 @@
.accept_ra_rt_info_max_plen = 0,
#endif
#endif
+ .accept_ra_rt_table = 0,
.proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
@@ -1690,6 +1692,31 @@
}
#endif
+u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) {
+ /* Determines into what table to put autoconf PIO/RIO/default routes
+ * learned on this device.
+ *
+ * - If 0, use the same table for every device. This puts routes into
+ * one of RT_TABLE_{PREFIX,INFO,DFLT} depending on the type of route
+ * (but note that these three are currently all equal to
+ * RT6_TABLE_MAIN).
+ * - If > 0, use the specified table.
+ * - If < 0, put routes into table dev->ifindex + (-rt_table).
+ */
+ struct inet6_dev *idev = in6_dev_get(dev);
+ u32 table;
+ int sysctl = idev->cnf.accept_ra_rt_table;
+ if (sysctl == 0) {
+ table = default_table;
+ } else if (sysctl > 0) {
+ table = (u32) sysctl;
+ } else {
+ table = (unsigned) dev->ifindex + (-sysctl);
+ }
+ in6_dev_put(idev);
+ return table;
+}
+
/*
* Add prefix route.
*/
@@ -1699,7 +1726,7 @@
unsigned long expires, u32 flags)
{
struct fib6_config cfg = {
- .fc_table = RT6_TABLE_PREFIX,
+ .fc_table = addrconf_rt_table(dev, RT6_TABLE_PREFIX),
.fc_metric = IP6_RT_PRIO_ADDRCONF,
.fc_ifindex = dev->ifindex,
.fc_expires = expires,
@@ -1733,7 +1760,8 @@
struct rt6_info *rt = NULL;
struct fib6_table *table;
- table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
+ table = fib6_get_table(dev_net(dev),
+ addrconf_rt_table(dev, RT6_TABLE_PREFIX));
if (table == NULL)
return NULL;
@@ -3922,6 +3950,7 @@
array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
#endif
#endif
+ array[DEVCONF_ACCEPT_RA_RT_TABLE] = cnf->accept_ra_rt_table;
array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -4550,6 +4579,13 @@
#endif
#endif
{
+ .procname = "accept_ra_rt_table",
+ .data = &ipv6_devconf.accept_ra_rt_table,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "proxy_ndp",
.data = &ipv6_devconf.proxy_ndp,
.maxlen = sizeof(int),
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index ba0c147..b595aa6 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -396,6 +396,7 @@
int len;
int hlimit;
int err = 0;
+ u32 mark = IP6_REPLY_MARK(net, skb->mark);
if ((u8 *)hdr < skb->head ||
(skb->network_header + sizeof(*hdr)) > skb->tail)
@@ -461,6 +462,7 @@
fl6.daddr = hdr->saddr;
if (saddr)
fl6.saddr = *saddr;
+ fl6.flowi6_mark = mark;
fl6.flowi6_oif = iif;
fl6.fl6_icmp_type = type;
fl6.fl6_icmp_code = code;
@@ -469,6 +471,7 @@
sk = icmpv6_xmit_lock(net);
if (sk == NULL)
return;
+ sk->sk_mark = mark;
np = inet6_sk(sk);
if (!icmpv6_xrlim_allow(sk, type, &fl6))
@@ -543,6 +546,7 @@
struct dst_entry *dst;
int err = 0;
int hlimit;
+ u32 mark = IP6_REPLY_MARK(net, skb->mark);
saddr = &ipv6_hdr(skb)->daddr;
@@ -559,11 +563,13 @@
fl6.saddr = *saddr;
fl6.flowi6_oif = skb->dev->ifindex;
fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
+ fl6.flowi6_mark = mark;
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
sk = icmpv6_xmit_lock(net);
if (sk == NULL)
return;
+ sk->sk_mark = mark;
np = inet6_sk(sk);
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 21ee002..aefc8b7 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -69,7 +69,7 @@
final_p = fl6_update_dst(&fl6, np->opt, &final);
fl6.saddr = treq->loc_addr;
fl6.flowi6_oif = sk->sk_bound_dev_if;
- fl6.flowi6_mark = sk->sk_mark;
+ fl6.flowi6_mark = inet_rsk(req)->ir_mark;
fl6.fl6_dport = inet_rsk(req)->rmt_port;
fl6.fl6_sport = inet_rsk(req)->loc_port;
fl6.flowi6_uid = sock_i_uid(sk);
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 8c1e9b2..7559966 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -159,6 +159,7 @@
fl6.flowi6_proto = IPPROTO_ICMPV6;
fl6.saddr = np->saddr;
fl6.daddr = *daddr;
+ fl6.flowi6_mark = sk->sk_mark;
fl6.fl6_icmp_type = user_icmph.icmp6_type;
fl6.fl6_icmp_code = user_icmph.icmp6_code;
fl6.flowi6_uid = sock_i_uid(sk);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index eabab4a..3e6b53b 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -79,13 +79,13 @@
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
#ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_add_route_info(struct net *net,
+static struct rt6_info *rt6_add_route_info(struct net_device *dev,
const struct in6_addr *prefix, int prefixlen,
- const struct in6_addr *gwaddr, int ifindex,
+ const struct in6_addr *gwaddr,
unsigned pref);
-static struct rt6_info *rt6_get_route_info(struct net *net,
+static struct rt6_info *rt6_get_route_info(struct net_device *dev,
const struct in6_addr *prefix, int prefixlen,
- const struct in6_addr *gwaddr, int ifindex);
+ const struct in6_addr *gwaddr);
#endif
static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
@@ -575,7 +575,6 @@
int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
const struct in6_addr *gwaddr)
{
- struct net *net = dev_net(dev);
struct route_info *rinfo = (struct route_info *) opt;
struct in6_addr prefix_buf, *prefix;
unsigned int pref;
@@ -617,8 +616,7 @@
prefix = &prefix_buf;
}
- rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
- dev->ifindex);
+ rt = rt6_get_route_info(dev, prefix, rinfo->prefix_len, gwaddr);
if (rt && !lifetime) {
ip6_del_rt(rt);
@@ -626,8 +624,7 @@
}
if (!rt && lifetime)
- rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
- pref);
+ rt = rt6_add_route_info(dev, prefix, rinfo->prefix_len, gwaddr, pref);
else if (rt)
rt->rt6i_flags = RTF_ROUTEINFO |
(rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
@@ -1852,15 +1849,16 @@
}
#ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_get_route_info(struct net *net,
+static struct rt6_info *rt6_get_route_info(struct net_device *dev,
const struct in6_addr *prefix, int prefixlen,
- const struct in6_addr *gwaddr, int ifindex)
+ const struct in6_addr *gwaddr)
{
struct fib6_node *fn;
struct rt6_info *rt = NULL;
struct fib6_table *table;
- table = fib6_get_table(net, RT6_TABLE_INFO);
+ table = fib6_get_table(dev_net(dev),
+ addrconf_rt_table(dev, RT6_TABLE_INFO));
if (!table)
return NULL;
@@ -1870,7 +1868,7 @@
goto out;
for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
- if (rt->dst.dev->ifindex != ifindex)
+ if (rt->dst.dev->ifindex != dev->ifindex)
continue;
if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
continue;
@@ -1884,21 +1882,21 @@
return rt;
}
-static struct rt6_info *rt6_add_route_info(struct net *net,
+static struct rt6_info *rt6_add_route_info(struct net_device *dev,
const struct in6_addr *prefix, int prefixlen,
- const struct in6_addr *gwaddr, int ifindex,
+ const struct in6_addr *gwaddr,
unsigned pref)
{
struct fib6_config cfg = {
- .fc_table = RT6_TABLE_INFO,
+ .fc_table = addrconf_rt_table(dev, RT6_TABLE_INFO),
.fc_metric = IP6_RT_PRIO_USER,
- .fc_ifindex = ifindex,
+ .fc_ifindex = dev->ifindex,
.fc_dst_len = prefixlen,
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
RTF_UP | RTF_PREF(pref),
.fc_nlinfo.pid = 0,
.fc_nlinfo.nlh = NULL,
- .fc_nlinfo.nl_net = net,
+ .fc_nlinfo.nl_net = dev_net(dev),
};
cfg.fc_dst = *prefix;
@@ -1910,7 +1908,7 @@
ip6_route_add(&cfg);
- return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
+ return rt6_get_route_info(dev, prefix, prefixlen, gwaddr);
}
#endif
@@ -1919,7 +1917,8 @@
struct rt6_info *rt;
struct fib6_table *table;
- table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
+ table = fib6_get_table(dev_net(dev),
+ addrconf_rt_table(dev, RT6_TABLE_MAIN));
if (!table)
return NULL;
@@ -1941,7 +1940,7 @@
unsigned int pref)
{
struct fib6_config cfg = {
- .fc_table = RT6_TABLE_DFLT,
+ .fc_table = addrconf_rt_table(dev, RT6_TABLE_DFLT),
.fc_metric = IP6_RT_PRIO_USER,
.fc_ifindex = dev->ifindex,
.fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
@@ -1958,28 +1957,17 @@
return rt6_get_dflt_router(gwaddr, dev);
}
+
+int rt6_addrconf_purge(struct rt6_info *rt, void *arg) {
+ if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
+ (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2))
+ return -1;
+ return 0;
+}
+
void rt6_purge_dflt_routers(struct net *net)
{
- struct rt6_info *rt;
- struct fib6_table *table;
-
- /* NOTE: Keep consistent with rt6_get_dflt_router */
- table = fib6_get_table(net, RT6_TABLE_DFLT);
- if (!table)
- return;
-
-restart:
- read_lock_bh(&table->tb6_lock);
- for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
- if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
- (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
- dst_hold(&rt->dst);
- read_unlock_bh(&table->tb6_lock);
- ip6_del_rt(rt);
- goto restart;
- }
- }
- read_unlock_bh(&table->tb6_lock);
+ fib6_clean_all(net, rt6_addrconf_purge, 0, NULL);
}
static void rtmsg_to_fib6_config(struct net *net,
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 83ee321..af939af 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -215,6 +215,8 @@
ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
ireq6->iif = inet6_iif(skb);
+ ireq->ir_mark = inet_request_mark(sk, skb);
+
req->expires = 0UL;
req->retrans = 0;
ireq->ecn_ok = ecn_ok;
@@ -241,7 +243,7 @@
final_p = fl6_update_dst(&fl6, np->opt, &final);
fl6.saddr = ireq6->loc_addr;
fl6.flowi6_oif = sk->sk_bound_dev_if;
- fl6.flowi6_mark = sk->sk_mark;
+ fl6.flowi6_mark = inet_rsk(req)->ir_mark;
fl6.fl6_dport = inet_rsk(req)->rmt_port;
fl6.fl6_sport = inet_sk(sk)->inet_sport;
fl6.flowi6_uid = sock_i_uid(sk);
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 166a57c..1f872c3 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -48,6 +48,13 @@
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "fwmark_reflect",
+ .data = &init_net.ipv6.sysctl.fwmark_reflect,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
{ }
};
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 806fafd..a62ce59 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -495,7 +495,7 @@
fl6.saddr = treq->loc_addr;
fl6.flowlabel = 0;
fl6.flowi6_oif = treq->iif;
- fl6.flowi6_mark = sk->sk_mark;
+ fl6.flowi6_mark = inet_rsk(req)->ir_mark;
fl6.fl6_dport = inet_rsk(req)->rmt_port;
fl6.fl6_sport = inet_rsk(req)->loc_port;
fl6.flowi6_uid = sock_i_uid(sk);
@@ -900,6 +900,7 @@
fl6.flowi6_proto = IPPROTO_TCP;
fl6.flowi6_oif = inet6_iif(skb);
+ fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
fl6.fl6_dport = t1->dest;
fl6.fl6_sport = t1->source;
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
@@ -1146,6 +1147,7 @@
TCP_ECN_create_request(req, tcp_hdr(skb));
treq->iif = sk->sk_bound_dev_if;
+ inet_rsk(req)->ir_mark = inet_request_mark(sk, skb);
/* So that link locals have meaning */
if (!sk->sk_bound_dev_if &&
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index e17925f..6fac473 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2157,6 +2157,8 @@
static const struct snd_kcontrol_new aif4_mad_switch =
SOC_DAPM_SINGLE("Switch", TAIKO_A_CDC_CLK_OTHR_CTL, 4, 1, 0);
+static const struct snd_kcontrol_new aif4_vi_switch =
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_SPKR_PROT_EN, 3, 1, 0);
/* virtual port entries */
static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -3574,7 +3576,9 @@
{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
- {"AIF4 VI", NULL, "SPK_OUT"},
+ /* VI Feedback */
+ {"AIF4 VI", NULL, "VIONOFF"},
+ {"VIONOFF", "Switch", "VIINPUT"},
/* MAD */
{"AIF4 MAD", NULL, "CDC_CONN"},
@@ -5244,6 +5248,15 @@
if (ret)
pr_err("%s error in close_slim_sch_tx %d\n",
__func__, ret);
+ ret = taiko_codec_enable_slim_chmask(dai, false);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(core,
+ &dai->wcd9xxx_ch_list,
+ dai->grph);
+ pr_debug("%s: Disconnect RX port, ret = %d\n",
+ __func__, ret);
+ }
+
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
0xC, 0x0);
/*Disable V&I sensing*/
@@ -5943,6 +5956,10 @@
SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
+ SND_SOC_DAPM_SWITCH("VIONOFF", SND_SOC_NOPM, 0, 0,
+ &aif4_vi_switch),
+ SND_SOC_DAPM_INPUT("VIINPUT"),
+
};
static irqreturn_t taiko_slimbus_irq(int irq, void *data)
@@ -6777,7 +6794,9 @@
/* Clean up starts */
/* Turn off PA ramp generator */
snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
- if (!mbhc->hph_pa_dac_state)
+ if (!mbhc->hph_pa_dac_state &&
+ (!(test_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state) ||
+ test_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state))))
wcd9xxx_enable_static_pa(mbhc, false);
wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
break;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 4addcee..bb1b7fb 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -430,10 +430,18 @@
rc = -EINVAL;
goto adm_get_param_return;
}
- if ((params_data) && (adm_get_parameters[0] <
- ARRAY_SIZE(adm_get_parameters))) {
+ if ((params_data) && (ARRAY_SIZE(adm_get_parameters) >=
+ (1+adm_get_parameters[0])) &&
+ (params_length/sizeof(int) >=
+ adm_get_parameters[0])) {
for (i = 0; i < adm_get_parameters[0]; i++)
params_data[i] = adm_get_parameters[1+i];
+ } else {
+ pr_err("%s: Get param data not copied! get_param array size %zd, index %d, params array size %zd, index %d\n",
+ __func__, ARRAY_SIZE(adm_get_parameters),
+ (1+adm_get_parameters[0]),
+ params_length/sizeof(int),
+ adm_get_parameters[0]);
}
rc = 0;
adm_get_param_return:
@@ -630,16 +638,22 @@
/* payload[3] is the param size, check if payload */
/* is big enough and has a valid param size */
- if ((data->payload_size > (4 * sizeof(uint32_t))) &&
- (payload[3] <= ADM_GET_PARAMETER_LENGTH) &&
- (adm_get_parameters[0] <
- ARRAY_SIZE(adm_get_parameters))) {
+ if ((payload[0] == 0) && (data->payload_size >
+ (4 * sizeof(*payload))) &&
+ (data->payload_size/sizeof(*payload)-4 >=
+ payload[3]) &&
+ (ARRAY_SIZE(adm_get_parameters)-1 >=
+ payload[3])) {
adm_get_parameters[0] = payload[3];
- pr_debug("GET_PP PARAM:received parameter length: %x\n",
- adm_get_parameters[0]);
+ pr_debug("%s: GET_PP PARAM:received parameter length: 0x%x\n",
+ __func__, adm_get_parameters[0]);
/* storing param size then params */
for (i = 0; i < payload[3]; i++)
adm_get_parameters[1+i] = payload[4+i];
+ } else {
+ adm_get_parameters[0] = -1;
+ pr_err("%s: GET_PP_PARAMS failed, setting size to %d\n",
+ __func__, adm_get_parameters[0]);
}
atomic_set(&this_adm.copp_stat[index], 1);
wake_up(&this_adm.wait[index]);
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 57ea2a7..0ff96b1 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -80,6 +80,67 @@
}
}
+int q6audio_get_port_id_from_index(u16 port_idx)
+{
+ switch (port_idx) {
+ case IDX_PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+ case IDX_PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
+ case IDX_AFE_PORT_ID_PRIMARY_PCM_RX:
+ return AFE_PORT_ID_PRIMARY_PCM_RX;
+ case IDX_AFE_PORT_ID_PRIMARY_PCM_TX:
+ return AFE_PORT_ID_PRIMARY_PCM_TX;
+ case IDX_AFE_PORT_ID_SECONDARY_PCM_RX:
+ return AFE_PORT_ID_SECONDARY_PCM_RX;
+ case IDX_AFE_PORT_ID_SECONDARY_PCM_TX:
+ return AFE_PORT_ID_SECONDARY_PCM_TX;
+ case IDX_SECONDARY_I2S_RX: return SECONDARY_I2S_RX;
+ case IDX_SECONDARY_I2S_TX: return SECONDARY_I2S_TX;
+ case IDX_MI2S_RX: return MI2S_RX;
+ case IDX_MI2S_TX: return MI2S_TX;
+ case IDX_HDMI_RX: return HDMI_RX;
+ case IDX_RSVD_2: return RSVD_2;
+ case IDX_RSVD_3: return RSVD_3;
+ case IDX_DIGI_MIC_TX: return DIGI_MIC_TX;
+ case IDX_VOICE_RECORD_RX: return VOICE_RECORD_RX;
+ case IDX_VOICE_RECORD_TX: return VOICE_RECORD_TX;
+ case IDX_VOICE_PLAYBACK_TX: return VOICE_PLAYBACK_TX;
+ case IDX_VOICE2_PLAYBACK_TX: return VOICE2_PLAYBACK_TX;
+ case IDX_SLIMBUS_0_RX: return SLIMBUS_0_RX;
+ case IDX_SLIMBUS_0_TX: return SLIMBUS_0_TX;
+ case IDX_SLIMBUS_1_RX: return SLIMBUS_1_RX;
+ case IDX_SLIMBUS_1_TX: return SLIMBUS_1_TX;
+ case IDX_SLIMBUS_2_RX: return SLIMBUS_2_RX;
+ case IDX_SLIMBUS_2_TX: return SLIMBUS_2_TX;
+ case IDX_SLIMBUS_4_TX: return SLIMBUS_4_TX;
+ case IDX_SLIMBUS_5_TX: return SLIMBUS_5_TX;
+ case IDX_INT_BT_SCO_RX: return INT_BT_SCO_RX;
+ case IDX_INT_BT_SCO_TX: return INT_BT_SCO_TX;
+ case IDX_INT_BT_A2DP_RX: return INT_BT_A2DP_RX;
+ case IDX_INT_FM_RX: return INT_FM_RX;
+ case IDX_INT_FM_TX: return INT_FM_TX;
+ case IDX_RT_PROXY_PORT_001_RX: return RT_PROXY_PORT_001_RX;
+ case IDX_RT_PROXY_PORT_001_TX: return RT_PROXY_PORT_001_TX;
+ case IDX_AFE_PORT_ID_PRIMARY_MI2S_RX:
+ return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case IDX_AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ case IDX_AFE_PORT_ID_SECONDARY_MI2S_RX:
+ return AFE_PORT_ID_SECONDARY_MI2S_RX;
+ case IDX_AFE_PORT_ID_SECONDARY_MI2S_TX:
+ return AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case IDX_AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case IDX_AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return AFE_PORT_ID_TERTIARY_MI2S_TX;
+
+ default: return -EINVAL;
+ }
+}
+
int q6audio_get_port_id(u16 port_id)
{
switch (port_id) {
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index 701dfef..80c18b1 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -24,6 +24,7 @@
#include <mach/qdsp6v2/rtac.h>
#include <sound/q6asm-v2.h>
#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
#include <sound/apr_audio-v2.h>
#include <q6voice.h>
#include "audio_acdb.h"
@@ -822,6 +823,7 @@
u32 bytes_returned = 0;
u32 port_index = 0;
u32 copp_id;
+ int port_id;
u32 payload_size;
u32 data_size = 0;
struct apr_hdr adm_params;
@@ -880,6 +882,13 @@
__func__, copp_id);
goto done;
}
+ port_id = q6audio_get_port_id_from_index(port_index);
+
+ if (port_id < 0) {
+ pr_err("%s: Could not find port id mapped for port_idx %d\n",
+ __func__, port_index);
+ goto done;
+ }
mutex_lock(&rtac_adm_apr_mutex);
if (rtac_adm_apr_data.apr_handle == NULL) {
@@ -936,7 +945,7 @@
adm_params.dest_svc = APR_SVC_ADM;
adm_params.dest_domain = APR_DOMAIN_ADSP;
adm_params.dest_port = copp_id;
- adm_params.token = copp_id;
+ adm_params.token = port_id;
adm_params.opcode = opcode;
/* fill for out-of-band */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index a5d42d5..9f12914 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -533,6 +533,11 @@
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+
if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
ret = rtd->dai_link->ops->prepare(substream);
if (ret < 0) {
@@ -572,19 +577,22 @@
cancel_delayed_work(&rtd->delayed_work);
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dapm_stream_event(rtd,
- codec_dai->driver->playback.stream_name,
- SND_SOC_DAPM_STREAM_START);
- else {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
if (codec_dai->capture_active == 1)
snd_soc_dapm_stream_event(rtd,
- codec_dai->driver->capture.stream_name,
- SND_SOC_DAPM_STREAM_START);
+ codec_dai->driver->capture.stream_name,
+ SND_SOC_DAPM_STREAM_START);
}
snd_soc_dai_digital_mute(codec_dai, 0);
out:
+ if (ret < 0 && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_err("%s: Issue stop stream for codec_dai due to op failure %d = ret\n",
+ __func__, ret);
+ snd_soc_dapm_stream_event(rtd,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
+ }
mutex_unlock(&rtd->pcm_mutex);
return ret;
}