Merge "ASoC: qdsp6v2: Fixed AAC dual-mono param_size"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 4e3abc2..a0b2f6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,12 @@
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
- the power of qcom,pvs-fuse[num-of-bits]. The location or
- 0-based index of an element in the list corresponds
- to the bin number. The value of each integer
- corresponds to the PVS process speed of the APC
- silicon for a chip with one of these cases:
- 1 = APC_PVS_SLOW
- 2 = APC_PVS_NOM
- 3 = APC_PVS_FAST
- 0 or other values = No PVS
+- qcom,pvs-init-voltage: A list of integers whose length is equal to 2
+ to the power of qcom,pvs-fuse[num-of-bits]. The
+ location or 0-based index of an element in the
+ list corresponds to the bin number. The value of
+ each integer corresponds to the initial voltage
+ of the PVS bin in turbo mode in microvolts.
- qcom,pvs-corner-ceiling-slow: Ceiling voltages of all corners for APC_PVS_SLOW
- qcom,pvs-corner-ceiling-nom: Ceiling voltages of all corners for APC_PVS_NOM
- qcom,pvs-corner-ceiling-fast: Ceiling voltages of all corners for APC_PVS_FAST
@@ -155,8 +151,14 @@
qcom,pvs-fuse-redun-sel = <22 24 3 2>;
qcom,pvs-fuse-redun = <22 27 5>;
- qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
- 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
+ 1310000 1300000 1290000 1280000
+ 1270000 1260000 1250000 1240000
+ 1230000 1220000 1210000 1200000
+ 1190000 1180000 1170000 1160000
+ 1150000 1140000 1140000 1140000
+ 1140000 1140000 1140000 1140000
+ 1140000 1140000 1140000 1140000>;
qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 8fd813c..4f9307a 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -18,10 +18,14 @@
- synaptics,button-map : virtual key code mappings to be used
- synaptics,x-flip : modify orientation of the x axis
- synaptics,y-flip : modify orientation of the y axis
- - synaptics,panel-x : panel x dimension
- - synaptics,panel-y : panel y dimension
+ - synaptics,panel-coords : touch panel min x, min y, max x and
+ max y resolution
+ - synaptics,display-coords : display min x, min y, max x and
+ max y resolution
+ - synaptics,reset-delay : reset delay for controller (ms), default 100
- synaptics,fw-image-name : name of firmware .img file in /etc/firmware
- synaptics,power-down : fully power down regulators in suspend
+ - synaptics,do-lockdown : perform one time lockdown procedure
Example:
i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
index 95be46c..3bb63de 100644
--- a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
@@ -18,6 +18,8 @@
- qcom,channel-id: channel Id for the PWM.
Optional device bindings:
+- qcom,force-pwm-size: For certain LPG channels, PWM size can be forced.
+ Possible values 6, 7, 8 and 9.
- qcom,channel-owner: A string value to supply owner information.
- qcom,mode-select: 0 = PWM mode
1 = LPG mode
@@ -110,6 +112,7 @@
<0xb040 0x80>;
reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
qcom,channel-id = <1>;
+ qcom,force-pwm-size = <9>;
qcom,period = <6000000>;
status = "okay";
qcom,pwm {
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 7ca741c..24f21b4 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -7,7 +7,8 @@
- interrupt-names : Required interrupt resource entries are:
"core_irq" : Interrupt for HSIC core
- <supply-name>-supply: handle to the regulator device tree node
- Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+ Required "supply-name" is either "hsic_vdd_dig" or "HSIC_VDDCX" and
+ optionally - "HSIC_GDSC".
Optional properties :
- interrupt-parent - This must provide reference to the current
@@ -81,6 +82,9 @@
the reset and enumeration. Since some devices might take more than 100ms
for initialization when receiving the bus reset, add delay to avoid the
problem that enmueration is before device initialization done.
+- hsic,vdd-voltage-level: This property must be a list of three integer
+ values (no, min, max) where each value represents either a voltage in
+ microvolts or a value corresponding to voltage corner
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
@@ -104,7 +108,7 @@
1 &intc 0 148 0
2 &msmgpio 144 0x8>;
interrupt-names = "core_irq", "async_irq", "wakeup";
- HSIC_VDDCX-supply = <&pm8019_l12>;
+ hsic_vdd_dig-supply = <&pm8841_s2_corner>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -113,6 +117,7 @@
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
hsic,consider-ipa-handshake;
+ hsic,vdd-voltage-level = <1 5 7>;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 44ed2dc..e7eae76 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -130,7 +130,8 @@
- interrupt-names : Required interrupt resource entries are:
HSUSB EHCI expects "core_irq" and optionally "async_irq".
- <supply-name>-supply: handle to the regulator device tree node
- Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+ Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+ "HSUSB_1p8-supply" "HSUSB_3p3-supply".
- qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
Optional properties :
@@ -138,6 +139,15 @@
- qcom,resume-gpio: if present then peripheral connected to usb controller
cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
gpio to wakeup peripheral.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+ values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+ either a voltage in microvolts or a value corresponding to voltage corner.
+ First value represents value to vote when USB is not at all active, second
+ value represents value to vote when target is not connected to dock during low
+ power mode, third value represents vlaue to vote when target is connected to dock
+ and no peripheral connected over dock during low power mode, fourth value represents
+ minimum value to vote when USB is operational, fifth item represents maximum value
+ to vote for USB is operational.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
@@ -145,11 +155,12 @@
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>, <0 140 0>;
interrupt-names = "core_irq", "async_irq";
- HSUSB_VDDCX-supply = <&pm8841_s2>;
+ hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
qcom,usb2-enable-hsphy2;
qcom,usb2-power-budget = <500>;
+ qcom,vdd-voltage-level = <1 2 3 5 7>;
};
ANDROID USB:
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 46f5f22..60bb518 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -84,7 +84,7 @@
1 &intc 0 148 0
2 &msmgpio 144 0x8>;
interrupt-names = "core_irq", "async_irq", "wakeup";
- HSIC_VDDCX-supply = <&pm8841_s2>;
+ hsic_vdd_dig-supply = <&pm8841_s2_corner>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -92,6 +92,7 @@
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
qcom,phy-susp-sof-workaround;
+ hsic,vdd-voltage-level = <1 5 7>;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 8314fab..2b75fa2 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -55,3 +55,8 @@
status = "ok";
};
+&ehci {
+ hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+ qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
+
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1820dc7..6969940 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -315,7 +315,7 @@
qcom,v-cutoff-uv = <3400000>;
qcom,max-voltage-uv = <4200000>;
qcom,r-conn-mohm = <0>;
- qcom,shutdown-soc-valid-limit = <20>;
+ qcom,shutdown-soc-valid-limit = <100>;
qcom,adjust-soc-low-threshold = <15>;
qcom,ocv-voltage-high-threshold-uv = <3750000>;
qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 5642d4d..5734b9c 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -189,7 +189,7 @@
qcom,v-cutoff-uv = <3400000>;
qcom,max-voltage-uv = <4200000>;
qcom,r-conn-mohm = <0>;
- qcom,shutdown-soc-valid-limit = <20>;
+ qcom,shutdown-soc-valid-limit = <100>;
qcom,adjust-soc-low-threshold = <15>;
qcom,ocv-voltage-high-threshold-uv = <3750000>;
qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 583cd3c..98d2f5e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -120,7 +120,7 @@
qcom,v-cutoff-uv = <3400000>;
qcom,max-voltage-uv = <4200000>;
qcom,r-conn-mohm = <0>;
- qcom,shutdown-soc-valid-limit = <20>;
+ qcom,shutdown-soc-valid-limit = <100>;
qcom,adjust-soc-low-threshold = <15>;
qcom,ocv-voltage-high-threshold-uv = <3750000>;
qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 3a18514..53e0578 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -238,7 +238,7 @@
qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,clk-rates = <400000 25000000 50000000>;
#address-cells = <0>;
interrupt-parent = <&sdhc_2>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 415912f..838592c 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -41,8 +41,13 @@
qcom,pvs-fuse = <22 6 5>;
qcom,pvs-fuse-redun = <22 27 5>;
- qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
- 2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+ qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+ 1275000 1260000 1245000 1230000 1215000
+ 1200000 1185000 1170000 1155000 1140000
+ 1140000 1140000 1140000 1140000 1140000
+ 1150000 1140000 1140000 1140000 1140000
+ 1140000 1140000 1140000 1275000 1275000
+ 1275000 1275000>;
qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 8f22ceb..a57adcd 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -33,27 +33,32 @@
&pm8226_l3 {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1337500>;
};
&pm8226_l3_ao {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1337500>;
};
&pm8226_l3_so {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1337500>;
};
&pm8226_s2 {
regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1280000>;
+ regulator-max-microvolt = <1330000>;
};
&apc_vreg_corner {
- qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
- 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
+ qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
+ 1300000 1290000 1280000 1270000 1260000
+ 1250000 1240000 1230000 1220000 1210000
+ 1200000 1190000 1180000 1170000 1160000
+ 1150000 1140000 1140000 1140000 1140000
+ 1140000 1140000 1140000 1140000 1140000
+ 1140000 1140000>;
qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 22d6948..483aad1 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -33,7 +33,7 @@
adsp_mem: adsp_region {
linux,contiguous-region;
- reg = <0 0xc00000>;
+ reg = <0 0x2a00000>;
label = "adsp_mem";
};
@@ -201,6 +201,12 @@
};
};
+ qcom,vidc {
+ compatible = "qcom,msm-vidc";
+ qcom,hfi = "q6";
+ qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
+ };
+
qcom,wfd {
compatible = "qcom,msm-wfd";
};
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index 1b4a594..e133117 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -38,6 +38,78 @@
qcom,cci-master = <0>;
};
+ eeprom0: qcom,eeprom@6a {
+ cell-index = <0>;
+ reg = <0x6a 0x0>;
+ qcom,eeprom-name = "truly_cm7700";
+ compatible = "qcom,msm_eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,num-blocks = <9>;
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0 1 1>;
+ qcom,mem0 = <0 0x0 2 0 1 0>;
+ qcom,page1 = <1 0x3d84 2 0x8 1 1>;
+ qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll1 = <0 0x0 2 0 1 1>;
+ qcom,mem1 = <32 0x3d00 2 0 1 0>;
+ qcom,page2 = <1 0x3d84 2 0x9 1 1>;
+ qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll2 = <0 0x0 2 0 1 1>;
+ qcom,mem2 = <32 0x3d00 2 0 1 0>;
+ qcom,page3 = <1 0x3d84 2 0xa 1 1>;
+ qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll3 = <0 0x0 2 0 1 1>;
+ qcom,mem3 = <32 0x3d00 2 0 1 0>;
+ qcom,page4 = <1 0x3d84 2 0xb 1 1>;
+ qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll4 = <0 0x0 2 0 1 1>;
+ qcom,mem4 = <32 0x3d00 2 0 1 0>;
+ qcom,page5 = <1 0x3d84 2 0xc 1 1>;
+ qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll5 = <0 0x0 2 0 1 1>;
+ qcom,mem5 = <32 0x3d00 2 0 1 0>;
+ qcom,page6 = <1 0x3d84 2 0xd 1 1>;
+ qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll6 = <0 0x0 2 0 1 1>;
+ qcom,mem6 = <32 0x3d00 2 0 1 0>;
+ qcom,page7 = <1 0x3d84 2 0xe 1 1>;
+ qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0 1 1>;
+ qcom,mem7 = <32 0x3d00 2 0 1 0>;
+ qcom,page8 = <1 0x3d84 2 0xf 1 1>;
+ qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll8 = <0 0x0 2 0 1 1>;
+ qcom,mem8 = <32 0x3d00 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8110_l2>;
+ cam_vio-supply = <&pm8110_l14>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+ qcom,cam-vreg-type = <0 0 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 1800000>;
+ qcom,cam-vreg-max-voltage = <1200000 1800000>;
+ qcom,cam-vreg-op-mode = <200000 8000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 13 0>,
+ <&msmgpio 21 0>,
+ <&msmgpio 20 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,cam-power-seq-type = "sensor_vreg",
+ "sensor_vreg", "sensor_clk",
+ "sensor_gpio", "sensor_gpio";
+ qcom,cam-power-seq-val = "cam_vdig",
+ "cam_vio", "sensor_cam_mclk",
+ "sensor_gpio_reset",
+ "sensor_gpio_standby";
+ qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+ qcom,cam-power-seq-delay = <1 1 5 5 10>;
+ };
+
qcom,camera@6f {
compatible = "qcom,ov8825";
reg = <0x6f>;
@@ -46,6 +118,7 @@
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 = <&pm8110_l2>;
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 1929b50..eb69678 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -42,10 +42,15 @@
qcom,pvs-fuse = <23 6 5>;
qcom,pvs-fuse-redun = <61 47 5>;
- qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
- 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
- qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
+ qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000 1275000 1275000 1275000
+ 1275000 1275000>;
+ qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <1075000 1075000 1200000>;
qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 2a619db..4a2de1c 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -168,6 +168,7 @@
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<2 216>, /* tsens_upper_lower_int */
+ <41 63>, /* dino_gen_purpose_irq35 */
<0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */
<0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */
<0xff 35>, /* WDT_barkInt */
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 257d7a4..079f0b1 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -170,6 +170,7 @@
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<2 216>, /* tsens_upper_lower_int */
+ <41 63>, /* dino_gen_purpose_irq35 */
<0xff 56>, /* q6_wdog_expired_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 5893a9b..2ab272a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -48,28 +48,33 @@
&pm8226_l3 {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1350000>;
};
&pm8226_l3_ao {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1350000>;
};
&pm8226_l3_so {
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1287500>;
+ regulator-max-microvolt = <1350000>;
};
&pm8226_s2 {
regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1280000>;
+ regulator-max-microvolt = <1350000>;
};
&apc_vreg_corner {
- qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
- 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
- qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+ qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
+ 1300000 1290000 1280000 1270000 1260000
+ 1250000 1240000 1230000 1220000 1210000
+ 1200000 1190000 1180000 1170000 1160000
+ 1150000 1140000 1140000 1140000 1140000
+ 1140000 1140000 1140000 1140000 1140000
+ 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
qcom,cpr-step-quotient = <30>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index d200100..d6c7272 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -227,7 +227,7 @@
1 &intc 0 148 0
2 &msmgpio 144 0x8>;
interrupt-names = "core_irq", "async_irq", "wakeup";
- HSIC_VDDCX-supply = <&pm8841_s2>;
+ hsic_vdd_dig-supply = <&pm8841_s2_corner>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -236,6 +236,7 @@
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
qcom,phy-susp-sof-workaround;
+ hsic,vdd-voltage-level = <1 5 7>;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 73aba8f..67e1802 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -397,7 +397,7 @@
1 &intc 0 148 0
2 &msmgpio 144 0x8>;
interrupt-names = "core_irq", "async_irq", "wakeup";
- HSIC_VDDCX-supply = <&pm8841_s2>;
+ hsic_vdd_dig-supply = <&pm8841_s2_corner>;
HSIC_GDSC-supply = <&gdsc_usb_hsic>;
hsic,strobe-gpio = <&msmgpio 144 0x00>;
hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -405,6 +405,7 @@
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
qcom,phy-susp-sof-workaround;
+ hsic,vdd-voltage-level = <1 5 7>;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index c3fd98d..071c7c9 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -26,6 +26,8 @@
&ehci {
status = "ok";
vbus-supply = <&usb2_otg_sw>;
+ hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+ qcom,vdd-voltage-level = <1 2 3 5 7>;
};
&hsic_host {
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 970c03f..1a197a3 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -286,6 +286,7 @@
CONFIG_OV5648=y
CONFIG_MSM_CAMERA_SENSOR=y
# CONFIG_MSM_CPP is not set
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSI22_HEADER=y
CONFIG_MSM_CSIPHY=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 54b1c14..8238414 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -286,6 +286,7 @@
CONFIG_HI256=y
CONFIG_OV12830=y
CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
CONFIG_MSM_CCI=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87e3e5b..696ddf9 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1761,6 +1761,16 @@
help
SMD Transport Layer for IPC Router
+config MSM_IPC_ROUTER_HSIC_XPRT
+ depends on USB_QCOM_IPC_BRIDGE
+ depends on MSM_IPC_ROUTER
+ bool "MSM HSIC XPRT Layer"
+ help
+ HSIC Transport Layer that enables off-chip communication of
+ IPC Router. When the HSIC endpoint becomes available, this layer
+ registers the transport with IPC Router and enable message
+ exchange.
+
config MSM_IPC_ROUTER_SECURITY
depends on MSM_IPC_ROUTER
bool "MSM IPC Router Security support"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 89eb589..dd533f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -130,6 +130,7 @@
obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 59c682f..9ea00c1 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -106,7 +106,23 @@
{ 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
{ 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
{ 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
- /* No support for 1p5 GHz yet */
+ { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 0 }
+};
+
+static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
+ { 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
+ { 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
+ { 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 7 },
+ { 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1094400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1190400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1305600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1344000, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1401600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1497600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
+ { 1, 1593600, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
{ 0 }
};
@@ -125,8 +141,9 @@
[6] = acpu_freq_tbl_8226_1p2,
[2] = acpu_freq_tbl_8226_1p4,
[5] = acpu_freq_tbl_8226_1p4,
- [3] = acpu_freq_tbl_8226_1p5,
[4] = acpu_freq_tbl_8226_1p5,
+ [7] = acpu_freq_tbl_8226_1p5,
+ [1] = acpu_freq_tbl_8226_1p6,
};
static struct acpuclk_drv_data drv_data = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index ba792ab..1999379 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2829,6 +2829,8 @@
F_APCS_PLL(1305600000, 68, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1344000000, 70, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1401600000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1593600000, 83, 0x0, 0x1, 0x0, 0x0, 0x0),
PLL_F_END
};
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 92dab97..33dcd9f 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3026,11 +3026,13 @@
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"),
+ CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006a"),
/* CSIPHY clocks */
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index b69b155..59e0e2a 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -148,7 +148,7 @@
void __iomem *efuse_base;
/* Process voltage parameters */
- u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+ u32 pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
@@ -999,6 +999,7 @@
u64 efuse_bits;
int rc, process;
u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+ u32 init_v;
bool redundant;
size_t pvs_bins;
@@ -1034,25 +1035,35 @@
((1 << pvs_fuse[2]) - 1);
pvs_bins = 1 << pvs_fuse[2];
- rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
- cpr_vreg->pvs_bin_process,
- pvs_bins);
+
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
+ cpr_vreg->pvs_init_v, pvs_bins);
if (rc < 0) {
- pr_err("pvs-bin-process missing: rc=%d\n", rc);
+ pr_err("pvs-init-voltage missing: rc=%d\n", rc);
return rc;
}
- process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
- pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)\n",
- pvs_fuse[0], efuse_bits, pvs_fuse[2],
- cpr_vreg->pvs_bin, process);
+ init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
+ for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
+ if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+ break;
+ }
- if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
- pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
- cpr_vreg->pvs_bin, process);
+ if (process == APC_PVS_NO) {
+ process = APC_PVS_SLOW;
+ cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+ cpr_vreg->ceiling_max = init_v;
+ } else if (process == APC_PVS_FAST &&
+ init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
process = APC_PVS_SLOW;
}
+ pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
+ pvs_fuse[0], efuse_bits, pvs_fuse[2],
+ cpr_vreg->pvs_bin, process);
+ pr_info("pvs initial turbo voltage_= from %u to %u\n",
+ init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+
cpr_vreg->process = process;
return 0;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6fe945c..ce66531 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -298,6 +298,8 @@
pr_err("%s: failure\n", __func__);
return NULL;
}
+ memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+ /* TODO: Copy optional headers, if available */
pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!pkt_fragment_q) {
@@ -323,6 +325,7 @@
kfree_skb(temp_skb);
}
kfree(pkt_fragment_q);
+ /* TODO: Free optional headers, if present */
kfree(cloned_pkt);
return NULL;
}
@@ -361,6 +364,7 @@
kfree_skb(temp_skb);
}
kfree(pkt->pkt_fragment_q);
+ /* TODO: Free Optional headers, if present */
kfree(pkt);
return;
}
@@ -373,6 +377,8 @@
int first = 1, offset = 0;
int skb_size, data_size;
void *data;
+ int last = 1;
+ int align_size;
skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!skb_head) {
@@ -382,10 +388,13 @@
skb_queue_head_init(skb_head);
data_size = buf_len;
+ align_size = ALIGN_SIZE(data_size);
while (offset != buf_len) {
skb_size = data_size;
if (first)
skb_size += IPC_ROUTER_HDR_SIZE;
+ if (last)
+ skb_size += align_size;
skb = alloc_skb(skb_size, GFP_KERNEL);
if (!skb) {
@@ -394,6 +403,7 @@
goto buf_to_skb_error;
}
data_size = data_size / 2;
+ last = 0;
continue;
}
@@ -407,6 +417,7 @@
skb_queue_tail(skb_head, skb);
offset += data_size;
data_size = buf_len - offset;
+ last = 1;
}
return skb_head;
@@ -447,7 +458,7 @@
return buf;
}
-static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
{
struct sk_buff *temp_skb;
@@ -461,6 +472,328 @@
kfree(skb_head);
}
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+ if (!pkt || !skb) {
+ pr_err("%s: Invalid pkt or skb\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+ skb_pull(skb, sizeof(struct rr_header_v1));
+ pkt->length -= sizeof(struct rr_header_v1);
+ return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+ struct rr_header_v2 *hdr;
+
+ if (!pkt || !skb) {
+ pr_err("%s: Invalid pkt or skb\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr = (struct rr_header_v2 *)skb->data;
+ pkt->hdr.version = (uint32_t)hdr->version;
+ pkt->hdr.type = (uint32_t)hdr->type;
+ pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+ pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+ pkt->hdr.size = (uint32_t)hdr->size;
+ pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+ pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+ pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+ skb_pull(skb, sizeof(struct rr_header_v2));
+ pkt->length -= sizeof(struct rr_header_v2);
+ return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+ struct sk_buff *temp_skb;
+ int ret;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (temp_skb->data[0] == IPC_ROUTER_V1) {
+ ret = extract_header_v1(pkt, temp_skb);
+ } else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+ ret = extract_header_v2(pkt, temp_skb);
+ /* TODO: Extract optional headers if present */
+ } else {
+ pr_err("%s: Invalid Header version %02x\n",
+ __func__, temp_skb->data[0]);
+ print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+ 16, 1, temp_skb->data, pkt->length, true);
+ return -EINVAL;
+ }
+ return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ * starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+ struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+ int hdr_size = 0;
+ int xprt_version = 0;
+ struct msm_ipc_routing_table_entry *rt_entry;
+ struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!xprt_info) {
+ rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+ if (!rt_entry || !(rt_entry->xprt_info)) {
+ pr_err("%s: Node %d is not up\n",
+ __func__, pkt->hdr.dst_node_id);
+ return -ENODEV;
+ }
+
+ xprt_info = rt_entry->xprt_info;
+ }
+ if (xprt_info)
+ xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+ if (xprt_version == IPC_ROUTER_V1) {
+ pkt->hdr.version = IPC_ROUTER_V1;
+ hdr_size = sizeof(struct rr_header_v1);
+ } else if (xprt_version == IPC_ROUTER_V2) {
+ pkt->hdr.version = IPC_ROUTER_V2;
+ hdr_size = sizeof(struct rr_header_v2);
+ /* TODO: Calculate optional header length, if present */
+ } else {
+ pr_err("%s: Invalid xprt_version %d\n",
+ __func__, xprt_version);
+ hdr_size = -EINVAL;
+ }
+
+ return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+ struct sk_buff *temp_skb;
+ struct rr_header_v1 *hdr;
+
+ if (!pkt || hdr_size <= 0) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(temp_skb) < hdr_size) {
+ temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+ if (!temp_skb) {
+ pr_err("%s: Could not allocate SKB of size %d\n",
+ __func__, hdr_size);
+ return -ENOMEM;
+ }
+ }
+
+ hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+ memcpy(hdr, &pkt->hdr, hdr_size);
+ if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+ skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+ pkt->length += hdr_size;
+ return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+ struct sk_buff *temp_skb;
+ struct rr_header_v2 *hdr;
+
+ if (!pkt || hdr_size <= 0) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(temp_skb) < hdr_size) {
+ temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+ if (!temp_skb) {
+ pr_err("%s: Could not allocate SKB of size %d\n",
+ __func__, hdr_size);
+ return -ENOMEM;
+ }
+ }
+
+ hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+ hdr->version = (uint8_t)pkt->hdr.version;
+ hdr->type = (uint8_t)pkt->hdr.type;
+ hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+ hdr->size = (uint32_t)pkt->hdr.size;
+ hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+ hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+ hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+ hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+ /* TODO: Add optional headers, if present */
+ if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+ skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+ pkt->length += hdr_size;
+ return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+ struct msm_ipc_router_xprt_info *xprt_info)
+{
+ int hdr_size;
+ struct sk_buff *temp_skb;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr_size = calc_tx_header_size(pkt, xprt_info);
+ if (hdr_size <= 0)
+ return hdr_size;
+
+ if (pkt->hdr.version == IPC_ROUTER_V1)
+ return prepend_header_v1(pkt, hdr_size);
+ else if (pkt->hdr.version == IPC_ROUTER_V2)
+ return prepend_header_v2(pkt, hdr_size);
+ else
+ return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+ struct sk_buff *dst_skb, *src_skb, *temp_skb;
+ int offset = 0, buf_len = 0, copy_len;
+ void *buf;
+ int align_size;
+
+ if (!pkt || pkt->length <= 0) {
+ pr_err("%s: Invalid PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+ return 0;
+
+ align_size = ALIGN_SIZE(pkt->length);
+ dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+ if (!dst_skb) {
+ pr_err("%s: could not allocate one skb of size %d\n",
+ __func__, pkt->length);
+ return -ENOMEM;
+ }
+ buf = skb_put(dst_skb, pkt->length);
+ buf_len = pkt->length;
+
+ skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+ copy_len = buf_len < src_skb->len ? buf_len : src_skb->len;
+ memcpy(buf + offset, src_skb->data, copy_len);
+ offset += copy_len;
+ buf_len -= copy_len;
+ }
+
+ while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+ temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+ kfree_skb(temp_skb);
+ }
+ skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+ return 0;
+}
+
static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
struct rr_packet *pkt, int clone)
{
@@ -515,7 +848,7 @@
down_read(&local_ports_lock_lha2);
do {
next_port_id++;
- if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+ if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
next_port_id = 1;
key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -932,7 +1265,7 @@
{
struct rr_packet *pkt;
struct sk_buff *ipc_rtr_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
int pkt_size;
void *data;
struct sk_buff_head *pkt_fragment_q;
@@ -973,32 +1306,33 @@
skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
data = skb_put(ipc_rtr_pkt, sizeof(*msg));
memcpy(data, msg, sizeof(*msg));
- hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: skb_push failed\n", __func__);
- kfree_skb(ipc_rtr_pkt);
- kfree(pkt_fragment_q);
- kfree(pkt);
- return -ENOMEM;
- }
+ skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+ pkt->pkt_fragment_q = pkt_fragment_q;
+ pkt->length = sizeof(*msg);
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = msg->cmd;
hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
hdr->src_port_id = IPC_ROUTER_ADDRESS;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->size = sizeof(*msg);
if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
hdr->dst_node_id = dst_node_id;
else
hdr->dst_node_id = xprt_info->remote_node_id;
hdr->dst_port_id = IPC_ROUTER_ADDRESS;
- skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
- pkt->pkt_fragment_q = pkt_fragment_q;
- pkt->length = pkt_size;
mutex_lock(&xprt_info->tx_lock_lhb2);
- ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+ ret = prepend_header(pkt, xprt_info);
+ if (ret < 0) {
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
+ pr_err("%s: Prepend Header failed\n", __func__);
+ release_pkt(pkt);
+ return ret;
+ }
+
+ ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock_lhb2);
release_pkt(pkt);
@@ -1074,7 +1408,7 @@
{
struct rr_packet *pkt;
struct sk_buff *ipc_rtr_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
int pkt_size;
void *data;
struct sk_buff_head *pkt_fragment_q;
@@ -1094,7 +1428,7 @@
}
skb_queue_head_init(pkt_fragment_q);
- pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+ pkt_size = sizeof(*msg);
ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
if (!ipc_rtr_pkt) {
pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1103,22 +1437,14 @@
return -ENOMEM;
}
- skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
data = skb_put(ipc_rtr_pkt, sizeof(*msg));
memcpy(data, msg, sizeof(*msg));
- hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: skb_push failed\n", __func__);
- kfree_skb(ipc_rtr_pkt);
- kfree(pkt_fragment_q);
- kfree(pkt);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = msg->cmd;
hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
hdr->src_port_id = IPC_ROUTER_ADDRESS;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->size = sizeof(*msg);
hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1164,70 +1490,60 @@
return 0;
}
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
- struct rr_packet *pkt)
-{
- struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
- if (!xprt_info || !pkt)
- return -EINVAL;
-
- down_read(&xprt_info_list_lock_lha5);
- list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
- mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
- if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
- fwd_xprt_info->xprt->write(pkt, pkt->length,
- fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
- }
- up_read(&xprt_info_list_lock_lha5);
- return 0;
-}
-
static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_packet *pkt)
{
- uint32_t dst_node_id;
- struct sk_buff *head_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_router_xprt_info *fwd_xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
int ret = 0;
+ int fwd_xprt_option;
if (!xprt_info || !pkt)
return -EINVAL;
- head_pkt = skb_peek(pkt->pkt_fragment_q);
- if (!head_pkt)
- return -EINVAL;
-
- hdr = (struct rr_header *)head_pkt->data;
- dst_node_id = hdr->dst_node_id;
+ hdr = &(pkt->hdr);
down_read(&routing_table_lock_lha3);
- rt_entry = lookup_routing_table(dst_node_id);
+ rt_entry = lookup_routing_table(hdr->dst_node_id);
if (!(rt_entry) || !(rt_entry->xprt_info)) {
- up_read(&routing_table_lock_lha3);
pr_err("%s: Routing table not initialized\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
+ goto fm_error1;
}
down_read(&rt_entry->lock_lha4);
fwd_xprt_info = rt_entry->xprt_info;
+ ret = prepend_header(pkt, fwd_xprt_info);
+ if (ret < 0) {
+ pr_err("%s: Prepend Header failed\n", __func__);
+ goto fm_error2;
+ }
+ fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+ if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+ ret = defragment_pkt(pkt);
+ if (ret < 0)
+ goto fm_error2;
+ }
+
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
pr_err("%s: Discarding Command to route back\n", __func__);
ret = -EINVAL;
- goto fwd_msg_out;
+ goto fm_error3;
}
if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
pr_err("%s: DST in the same cluster\n", __func__);
- goto fwd_msg_out;
+ ret = 0;
+ goto fm_error3;
}
- mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
up_read(&rt_entry->lock_lha4);
+fm_error1:
up_read(&routing_table_lock_lha3);
return ret;
@@ -1470,7 +1786,7 @@
}
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
- struct rr_header *hdr)
+ struct rr_header_v1 *hdr)
{
int i, rc = 0;
union rr_control_msg ctl;
@@ -1508,7 +1824,7 @@
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
- ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+ ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
IPC_ROUTER_DUMMY_DEST_NODE);
if (rc < 0) {
@@ -1654,7 +1970,7 @@
* to the cluster from which this message is received. Notify the
* local clients waiting for this service.
*/
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
return 0;
}
@@ -1677,7 +1993,7 @@
* belong to the cluster from which this message is received.
* Notify the local clients communicating with the service.
*/
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
}
up_write(&server_list_lock_lha2);
@@ -1697,7 +2013,7 @@
msm_ipc_router_destroy_remote_port(rport_ptr);
up_write(&routing_table_lock_lha3);
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
return 0;
}
@@ -1707,26 +2023,20 @@
{
union rr_control_msg *msg;
int rc = 0;
- struct sk_buff *temp_ptr;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
- if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+ if (pkt->length != sizeof(*msg)) {
pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
- (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+ sizeof(*msg));
return -EINVAL;
}
- temp_ptr = skb_peek(pkt->pkt_fragment_q);
- if (!temp_ptr) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- return -EINVAL;
+ hdr = &(pkt->hdr);
+ msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+ if (!msg) {
+ pr_err("%s: Error extracting control msg\n", __func__);
+ return -ENOMEM;
}
- hdr = (struct rr_header *)temp_ptr->data;
- if (!hdr) {
- pr_err("%s: No data inside the skb\n", __func__);
- return -EINVAL;
- }
- msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
switch (msg->cmd) {
case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1752,17 +2062,17 @@
RR("o UNKNOWN(%08x)\n", msg->cmd);
rc = -ENOSYS;
}
-
+ kfree(msg);
return rc;
}
static void do_read_data(struct work_struct *work)
{
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct rr_packet *pkt = NULL;
struct msm_ipc_port *port_ptr;
- struct sk_buff *head_skb;
struct msm_ipc_router_remote_port *rport_ptr;
+ int ret;
struct msm_ipc_router_xprt_info *xprt_info =
container_of(work,
@@ -1777,24 +2087,15 @@
goto fail_data;
}
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: head_skb is invalid\n", __func__);
+ ret = extract_header(pkt);
+ if (ret < 0)
goto fail_data;
- }
-
- hdr = (struct rr_header *)(head_skb->data);
+ hdr = &(pkt->hdr);
RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
hdr->version, hdr->type, hdr->src_node_id,
- hdr->src_port_id, hdr->confirm_rx, hdr->size,
+ hdr->src_port_id, hdr->control_flag, hdr->size,
hdr->dst_node_id, hdr->dst_port_id);
- if (hdr->version != IPC_ROUTER_VERSION) {
- pr_err("version %d != %d\n",
- hdr->version, IPC_ROUTER_VERSION);
- goto fail_data;
- }
-
if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
(hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1803,8 +2104,7 @@
continue;
}
- if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
- (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+ if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
process_control_msg(xprt_info, pkt);
release_pkt(pkt);
continue;
@@ -1819,7 +2119,7 @@
(hdr->src_port_id & 0xffffff),
(hdr->dst_node_id << 24) |
(hdr->dst_port_id & 0xffffff),
- (hdr->type << 24) | (hdr->confirm_rx << 16) |
+ (hdr->type << 24) | (hdr->control_flag << 16) |
(hdr->size & 0xffff));
}
#endif
@@ -1906,6 +2206,7 @@
ctl.srv.port_id = port_ptr->this_port.port_id;
up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
+ broadcast_ctl_msg_locally(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
port_ptr->mode_info.mode = MULTI_LINK_MODE;
@@ -1957,6 +2258,7 @@
port_ptr->this_port.port_id);
up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
+ broadcast_ctl_msg_locally(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = CLIENT_PORT;
spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1967,8 +2269,7 @@
uint32_t port_id,
struct sk_buff_head *data)
{
- struct sk_buff *head_skb;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_port *port_ptr;
struct rr_packet *pkt;
int ret_len;
@@ -1983,34 +2284,22 @@
pr_err("%s: New pkt create failed\n", __func__);
return -ENOMEM;
}
-
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- release_pkt(pkt);
- return -EINVAL;
- }
- hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: Prepend Header failed\n", __func__);
- release_pkt(pkt);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
hdr->src_node_id = src->this_port.node_id;
hdr->src_port_id = src->this_port.port_id;
hdr->size = pkt->length;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
hdr->dst_port_id = port_id;
- pkt->length += IPC_ROUTER_HDR_SIZE;
down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(port_id);
if (!port_ptr) {
pr_err("%s: Local port %d not present\n", __func__, port_id);
up_read(&local_ports_lock_lha2);
+ pkt->pkt_fragment_q = NULL;
release_pkt(pkt);
return -ENODEV;
}
@@ -2027,35 +2316,26 @@
struct msm_ipc_router_remote_port *rport_ptr,
struct rr_packet *pkt)
{
- struct sk_buff *head_skb;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_router_xprt_info *xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
struct msm_ipc_resume_tx_port *resume_tx_port;
+ struct sk_buff *temp_skb;
+ int xprt_option;
int ret;
+ int align_size;
if (!rport_ptr || !src || !pkt)
return -EINVAL;
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- return -EINVAL;
- }
- hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: Prepend Header failed\n", __func__);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
hdr->src_node_id = src->this_port.node_id;
hdr->src_port_id = src->this_port.port_id;
hdr->size = pkt->length;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->dst_node_id = rport_ptr->node_id;
hdr->dst_port_id = rport_ptr->port_id;
- pkt->length += IPC_ROUTER_HDR_SIZE;
mutex_lock(&rport_ptr->quota_lock_lhb2);
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2083,7 +2363,7 @@
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
- hdr->confirm_rx = 1;
+ hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
mutex_unlock(&rport_ptr->quota_lock_lhb2);
rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2094,6 +2374,25 @@
}
down_read(&rt_entry->lock_lha4);
xprt_info = rt_entry->xprt_info;
+ ret = prepend_header(pkt, xprt_info);
+ if (ret < 0) {
+ up_read(&rt_entry->lock_lha4);
+ pr_err("%s: Prepend Header failed\n", __func__);
+ return ret;
+ }
+ xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+ if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+ ret = defragment_pkt(pkt);
+ if (ret < 0) {
+ up_read(&rt_entry->lock_lha4);
+ return ret;
+ }
+ }
+
+ temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+ align_size = ALIGN_SIZE(pkt->length);
+ skb_put(temp_skb, align_size);
+ pkt->length += align_size;
mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2107,10 +2406,10 @@
RAW_HDR("[w rr_h] "
"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
- "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+ "control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
hdr->version, type_to_str(hdr->type),
hdr->src_node_id, hdr->src_port_id,
- hdr->confirm_rx, hdr->size,
+ hdr->control_flag, hdr->size,
hdr->dst_node_id, hdr->dst_port_id);
#if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2123,13 +2422,13 @@
(hdr->src_port_id & 0xffffff),
(hdr->dst_node_id << 24) |
(hdr->dst_port_id & 0xffffff),
- (hdr->type << 24) | (hdr->confirm_rx << 16) |
+ (hdr->type << 24) | (hdr->control_flag << 16) |
(hdr->size & 0xffff));
}
#endif
#endif
- return pkt->length;
+ return hdr->size;
}
int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2203,6 +2502,8 @@
ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
up_read(&routing_table_lock_lha3);
+ if (ret < 0)
+ pkt->pkt_fragment_q = NULL;
release_pkt(pkt);
return ret;
@@ -2222,11 +2523,10 @@
}
ret = msm_ipc_router_send_to(src, out_skb_head, dest);
- if (ret == -EAGAIN)
- return ret;
if (ret < 0) {
- pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
- __func__, ret);
+ if (ret != -EAGAIN)
+ pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+ __func__, ret);
msm_ipc_router_free_skb(out_skb_head);
return ret;
}
@@ -2248,7 +2548,7 @@
static int msm_ipc_router_send_resume_tx(void *data)
{
union rr_control_msg msg;
- struct rr_header *hdr = (struct rr_header *)data;
+ struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
struct msm_ipc_routing_table_entry *rt_entry;
int ret;
@@ -2278,14 +2578,12 @@
}
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **read_pkt,
size_t buf_len)
{
struct rr_packet *pkt;
- struct sk_buff *head_skb;
- int ret;
- if (!port_ptr || !data)
+ if (!port_ptr || !read_pkt)
return -EINVAL;
mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2295,26 +2593,19 @@
}
pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
- if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+ if ((buf_len) && (pkt->hdr.size > buf_len)) {
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -ETOOSMALL;
}
list_del(&pkt->list);
if (list_empty(&port_ptr->port_rx_q))
wake_unlock(&port_ptr->port_rx_wake_lock);
- *data = pkt->pkt_fragment_q;
- ret = pkt->length;
+ *read_pkt = pkt;
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
- kfree(pkt);
- head_skb = skb_peek(*data);
- if (!head_skb) {
- pr_err("%s: Socket Buffer not found", __func__);
- return -EFAULT;
- }
- if (((struct rr_header *)(head_skb->data))->confirm_rx)
- msm_ipc_router_send_resume_tx((void *)(head_skb->data));
+ if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+ msm_ipc_router_send_resume_tx(&pkt->hdr);
- return ret;
+ return pkt->length;
}
/**
@@ -2362,7 +2653,7 @@
/**
* msm_ipc_router_recv_from() - Recieve messages destined to a local port.
* @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
* @src: Pointer to local port address
* @timeout: < 0 timeout indicates infinite wait till a message arrives.
* > 0 timeout indicates the wait time.
@@ -2383,31 +2674,30 @@
* of bytes that are read.
*/
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
struct msm_ipc_addr *src,
long timeout)
{
int ret, data_len, align_size;
struct sk_buff *temp_skb;
- struct rr_header *hdr = NULL;
+ struct rr_header_v1 *hdr = NULL;
- if (!port_ptr || !data) {
+ if (!port_ptr || !pkt) {
pr_err("%s: Invalid pointers being passed\n", __func__);
return -EINVAL;
}
- *data = NULL;
+ *pkt = NULL;
ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
if (ret)
return ret;
- ret = msm_ipc_router_read(port_ptr, data, 0);
- if (ret <= 0 || !(*data))
+ ret = msm_ipc_router_read(port_ptr, pkt, 0);
+ if (ret <= 0 || !(*pkt))
return ret;
- temp_skb = skb_peek(*data);
- hdr = (struct rr_header *)(temp_skb->data);
+ hdr = &((*pkt)->hdr);
if (src) {
src->addrtype = MSM_IPC_ADDR_ID;
src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2415,10 +2705,9 @@
}
data_len = hdr->size;
- skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
align_size = ALIGN_SIZE(data_len);
if (align_size) {
- temp_skb = skb_peek_tail(*data);
+ temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
skb_trim(temp_skb, (temp_skb->len - align_size));
}
return data_len;
@@ -2429,11 +2718,10 @@
unsigned char **data,
unsigned int *len)
{
- struct sk_buff_head *in_skb_head;
+ struct rr_packet *pkt;
int ret;
- ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+ ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
if (ret < 0) {
if (ret != -ENOMSG)
pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2441,12 +2729,12 @@
return ret;
}
- *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+ *data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
if (!(*data))
pr_err("%s: Buf conversion failed\n", __func__);
*len = ret;
- msm_ipc_router_free_skb(in_skb_head);
+ release_pkt(pkt);
return 0;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..8ffd661 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
#include <net/sock.h>
/* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION 1
+#define IPC_ROUTER_V1 1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2 3
-#define IPC_ROUTER_CLIENT_BCAST_ID 0xffffffff
-#define IPC_ROUTER_ADDRESS 0xfffffffe
+#define IPC_ROUTER_ADDRESS 0x0000FFFF
#define IPC_ROUTER_NID_LOCAL 1
+#define MAX_IPC_PKT_SIZE 66000
#define IPC_ROUTER_CTRL_CMD_DATA 1
#define IPC_ROUTER_CTRL_CMD_HELLO 2
@@ -55,6 +60,11 @@
#define ALL_SERVICE 0xFFFFFFFF
#define ALL_INSTANCE 0xFFFFFFFF
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
enum {
CLIENT_PORT,
SERVER_PORT,
@@ -68,10 +78,22 @@
MULTI_LINK_MODE,
};
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
union rr_control_msg {
uint32_t cmd;
struct {
uint32_t cmd;
+ uint32_t magic;
+ uint32_t capability;
+ } hello;
+ struct {
+ uint32_t cmd;
uint32_t service;
uint32_t instance;
uint32_t node_id;
@@ -84,22 +106,67 @@
} cli;
};
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
uint32_t version;
uint32_t type;
uint32_t src_node_id;
uint32_t src_port_id;
- uint32_t confirm_rx;
+ uint32_t control_flag;
uint32_t size;
uint32_t dst_node_id;
uint32_t dst_port_id;
};
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+ uint8_t version;
+ uint8_t type;
+ uint16_t control_flag;
+ uint32_t size;
+ uint16_t src_node_id;
+ uint16_t src_port_id;
+ uint16_t dst_node_id;
+ uint16_t dst_port_id;
+} __attribute__((__packed__));
+union rr_header {
+ struct rr_header_v1 hdr_v1;
+ struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
struct rr_packet {
struct list_head list;
+ struct rr_header_v1 hdr;
struct sk_buff_head *pkt_fragment_q;
uint32_t length;
};
@@ -110,11 +177,28 @@
void *default_pil;
};
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ * event is complete.
+ */
struct msm_ipc_router_xprt {
char *name;
uint32_t link_id;
void *priv;
+ int (*get_version)(struct msm_ipc_router_xprt *xprt);
+ int (*get_option)(struct msm_ipc_router_xprt *xprt);
int (*read_avail)(struct msm_ipc_router_xprt *xprt);
int (*read)(void *data, uint32_t len,
struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
struct sk_buff_head *data,
struct msm_ipc_addr *dest);
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
size_t buf_len);
int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
struct msm_ipc_addr *src_addr,
long timeout);
int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
@@ -173,4 +257,5 @@
static inline void msm_ipc_unload_default_node(void *pil) { }
#endif
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);
#endif
diff --git a/arch/arm/mach-msm/ipc_router_hsic_xprt.c b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
new file mode 100644
index 0000000..0427c1c
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER HSIC XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/ipc_bridge.h>
+#include <mach/subsystem_restart.h>
+
+#include "ipc_router.h"
+
+static int msm_ipc_router_hsic_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_hsic_xprt_debug_mask) \
+ pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define NUM_HSIC_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
+ * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ * by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_hsic_xprt {
+ struct msm_ipc_router_xprt xprt;
+ struct platform_device *pdev;
+ struct workqueue_struct *hsic_xprt_wq;
+ struct delayed_work read_work;
+ struct rr_packet *in_pkt;
+ struct mutex ss_reset_lock;
+ int ss_reset;
+ struct completion sft_close_complete;
+ unsigned xprt_version;
+ unsigned xprt_option;
+};
+
+struct msm_ipc_router_hsic_xprt_work {
+ struct msm_ipc_router_xprt *xprt;
+ struct work_struct work;
+};
+
+static void hsic_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
+ * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_hsic_xprt_config {
+ char ch_name[XPRT_NAME_LEN];
+ char xprt_name[XPRT_NAME_LEN];
+ int hsic_pdev_id;
+ uint32_t link_id;
+ unsigned xprt_version;
+};
+
+struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
+ {"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
+};
+
+static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
+
+/**
+ * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
+ * @pdev: Platform device registered by HSIC's ipc_bridge driver
+ *
+ * @return: Index to the entry in the hsic_remote_xprt table if matching
+ * endpoint is found, < 0 on error.
+ *
+ * This function is used to find the configuration information specific to
+ * an HSIC endpoint from the hsic_remote_xprt table.
+ */
+static int find_hsic_xprt_cfg(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < NUM_HSIC_XPRTS; i++) {
+ /* TODO: Update the condition for multiple hsic links */
+ if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
+ return i;
+ }
+
+ return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
+ * supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_version(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+ return (int)hsic_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_option(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+ return (int)hsic_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_hsic_remote_write_avail(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct ipc_bridge_platform_data *pdata;
+ int write_avail;
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+ container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+ mutex_lock(&hsic_xprtp->ss_reset_lock);
+ if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
+ write_avail = 0;
+ } else {
+ pdata = hsic_xprtp->pdev->dev.platform_data;
+ write_avail = pdata->max_write_size;
+ }
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return write_avail;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_write(void *data,
+ uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+ struct rr_packet *pkt = (struct rr_packet *)data;
+ struct sk_buff *skb;
+ struct ipc_bridge_platform_data *pdata;
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+ int ret;
+
+ if (!pkt || pkt->length != len || !xprt) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+ mutex_lock(&hsic_xprtp->ss_reset_lock);
+ if (hsic_xprtp->ss_reset) {
+ pr_err("%s: Trying to write on a reset link\n", __func__);
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return -ENETRESET;
+ }
+
+ if (!hsic_xprtp->pdev) {
+ pr_err("%s: Trying to write on a closed link\n", __func__);
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return -ENODEV;
+ }
+
+ pdata = hsic_xprtp->pdev->dev.platform_data;
+ if (!pdata || !pdata->write) {
+ pr_err("%s on a uninitialized link\n", __func__);
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return -EFAULT;
+ }
+
+ skb = skb_peek(pkt->pkt_fragment_q);
+ if (!skb) {
+ pr_err("%s SKB is NULL\n", __func__);
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return -EINVAL;
+ }
+ D("%s: About to write %d bytes\n", __func__, len);
+ ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
+ if (ret == skb->len)
+ ret = len;
+ D("%s: Finished writing %d bytes\n", __func__, len);
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ return ret;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_close(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+ struct ipc_bridge_platform_data *pdata;
+
+ if (!xprt)
+ return -EINVAL;
+ hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+ mutex_lock(&hsic_xprtp->ss_reset_lock);
+ hsic_xprtp->ss_reset = 1;
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ flush_workqueue(hsic_xprtp->hsic_xprt_wq);
+ destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
+ pdata = hsic_xprtp->pdev->dev.platform_data;
+ if (pdata && pdata->close)
+ pdata->close(hsic_xprtp->pdev);
+ hsic_xprtp->pdev = NULL;
+ return 0;
+}
+
+/**
+ * hsic_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the HSIC
+ * endpoint, until the endpoint returns an error.
+ */
+static void hsic_xprt_read_data(struct work_struct *work)
+{
+ int pkt_size;
+ struct sk_buff *skb = NULL;
+ void *data;
+ struct ipc_bridge_platform_data *pdata;
+ struct delayed_work *rwork = to_delayed_work(work);
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+ container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
+
+ while (1) {
+ mutex_lock(&hsic_xprtp->ss_reset_lock);
+ if (hsic_xprtp->ss_reset) {
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ break;
+ }
+ pdata = hsic_xprtp->pdev->dev.platform_data;
+ mutex_unlock(&hsic_xprtp->ss_reset_lock);
+ while (!hsic_xprtp->in_pkt) {
+ hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+ GFP_KERNEL);
+ if (hsic_xprtp->in_pkt)
+ break;
+ pr_err("%s: packet allocation failure\n", __func__);
+ msleep(100);
+ }
+ while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
+ hsic_xprtp->in_pkt->pkt_fragment_q =
+ kmalloc(sizeof(struct sk_buff_head),
+ GFP_KERNEL);
+ if (hsic_xprtp->in_pkt->pkt_fragment_q)
+ break;
+ pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+ __func__);
+ msleep(100);
+ }
+ skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
+ D("%s: Allocated rr_packet\n", __func__);
+
+ while (!skb) {
+ skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
+ if (skb)
+ break;
+ pr_err("%s: Couldn't alloc SKB\n", __func__);
+ msleep(100);
+ }
+ data = skb_put(skb, pdata->max_read_size);
+ pkt_size = pdata->read(hsic_xprtp->pdev, data,
+ pdata->max_read_size);
+ if (pkt_size < 0) {
+ pr_err("%s: Error %d @ read operation\n",
+ __func__, pkt_size);
+ kfree_skb(skb);
+ kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
+ kfree(hsic_xprtp->in_pkt);
+ break;
+ }
+ skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
+ hsic_xprtp->in_pkt->length = pkt_size;
+ D("%s: Packet size read %d\n", __func__, pkt_size);
+ msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
+ IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
+ release_pkt(hsic_xprtp->in_pkt);
+ hsic_xprtp->in_pkt = NULL;
+ skb = NULL;
+ }
+}
+
+/**
+ * hsic_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this HSIC XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+ container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+ complete_all(&hsic_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an HSIC endpoint, during SSR.
+ */
+static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
+{
+ int id;
+ struct ipc_bridge_platform_data *pdata;
+
+ id = find_hsic_xprt_cfg(pdev);
+ if (id < 0) {
+ pr_err("%s: called for unknown ch %s\n",
+ __func__, pdev->name);
+ return id;
+ }
+
+ mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
+ hsic_remote_xprt[id].ss_reset = 1;
+ mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
+ flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+ destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+ init_completion(&hsic_remote_xprt[id].sft_close_complete);
+ msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+ IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+ D("%s: Notified IPC Router of %s CLOSE\n",
+ __func__, hsic_remote_xprt[id].xprt.name);
+ wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
+ hsic_remote_xprt[id].pdev = NULL;
+ pdata = pdev->dev.platform_data;
+ if (pdata && pdata->close)
+ pdata->close(pdev);
+ return 0;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an HSIC endpoint.
+ */
+static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
+{
+ int rc;
+ int id; /*Index into the hsic_xprt_cfg table*/
+ struct ipc_bridge_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata || !pdata->open || !pdata->read ||
+ !pdata->write || !pdata->close) {
+ pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ id = find_hsic_xprt_cfg(pdev);
+ if (id < 0) {
+ pr_err("%s: called for unknown ch %s\n",
+ __func__, pdev->name);
+ return id;
+ }
+
+ hsic_remote_xprt[id].hsic_xprt_wq =
+ create_singlethread_workqueue(pdev->name);
+ if (!hsic_remote_xprt[id].hsic_xprt_wq) {
+ pr_err("%s: WQ creation failed for %s\n",
+ __func__, pdev->name);
+ return -EFAULT;
+ }
+
+ hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
+ hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
+ hsic_remote_xprt[id].xprt.get_version =
+ msm_ipc_router_hsic_get_xprt_version;
+ hsic_remote_xprt[id].xprt.get_option =
+ msm_ipc_router_hsic_get_xprt_option;
+ hsic_remote_xprt[id].xprt.read_avail = NULL;
+ hsic_remote_xprt[id].xprt.read = NULL;
+ hsic_remote_xprt[id].xprt.write_avail =
+ msm_ipc_router_hsic_remote_write_avail;
+ hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
+ hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
+ hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
+ hsic_remote_xprt[id].xprt.priv = NULL;
+
+ hsic_remote_xprt[id].in_pkt = NULL;
+ INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
+ mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
+ hsic_remote_xprt[id].ss_reset = 0;
+ hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
+ hsic_remote_xprt[id].xprt_option = 0;
+
+ rc = pdata->open(pdev);
+ if (rc < 0) {
+ pr_err("%s: Channel open failed for %s.%d\n",
+ __func__, pdev->name, pdev->id);
+ destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+ return rc;
+ }
+ hsic_remote_xprt[id].pdev = pdev;
+ msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+ IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+ D("%s: Notified IPC Router of %s OPEN\n",
+ __func__, hsic_remote_xprt[id].xprt.name);
+ queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
+ &hsic_remote_xprt[id].read_work, 0);
+ return 0;
+}
+
+static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
+ {
+ .probe = msm_ipc_router_hsic_remote_probe,
+ .remove = msm_ipc_router_hsic_remote_remove,
+ .driver = {
+ .name = "ipc_bridge",
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+static int __init msm_ipc_router_hsic_init(void)
+{
+ int i, ret, rc = 0;
+ BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
+ for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
+ ret = platform_driver_register(
+ &msm_ipc_router_hsic_remote_driver[i]);
+ if (ret) {
+ pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
+ __func__, i);
+ rc = ret;
+ }
+ }
+ return rc;
+}
+
+module_init(msm_ipc_router_hsic_init);
+MODULE_DESCRIPTION("IPC Router HSIC XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index d6a3e03..87880c2 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
int ss_reset;
void *pil;
struct completion sft_close_complete;
+ unsigned xprt_version;
+ unsigned xprt_option;
};
struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
char xprt_name[XPRT_NAME_LEN];
uint32_t edge;
uint32_t link_id;
+ unsigned xprt_version;
};
struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
- {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
- {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
- {"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
- {"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+ {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+ {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+ {"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+ {"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
};
static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
return -ENODEV;
}
+static int msm_ipc_router_smd_get_xprt_version(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_smd_xprt *smd_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_smd_xprt *smd_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return (int)smd_xprtp->xprt_option;
+}
+
static int msm_ipc_router_smd_remote_write_avail(
struct msm_ipc_router_xprt *xprt)
{
@@ -110,7 +135,6 @@
{
struct rr_packet *pkt = (struct rr_packet *)data;
struct sk_buff *ipc_rtr_pkt;
- int align_sz, align_data = 0;
int offset, sz_written = 0;
int ret, num_retries = 0;
unsigned long flags;
@@ -123,9 +147,7 @@
if (!len || pkt->length != len)
return -EINVAL;
- align_sz = ALIGN_SIZE(pkt->length);
- while ((ret = smd_write_start(smd_xprtp->channel,
- (len + align_sz))) < 0) {
+ while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
if (smd_xprtp->ss_reset) {
spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
num_retries++;
}
- D("%s: Ready to write\n", __func__);
+ D("%s: Ready to write %d bytes\n", __func__, len);
skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
offset = 0;
while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
__func__, offset, xprt->name);
}
- if (align_sz) {
- if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
- smd_enable_read_intr(smd_xprtp->channel);
-
- wait_event(smd_xprtp->write_avail_wait_q,
- ((smd_write_segment_avail(smd_xprtp->channel) >=
- align_sz) || smd_xprtp->ss_reset));
- smd_disable_read_intr(smd_xprtp->channel);
- spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
- if (smd_xprtp->ss_reset) {
- spin_unlock_irqrestore(
- &smd_xprtp->ss_reset_lock, flags);
- pr_err("%s: %s chnl reset\n",
- __func__, xprt->name);
- return -ENETRESET;
- }
- spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
- flags);
-
- smd_write_segment(smd_xprtp->channel,
- &align_data, align_sz, 0);
- D("%s: Wrote %d align bytes over %s\n",
- __func__, align_sz, xprt->name);
- }
if (!smd_write_end(smd_xprtp->channel))
D("%s: Finished writing\n", __func__);
return len;
@@ -453,6 +451,10 @@
smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+ smd_remote_xprt[id].xprt.get_version =
+ msm_ipc_router_smd_get_xprt_version;
+ smd_remote_xprt[id].xprt.get_option =
+ msm_ipc_router_smd_get_xprt_option;
smd_remote_xprt[id].xprt.read_avail = NULL;
smd_remote_xprt[id].xprt.read = NULL;
smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
smd_remote_xprt[id].ss_reset = 0;
+ smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+ smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..bdda546 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
int i, copied, first = 1;
int data_size = 0, request_size, offset;
void *data;
+ int last = 0;
+ int align_size;
for (i = 0; i < num_sect; i++)
data_size += msg_sect[i].iov_len;
if (!data_size)
return NULL;
+ align_size = ALIGN_SIZE(data_size);
msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!msg_head) {
@@ -148,10 +151,14 @@
for (copied = 1, i = 0; copied && (i < num_sect); i++) {
data_size = msg_sect[i].iov_len;
offset = 0;
+ if (i == (num_sect - 1))
+ last = 1;
while (offset != msg_sect[i].iov_len) {
request_size = data_size;
if (first)
request_size += IPC_ROUTER_HDR_SIZE;
+ if (last)
+ request_size += align_size;
msg = alloc_skb(request_size, GFP_KERNEL);
if (!msg) {
@@ -161,6 +168,7 @@
goto msg_build_failure;
}
data_size = data_size / 2;
+ last = 0;
continue;
}
@@ -182,6 +190,8 @@
skb_queue_tail(msg_head, msg);
offset += data_size;
data_size = msg_sect[i].iov_len - offset;
+ if (i == (num_sect - 1))
+ last = 1;
}
}
return msg_head;
@@ -196,24 +206,23 @@
}
static int msm_ipc_router_extract_msg(struct msghdr *m,
- struct sk_buff_head *msg_head)
+ struct rr_packet *pkt)
{
struct sockaddr_msm_ipc *addr;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct sk_buff *temp;
union rr_control_msg *ctl_msg;
int offset = 0, data_len = 0, copy_len;
- if (!m || !msg_head) {
+ if (!m || !pkt) {
pr_err("%s: Invalid pointers passed\n", __func__);
return -EINVAL;
}
addr = (struct sockaddr_msm_ipc *)m->msg_name;
- temp = skb_peek(msg_head);
- hdr = (struct rr_header *)(temp->data);
+ hdr = &(pkt->hdr);
if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
- skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+ temp = skb_peek(pkt->pkt_fragment_q);
ctl_msg = (union rr_control_msg *)(temp->data);
addr->family = AF_MSM_IPC;
addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
return offset;
}
- if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+ if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
addr->family = AF_MSM_IPC;
addr->address.addrtype = MSM_IPC_ADDR_ID;
addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
}
data_len = hdr->size;
- skb_pull(temp, IPC_ROUTER_HDR_SIZE);
- skb_queue_walk(msg_head, temp) {
+ skb_queue_walk(pkt->pkt_fragment_q, temp) {
copy_len = data_len < temp->len ? data_len : temp->len;
if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
copy_len)) {
@@ -245,22 +253,6 @@
return offset;
}
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
- struct sk_buff *temp;
-
- if (!msg_head) {
- pr_err("%s: Invalid msg pointer\n", __func__);
- return;
- }
-
- while (!skb_queue_empty(msg_head)) {
- temp = skb_dequeue(msg_head);
- kfree_skb(temp);
- }
- kfree(msg_head);
-}
-
static int msm_ipc_router_create(struct net *net,
struct socket *sock,
int protocol,
@@ -385,8 +377,16 @@
if (ipc_buf)
msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
- if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
- ret = total_len;
+ if (ret != total_len) {
+ if (ret < 0) {
+ if (ret != -EAGAIN)
+ pr_err("%s: Send_to failure %d\n",
+ __func__, ret);
+ msm_ipc_router_free_skb(msg);
+ } else if (ret >= 0) {
+ ret = -EFAULT;
+ }
+ }
out_sendmsg:
release_sock(sk);
@@ -398,7 +398,7 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- struct sk_buff_head *msg;
+ struct rr_packet *pkt;
struct sk_buff *ipc_buf;
long timeout;
int ret;
@@ -420,18 +420,17 @@
return ret;
}
- ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
- if (ret <= 0 || !msg) {
+ ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+ if (ret <= 0 || !pkt) {
release_sock(sk);
return ret;
}
- ret = msm_ipc_router_extract_msg(m, msg);
- ipc_buf = skb_peek(msg);
+ ret = msm_ipc_router_extract_msg(m, pkt);
+ ipc_buf = skb_peek(pkt->pkt_fragment_q);
if (ipc_buf)
msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
- msm_ipc_router_release_msg(msg);
- msg = NULL;
+ release_pkt(pkt);
release_sock(sk);
return ret;
}
@@ -460,7 +459,7 @@
switch (cmd) {
case IPC_ROUTER_IOCTL_GET_VERSION:
- n = IPC_ROUTER_VERSION;
+ n = IPC_ROUTER_V1;
ret = put_user(n, (unsigned int *)arg);
break;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index bc15fe8..8b64653 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1876,7 +1876,7 @@
struct msm_bus_bimc_info *binfo;
struct msm_bus_bimc_qos_bw qbw;
int i;
- long int bw;
+ int64_t bw;
int ports = info->node_info->num_mports;
struct msm_bus_bimc_commit *sel_cd =
(struct msm_bus_bimc_commit *)sel_cdata;
@@ -1912,11 +1912,11 @@
qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
qbw.ws = info->node_info->ws;
/* Threshold low = 90% of bw */
- qbw.thl = (90 * bw) / 100;
+ qbw.thl = div_s64((90 * bw), 100);
/* Threshold medium = bw */
qbw.thm = bw;
/* Threshold high = 10% more than bw */
- qbw.thh = (110 * bw) / 100;
+ qbw.thh = div_s64((110 * bw), 100);
/* Check if info is a shared master.
* If it is, mark it dirty
* If it isn't, then set QOS Bandwidth
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index d33c340..8f7b7f2 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -511,7 +511,7 @@
struct msm_bus_noc_info *ninfo;
struct msm_bus_noc_qos_bw qos_bw;
int i, ports;
- long int bw;
+ int64_t bw;
struct msm_bus_noc_commit *sel_cd =
(struct msm_bus_noc_commit *)sel_cdata;
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index a9a6942..de15be5 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -378,9 +378,7 @@
{
struct lpass_data *drv = subsys_to_drv(dev_id);
- disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
schedule_work(&drv->work);
-
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index deb1cc7..d34bdf2 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -144,7 +144,7 @@
SMSM_APPS_DEM_I = 3,
};
-int msm_smd_debug_mask = MSM_SMx_POWER_INFO;
+int msm_smd_debug_mask = MSM_SMx_POWER_INFO | MSM_SMD_INFO;
module_param_named(debug_mask, msm_smd_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
void *smd_log_ctx;
@@ -825,7 +825,7 @@
}
}
-static void smd_channel_reset_state(struct smd_alloc_elm *shared,
+static void smd_channel_reset_state(struct smd_alloc_elm *shared, int table_id,
unsigned new_state, unsigned pid)
{
unsigned n;
@@ -834,6 +834,19 @@
void *local_ch;
void *remote_ch;
int is_word_access;
+ unsigned base_id;
+
+ switch (table_id) {
+ case PRI_ALLOC_TBL:
+ base_id = SMEM_SMD_BASE_ID;
+ break;
+ case SEC_ALLOC_TBL:
+ base_id = SMEM_SMD_BASE_ID_2;
+ break;
+ default:
+ SMD_INFO("%s: invalid table_id:%d\n", __func__, table_id);
+ return;
+ }
for (n = 0; n < SMD_CHANNELS; n++) {
if (!shared[n].ref_count)
@@ -844,10 +857,10 @@
type = SMD_CHANNEL_TYPE(shared[n].type);
is_word_access = is_word_access_ch(type);
if (is_word_access)
- shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+ shared2 = smem_alloc(base_id + n,
sizeof(struct smd_shared_v2_word_access));
else
- shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+ shared2 = smem_alloc(base_id + n,
sizeof(struct smd_shared_v2));
if (!shared2)
continue;
@@ -870,16 +883,19 @@
void smd_channel_reset(uint32_t restart_pid)
{
- struct smd_alloc_elm *shared;
+ struct smd_alloc_elm *shared_pri;
+ struct smd_alloc_elm *shared_sec;
unsigned long flags;
SMx_POWER_INFO("%s: starting reset\n", __func__);
- shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
- if (!shared) {
+ shared_pri = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared_pri) * 64);
+ if (!shared_pri) {
pr_err("%s: allocation table not initialized\n", __func__);
return;
}
+ shared_sec = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
+ sizeof(*shared_sec) * 64);
/* reset SMSM entry */
if (smsm_info.state) {
@@ -903,7 +919,11 @@
/* change all remote states to CLOSING */
mutex_lock(&smd_probe_lock);
spin_lock_irqsave(&smd_lock, flags);
- smd_channel_reset_state(shared, SMD_SS_CLOSING, restart_pid);
+ smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSING,
+ restart_pid);
+ if (shared_sec)
+ smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+ SMD_SS_CLOSING, restart_pid);
spin_unlock_irqrestore(&smd_lock, flags);
mutex_unlock(&smd_probe_lock);
@@ -919,7 +939,11 @@
/* change all remote states to CLOSED */
mutex_lock(&smd_probe_lock);
spin_lock_irqsave(&smd_lock, flags);
- smd_channel_reset_state(shared, SMD_SS_CLOSED, restart_pid);
+ smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSED,
+ restart_pid);
+ if (shared_sec)
+ smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+ SMD_SS_CLOSED, restart_pid);
spin_unlock_irqrestore(&smd_lock, flags);
mutex_unlock(&smd_probe_lock);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2781a34..7da0811 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -911,11 +911,7 @@
mutex_lock(&private->process_private_mutex);
- /*
- * If debug root initialized then it means the rest of the fields
- * are also initialized
- */
- if (private->debug_root)
+ if (test_bit(KGSL_PROCESS_INIT, &private->priv))
goto done;
private->mem_rb = RB_ROOT;
@@ -936,6 +932,8 @@
if (kgsl_process_init_debugfs(private))
goto error;
+ set_bit(KGSL_PROCESS_INIT, &private->priv);
+
done:
mutex_unlock(&private->process_private_mutex);
return private;
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index b2f137c..fe9bc76 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2011,2013, 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
@@ -35,7 +35,7 @@
static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
static inline void kgsl_core_debugfs_close(void) { }
static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
-static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv)
{
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 09a31c9..0b5fe52 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -315,8 +315,23 @@
unsigned int pagefault_ts;
};
+/**
+ * struct kgsl_process_private - Private structure for a KGSL process (across
+ * all devices)
+ * @priv: Internal flags, use KGSL_PROCESS_* values
+ * @pid: ID for the task owner of the process
+ * @mem_lock: Spinlock to protect the process memory lists
+ * @refcount: kref object for reference counting the process
+ * @process_private_mutex: Mutex to synchronize access to the process struct
+ * @mem_rb: RB tree node for the memory owned by this process
+ * @idr: Iterator for assigning IDs to memory allocations
+ * @pagetable: Pointer to the pagetable owned by this process
+ * @kobj: Pointer to a kobj for the sysfs directory for this process
+ * @debug_root: Pointer to the debugfs root for this process
+ * @stats: Memory allocation statistics for this process
+ */
struct kgsl_process_private {
- unsigned int refcnt;
+ unsigned long priv;
pid_t pid;
spinlock_t mem_lock;
@@ -338,6 +353,14 @@
} stats[KGSL_MEM_ENTRY_MAX];
};
+/**
+ * enum kgsl_process_priv_flags - Private flags for kgsl_process_private
+ * @KGSL_PROCESS_INIT: Set if the process structure has been set up
+ */
+enum kgsl_process_priv_flags {
+ KGSL_PROCESS_INIT = 0,
+};
+
struct kgsl_device_private {
struct kgsl_device *device;
struct kgsl_process_private *process_priv;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 9f326f1..0a92d51 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -32,7 +32,6 @@
#define SHOW_PROGRESS
#define MAX_FIRMWARE_ID_LEN 10
#define FORCE_UPDATE false
-#define DO_LOCKDOWN false
#define INSIDE_FIRMWARE_UPDATE
#define FW_IMAGE_OFFSET 0x100
@@ -1115,7 +1114,11 @@
if (retval < 0)
return retval;
- if (f01_device_status.flash_prog) {
+ if (force) {
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Force to enter flash prog mode\n",
+ __func__);
+ } else if (f01_device_status.flash_prog) {
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s: Already in flash prog mode\n",
__func__);
@@ -1475,6 +1478,9 @@
"%s: Erase all command written\n",
__func__);
+ if (fwu->polling_mode)
+ msleep(100);
+
retval = fwu_wait_for_idle(ERASE_WAIT_MS);
if (retval < 0)
return retval;
@@ -1757,7 +1763,7 @@
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->do_lockdown = rmi4_data->board->do_lockdown;
return retval;
}
@@ -1800,7 +1806,7 @@
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->do_lockdown = rmi4_data->board->do_lockdown;
return retval;
}
@@ -1835,7 +1841,7 @@
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->do_lockdown = rmi4_data->board->do_lockdown;
return retval;
}
@@ -2166,7 +2172,7 @@
fwu->initialized = true;
fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->do_lockdown = rmi4_data->board->do_lockdown;
fwu->initialized = true;
fwu->polling_mode = false;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 2506e05..cf1c717 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -96,6 +96,8 @@
#define F12_FINGERS_TO_SUPPORT 10
#define MAX_F11_TOUCH_WIDTH 15
+#define RMI4_COORDS_ARR_SIZE 4
+
static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data,
unsigned short length);
@@ -1053,9 +1055,9 @@
wy = finger_data->wy;
#endif
- if (rmi4_data->board->x_flip)
+ if (rmi4_data->flip_x)
x = rmi4_data->sensor_max_x - x;
- if (rmi4_data->board->y_flip)
+ if (rmi4_data->flip_y)
y = rmi4_data->sensor_max_y - y;
dev_dbg(&rmi4_data->i2c_client->dev,
@@ -1332,6 +1334,50 @@
}
#ifdef CONFIG_OF
+static int synaptics_rmi4_get_dt_coords(struct device *dev, char *name,
+ struct synaptics_rmi4_platform_data *pdata)
+{
+ u32 coords[RMI4_COORDS_ARR_SIZE];
+ struct property *prop;
+ struct device_node *np = dev->of_node;
+ int coords_size, rc;
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ coords_size = prop->length / sizeof(u32);
+ if (coords_size != RMI4_COORDS_ARR_SIZE) {
+ dev_err(dev, "invalid %s\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read %s\n", name);
+ return rc;
+ }
+
+ if (strcmp(name, "synaptics,panel-coords") == 0) {
+ pdata->panel_minx = coords[0];
+ pdata->panel_miny = coords[1];
+ pdata->panel_maxx = coords[2];
+ pdata->panel_maxy = coords[3];
+ } else if (strcmp(name, "synaptics,display-coords") == 0) {
+ pdata->disp_minx = coords[0];
+ pdata->disp_miny = coords[1];
+ pdata->disp_maxx = coords[2];
+ pdata->disp_maxy = coords[3];
+ } else {
+ dev_err(dev, "unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int synaptics_rmi4_parse_dt(struct device *dev,
struct synaptics_rmi4_platform_data *rmi4_pdata)
{
@@ -1349,21 +1395,26 @@
"synaptics,disable-gpios");
rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+ rmi4_pdata->do_lockdown = of_property_read_bool(np,
+ "synaptics,do-lockdown");
- rc = of_property_read_u32(np, "synaptics,panel-x", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read panel X dimension\n");
+ rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,display-coords",
+ rmi4_pdata);
+ if (rc && (rc != -EINVAL))
return rc;
- } else {
- rmi4_pdata->panel_x = temp_val;
- }
- rc = of_property_read_u32(np, "synaptics,panel-y", &temp_val);
- if (rc && (rc != -EINVAL)) {
- dev_err(dev, "Unable to read panel Y dimension\n");
+ rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,panel-coords",
+ rmi4_pdata);
+ if (rc && (rc != -EINVAL))
return rc;
- } else {
- rmi4_pdata->panel_y = temp_val;
+
+ rmi4_pdata->reset_delay = RESET_DELAY;
+ rc = of_property_read_u32(np, "synaptics,reset-delay", &temp_val);
+ if (!rc)
+ rmi4_pdata->reset_delay = temp_val;
+ else if (rc != -EINVAL) {
+ dev_err(dev, "Unable to read reset delay\n");
+ return rc;
}
rc = of_property_read_string(np, "synaptics,fw-image-name",
@@ -1819,11 +1870,10 @@
const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
if (!pdata->capacitance_button_map) {
- dev_err(&rmi4_data->i2c_client->dev,
- "%s: capacitance_button_map is" \
- "NULL in board file\n",
+ dev_info(&rmi4_data->i2c_client->dev,
+ "%s: capacitance_button_map not in use\n",
__func__);
- return -ENODEV;
+ return 0;
} else if (!pdata->capacitance_button_map->map) {
dev_err(&rmi4_data->i2c_client->dev,
"%s: Button map is missing in board file\n",
@@ -2258,7 +2308,7 @@
return retval;
}
- msleep(RESET_DELAY);
+ msleep(rmi4_data->board->reset_delay);
return retval;
};
@@ -2603,7 +2653,7 @@
gpio_set_value(rmi4_data->board->reset_gpio, 0);
usleep(RMI4_GPIO_SLEEP_LOW_US);
gpio_set_value(rmi4_data->board->reset_gpio, 1);
- msleep(RESET_DELAY);
+ msleep(rmi4_data->board->reset_delay);
} else
synaptics_rmi4_reset_command(rmi4_data);
@@ -2776,12 +2826,32 @@
goto err_free_gpios;
}
+ if (rmi4_data->board->disp_maxx)
+ rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
+ else
+ rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
+
+ if (rmi4_data->board->disp_maxy)
+ rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
+ else
+ rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
+
+ if (rmi4_data->board->disp_minx)
+ rmi4_data->disp_minx = rmi4_data->board->disp_minx;
+ else
+ rmi4_data->disp_minx = 0;
+
+ if (rmi4_data->board->disp_miny)
+ rmi4_data->disp_miny = rmi4_data->board->disp_miny;
+ else
+ rmi4_data->disp_miny = 0;
+
input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_POSITION_X, 0,
- rmi4_data->sensor_max_x, 0, 0);
+ ABS_MT_POSITION_X, rmi4_data->disp_minx,
+ rmi4_data->disp_maxx, 0, 0);
input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_POSITION_Y, 0,
- rmi4_data->sensor_max_y, 0, 0);
+ ABS_MT_POSITION_Y, rmi4_data->disp_miny,
+ rmi4_data->disp_maxy, 0, 0);
input_set_abs_params(rmi4_data->input_dev,
ABS_PRESSURE, 0, 255, 0, 0);
#ifdef REPORT_2D_W
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 677a2fe..ef39bb7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -186,6 +186,10 @@
* @irq: attention interrupt
* @sensor_max_x: sensor maximum x value
* @sensor_max_y: sensor maximum y value
+ * @disp_maxx: max x value of display
+ * @disp_maxy: max y value of display
+ * @disp_minx: min x value of display
+ * @disp_miny: min y value of display
* @irq_enabled: flag for indicating interrupt enable status
* @touch_stopped: flag to stop interrupt thread processing
* @fingers_on_2d: flag to indicate presence of fingers in 2d area
@@ -230,6 +234,10 @@
int irq;
int sensor_max_x;
int sensor_max_y;
+ int disp_maxx;
+ int disp_maxy;
+ int disp_minx;
+ int disp_miny;
bool irq_enabled;
bool touch_stopped;
bool fingers_on_2d;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 675110f..bf59d03 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
#include <linux/spmi.h>
#include <linux/qpnp/pwm.h>
#include <linux/workqueue.h>
+#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
@@ -43,6 +44,7 @@
#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
#define WLED_CURR_SINK_MASK 0xE0
#define WLED_CURR_SINK_SHFT 0x05
+#define WLED_DISABLE_ALL_SINKS 0x00
#define WLED_SWITCH_FREQ_MASK 0x0F
#define WLED_OVP_VAL_MASK 0x03
#define WLED_OVP_VAL_BIT_SHFT 0x00
@@ -58,8 +60,10 @@
#define WLED_CTL_DLY_STEP 200
#define WLED_CTL_DLY_MAX 1400
#define WLED_MAX_CURR 25
+#define WLED_NO_CURRENT 0x00
+#define WLED_OVP_DELAY 1000
#define WLED_MSB_MASK 0x0F
-#define WLED_MAX_CURR_MASK 0x19
+#define WLED_MAX_CURR_MASK 0x1F
#define WLED_OP_FDBCK_MASK 0x07
#define WLED_OP_FDBCK_BIT_SHFT 0x00
#define WLED_OP_FDBCK_DEFAULT 0x00
@@ -73,6 +77,9 @@
#define WLED_SYNC_VAL 0x07
#define WLED_SYNC_RESET_VAL 0x00
+#define PMIC_VER_8026 0x04
+#define PMIC_VERSION_REG 0x0105
+
#define WLED_DEFAULT_STRINGS 0x01
#define WLED_DEFAULT_OVP_VAL 0x02
#define WLED_BOOST_LIM_DEFAULT 0x03
@@ -337,6 +344,7 @@
u8 ctrl_delay_us;
u8 switch_freq;
u8 op_fdbck;
+ u8 pmic_version;
bool dig_mod_gen_en;
bool cs_out_en;
};
@@ -511,16 +519,86 @@
pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
}
+static int qpnp_wled_sync(struct qpnp_led_data *led)
+{
+ int rc;
+ u8 val;
+
+ /* sync */
+ val = WLED_SYNC_VAL;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ WLED_SYNC_REG(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED set sync reg failed(%d)\n", rc);
+ return rc;
+ }
+
+ val = WLED_SYNC_RESET_VAL;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ WLED_SYNC_REG(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED reset sync reg failed(%d)\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
static int qpnp_wled_set(struct qpnp_led_data *led)
{
int rc, duty, level;
- u8 val, i, num_wled_strings;
+ u8 val, i, num_wled_strings, sink_val;
+
+ num_wled_strings = led->wled_cfg->num_strings;
level = led->cdev.brightness;
if (level > WLED_MAX_LEVEL)
level = WLED_MAX_LEVEL;
if (level == 0) {
+ for (i = 0; i < num_wled_strings; i++) {
+ rc = qpnp_led_masked_write(led,
+ WLED_FULL_SCALE_REG(led->base, i),
+ WLED_MAX_CURR_MASK, WLED_NO_CURRENT);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Write max current failure (%d)\n",
+ rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_wled_sync(led);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED sync failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+ led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+ &sink_val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED read sink reg failed(%d)\n", rc);
+ return rc;
+ }
+
+ if (led->wled_cfg->pmic_version == PMIC_VER_8026) {
+ val = WLED_DISABLE_ALL_SINKS;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+ led->spmi_dev->sid,
+ WLED_CURR_SINK_REG(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED write sink reg failed(%d)\n", rc);
+ return rc;
+ }
+
+ usleep(WLED_OVP_DELAY);
+ }
+
val = WLED_BOOST_OFF;
rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
@@ -530,6 +608,35 @@
"WLED write ctrl reg failed(%d)\n", rc);
return rc;
}
+
+ for (i = 0; i < num_wled_strings; i++) {
+ rc = qpnp_led_masked_write(led,
+ WLED_FULL_SCALE_REG(led->base, i),
+ WLED_MAX_CURR_MASK, led->max_current);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Write max current failure (%d)\n",
+ rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_wled_sync(led);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED sync failed(%d)\n", rc);
+ return rc;
+ }
+
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+ led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+ &sink_val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED write sink reg failed(%d)\n", rc);
+ return rc;
+ }
+
} else {
val = WLED_BOOST_ON;
rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
@@ -544,8 +651,6 @@
duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
- num_wled_strings = led->wled_cfg->num_strings;
-
/* program brightness control registers */
for (i = 0; i < num_wled_strings; i++) {
rc = qpnp_led_masked_write(led,
@@ -567,22 +672,9 @@
}
}
- /* sync */
- val = WLED_SYNC_VAL;
- rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
- WLED_SYNC_REG(led->base), &val, 1);
+ rc = qpnp_wled_sync(led);
if (rc) {
- dev_err(&led->spmi_dev->dev,
- "WLED set sync reg failed(%d)\n", rc);
- return rc;
- }
-
- val = WLED_SYNC_RESET_VAL;
- rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
- WLED_SYNC_REG(led->base), &val, 1);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "WLED reset sync reg failed(%d)\n", rc);
+ dev_err(&led->spmi_dev->dev, "WLED sync failed(%d)\n", rc);
return rc;
}
return 0;
@@ -2489,6 +2581,13 @@
return -ENOMEM;
}
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ PMIC_VERSION_REG, &led->wled_cfg->pmic_version, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read pmic ver, rc(%d)\n", rc);
+ }
+
led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
rc = of_property_read_u32(node, "qcom,num-strings", &val);
if (!rc)
diff --git a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
index 78d15d9..d9fba33 100644
--- a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
+++ b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
@@ -2777,40 +2777,6 @@
return rc;
}
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
- struct msm_cam_config_dev *config_cam = fp->private_data;
- int rc = 0;
- int phyaddr;
- int retval;
- unsigned long size;
-
- D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
- phyaddr = (int)config_cam->mem_map.cookie;
- if (!phyaddr) {
- pr_err("%s: no physical memory to map", __func__);
- return -EFAULT;
- }
- memset(&config_cam->mem_map, 0,
- sizeof(struct msm_mem_map_info));
- size = vma->vm_end - vma->vm_start;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = remap_pfn_range(vma, vma->vm_start,
- phyaddr >> PAGE_SHIFT,
- size, vma->vm_page_prot);
- if (retval) {
- pr_err("%s: remap failed, rc = %d",
- __func__, retval);
- rc = -ENOMEM;
- goto end;
- }
- D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
- __func__, (uint32_t)phyaddr,
- vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
- return rc;
-}
-
static int msm_open_config(struct inode *inode, struct file *fp)
{
int rc;
@@ -3081,12 +3047,6 @@
rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
break;
- case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
- if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
- sizeof(struct msm_mem_map_info)))
- rc = -EINVAL;
- break;
-
case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
struct msm_mctl_set_sdev_data set_data;
if (copy_from_user(&set_data, (void __user *)arg,
@@ -3148,7 +3108,6 @@
.open = msm_open_config,
.poll = msm_poll_config,
.unlocked_ioctl = msm_ioctl_config,
- .mmap = msm_mmap_config,
.release = msm_close_config,
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index c188105..32d74ba 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -816,6 +816,7 @@
cci_client = msm_actuator_t->i2c_client.cci_client;
cci_client->cci_subdev = msm_cci_get_subdev();
+ cci_client->cci_i2c_master = MASTER_MAX;
v4l2_subdev_init(&msm_actuator_t->msm_sd.sd,
msm_actuator_t->act_v4l2_subdev_ops);
v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
index 591c464..059633b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
@@ -15,7 +15,7 @@
#define CCI_HW_VERSION_ADDR 0x00000000
#define CCI_RESET_CMD_ADDR 0x00000004
-#define CCI_RESET_CMD_RMSK 0xcf73f3f7
+#define CCI_RESET_CMD_RMSK 0x0f73f3f7
#define CCI_M0_RESET_RMSK 0x3F1
#define CCI_M1_RESET_RMSK 0x3F001
#define CCI_QUEUE_START_ADDR 0x00000008
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 17c5a14..d11798e 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
@@ -628,21 +628,46 @@
{"cci_clk", -1},
};
-static int32_t msm_cci_init(struct v4l2_subdev *sd)
+static int32_t msm_cci_init(struct v4l2_subdev *sd,
+ struct msm_camera_cci_ctrl *c_ctrl)
{
int rc = 0;
struct cci_device *cci_dev;
+ enum cci_i2c_master_t master;
cci_dev = v4l2_get_subdevdata(sd);
- CDBG("%s line %d\n", __func__, __LINE__);
- if (!cci_dev) {
- pr_err("%s cci device NULL\n", __func__);
+ if (!cci_dev || !c_ctrl) {
+ pr_err("%s:%d failed: invalid params %p %p\n", __func__,
+ __LINE__, cci_dev, c_ctrl);
rc = -ENOMEM;
return rc;
}
if (cci_dev->ref_count++) {
CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+ master = c_ctrl->cci_info->cci_i2c_master;
+ CDBG("%s:%d master %d\n", __func__, __LINE__, master);
+ if (master < MASTER_MAX) {
+ mutex_lock(&cci_dev->cci_master_info[master].mutex);
+ /* Set reset pending flag to TRUE */
+ cci_dev->cci_master_info[master].reset_pending = TRUE;
+ /* Set proper mask to RESET CMD address */
+ if (master == MASTER_0)
+ msm_camera_io_w(CCI_M0_RESET_RMSK,
+ cci_dev->base + CCI_RESET_CMD_ADDR);
+ else
+ msm_camera_io_w(CCI_M1_RESET_RMSK,
+ cci_dev->base + CCI_RESET_CMD_ADDR);
+ /* wait for reset done irq */
+ rc = wait_for_completion_interruptible_timeout(
+ &cci_dev->cci_master_info[master].
+ reset_complete,
+ CCI_TIMEOUT);
+ if (rc <= 0)
+ pr_err("%s:%d wait failed %d\n", __func__,
+ __LINE__, rc);
+ mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+ }
return 0;
}
@@ -685,6 +710,7 @@
cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
msm_camera_io_w(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
cci_dev->cci_state = CCI_STATE_ENABLED;
+
return 0;
reset_complete_failed:
@@ -695,6 +721,7 @@
msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
cci_dev->cci_gpio_tbl_size, 0);
request_gpio_failed:
+ cci_dev->ref_count--;
return rc;
}
@@ -710,7 +737,7 @@
}
if (--cci_dev->ref_count) {
- CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+ CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
return 0;
}
@@ -723,6 +750,7 @@
cci_dev->cci_gpio_tbl_size, 0);
cci_dev->cci_state = CCI_STATE_DISABLED;
+
return 0;
}
@@ -734,7 +762,7 @@
cci_ctrl->cmd);
switch (cci_ctrl->cmd) {
case MSM_CCI_INIT:
- rc = msm_cci_init(sd);
+ rc = msm_cci_init(sd, cci_ctrl);
break;
case MSM_CCI_RELEASE:
rc = msm_cci_release(sd);
@@ -837,10 +865,7 @@
rc = msm_cci_config(sd, arg);
break;
case MSM_SD_SHUTDOWN: {
- struct msm_camera_cci_ctrl ctrl_cmd;
- ctrl_cmd.cmd = MSM_CCI_RELEASE;
- rc = msm_cci_config(sd, &ctrl_cmd);
- break;
+ return rc;
}
default:
rc = -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 1407f12..7f13568 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -229,6 +229,88 @@
return rc;
}
+static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+ int rc = 0, i = 0;
+ struct msm_eeprom_board_info *eb_info;
+ struct msm_camera_power_ctrl_t *power_info =
+ &e_ctrl->eboard_info->power_info;
+ struct device_node *of_node = NULL;
+ struct msm_camera_gpio_conf *gconf = NULL;
+ uint16_t gpio_array_size = 0;
+ uint16_t *gpio_array = NULL;
+
+ eb_info = e_ctrl->eboard_info;
+ if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+ of_node = e_ctrl->i2c_client.
+ spi_client->spi_master->dev.of_node;
+ else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+ of_node = e_ctrl->pdev->dev.of_node;
+ else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE)
+ of_node = e_ctrl->i2c_client.client->dev.of_node;
+
+ rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
+ &power_info->num_vreg);
+ if (rc < 0)
+ return rc;
+
+ rc = msm_camera_get_dt_power_setting_data(of_node,
+ power_info->cam_vreg, power_info->num_vreg,
+ &power_info->power_setting, &power_info->power_setting_size);
+ if (rc < 0)
+ goto error1;
+
+ power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+ GFP_KERNEL);
+ if (!power_info->gpio_conf) {
+ rc = -ENOMEM;
+ goto error2;
+ }
+ gconf = power_info->gpio_conf;
+ gpio_array_size = of_gpio_count(of_node);
+ CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+ if (gpio_array_size) {
+ gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+ GFP_KERNEL);
+ if (!gpio_array) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto error3;
+ }
+ for (i = 0; i < gpio_array_size; i++) {
+ gpio_array[i] = of_get_gpio(of_node, i);
+ CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+ gpio_array[i]);
+ }
+
+ rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto error4;
+ }
+
+ rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto error4;
+ }
+ kfree(gpio_array);
+ }
+
+ return rc;
+error4:
+ kfree(gpio_array);
+error3:
+ kfree(power_info->gpio_conf);
+error2:
+ kfree(power_info->cam_vreg);
+error1:
+ kfree(power_info->power_setting);
+ return rc;
+}
+
static int msm_eeprom_alloc_memory_map(struct msm_eeprom_ctrl_t *e_ctrl,
struct device_node *of)
{
@@ -320,10 +402,19 @@
int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id) {
int rc = 0;
+ int32_t j = 0;
+ uint32_t temp = 0;
struct msm_eeprom_ctrl_t *e_ctrl = NULL;
struct msm_camera_power_ctrl_t *power_info = NULL;
+ struct device_node *of_node = client->dev.of_node;
CDBG("%s E\n", __func__);
+
+ if (!of_node) {
+ pr_err("%s of_node NULL\n", __func__);
+ return -EINVAL;
+ }
+
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pr_err("%s i2c_check_functionality failed\n", __func__);
goto probe_failure;
@@ -337,13 +428,23 @@
e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
CDBG("%s client = %x\n", __func__, (unsigned int)client);
- e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data);
+ e_ctrl->eboard_info = kzalloc(sizeof(
+ struct msm_eeprom_board_info), GFP_KERNEL);
if (!e_ctrl->eboard_info) {
pr_err("%s:%d board info NULL\n", __func__, __LINE__);
return -EINVAL;
}
+
+ rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp);
+ if (rc < 0) {
+ pr_err("%s failed rc %d\n", __func__, rc);
+ return rc;
+ }
+
power_info = &e_ctrl->eboard_info->power_info;
+ e_ctrl->eboard_info->i2c_slaveaddr = temp;
e_ctrl->i2c_client.client = client;
+ e_ctrl->is_supported = 0;
/* Set device type as I2C */
e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE;
@@ -356,6 +457,45 @@
power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
power_info->dev = &client->dev;
+ rc = of_property_read_string(of_node, "qcom,eeprom-name",
+ &e_ctrl->eboard_info->eeprom_name);
+ CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
+ e_ctrl->eboard_info->eeprom_name, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto board_free;
+ }
+
+ rc = msm_eeprom_get_dt_data(e_ctrl);
+ if (rc)
+ goto board_free;
+
+ rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
+ if (rc)
+ goto board_free;
+
+ rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
+ if (rc) {
+ pr_err("%s failed power up %d\n", __func__, __LINE__);
+ goto memdata_free;
+ }
+ rc = read_eeprom_memory(e_ctrl);
+ if (rc < 0) {
+ pr_err("%s read_eeprom_memory failed\n", __func__);
+ goto power_down;
+ }
+
+ for (j = 0; j < e_ctrl->num_bytes; j++)
+ CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
+
+ rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
+ if (rc) {
+ pr_err("failed rc %d\n", rc);
+ goto power_down;
+ }
+
/*IMPLEMENT READING PART*/
/* Initialize sub device */
v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd,
@@ -368,9 +508,18 @@
e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
msm_sd_register(&e_ctrl->msm_sd);
+ e_ctrl->is_supported = 1;
CDBG("%s success result=%d X\n", __func__, rc);
return rc;
+power_down:
+ msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+ &e_ctrl->i2c_client);
+memdata_free:
+ kfree(e_ctrl->memory_data);
+ kfree(e_ctrl->eboard_info->eeprom_map);
+board_free:
+ kfree(e_ctrl->eboard_info);
probe_failure:
pr_err("%s failed! rc = %d\n", __func__, rc);
return rc;
@@ -454,86 +603,6 @@
return 0;
}
-static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
-{
- int rc = 0, i = 0;
- struct msm_eeprom_board_info *eb_info;
- struct msm_camera_power_ctrl_t *power_info =
- &e_ctrl->eboard_info->power_info;
- struct device_node *of_node = NULL;
- struct msm_camera_gpio_conf *gconf = NULL;
- uint16_t gpio_array_size = 0;
- uint16_t *gpio_array = NULL;
-
- eb_info = e_ctrl->eboard_info;
- if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
- of_node = e_ctrl->i2c_client.
- spi_client->spi_master->dev.of_node;
- else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
- of_node = e_ctrl->pdev->dev.of_node;
-
- rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
- &power_info->num_vreg);
- if (rc < 0)
- return rc;
-
- rc = msm_camera_get_dt_power_setting_data(of_node,
- power_info->cam_vreg, power_info->num_vreg,
- &power_info->power_setting, &power_info->power_setting_size);
- if (rc < 0)
- goto ERROR1;
-
- power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
- GFP_KERNEL);
- if (!power_info->gpio_conf) {
- rc = -ENOMEM;
- goto ERROR2;
- }
- gconf = power_info->gpio_conf;
- gpio_array_size = of_gpio_count(of_node);
- CDBG("%s gpio count %d\n", __func__, gpio_array_size);
-
- if (gpio_array_size) {
- gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
- GFP_KERNEL);
- if (!gpio_array) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR3;
- }
- for (i = 0; i < gpio_array_size; i++) {
- gpio_array[i] = of_get_gpio(of_node, i);
- CDBG("%s gpio_array[%d] = %d\n", __func__, i,
- gpio_array[i]);
- }
-
- rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
- gpio_array, gpio_array_size);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR4;
- }
-
- rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
- gpio_array, gpio_array_size);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR4;
- }
- kfree(gpio_array);
- }
-
- return rc;
-ERROR4:
- kfree(gpio_array);
-ERROR3:
- kfree(power_info->gpio_conf);
-ERROR2:
- kfree(power_info->cam_vreg);
-ERROR1:
- kfree(power_info->power_setting);
- return rc;
-}
-
static int msm_eeprom_spi_setup(struct spi_device *spi)
{
struct msm_eeprom_ctrl_t *e_ctrl = NULL;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index ddc168a..0083378 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1272,9 +1272,10 @@
case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
return msm_sensor_get_af_status(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
- case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
+ case MSM_SD_SHUTDOWN:
+ return 0;
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index e335ff0..afd7200 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -514,6 +514,19 @@
b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
binfo->device_addr[i]);
+
+ if ((vidc_inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to INV caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+
if (binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
rc = msm_smem_cache_operations(v4l2_inst->mem_client,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 73ff9fa..a3d88c5 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -363,6 +363,14 @@
.type = OUTPUT_PORT,
},
{
+ .name = "HEVC_HYBRID",
+ .description = "HEVC compressed format",
+ .fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 122f0e9..fdc851c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1337,7 +1337,9 @@
case V4L2_PIX_FMT_HEVC:
codec = HAL_VIDEO_CODEC_HEVC;
break;
-
+ case V4L2_PIX_FMT_HEVC_HYBRID:
+ codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+ break;
default:
dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
codec = HAL_UNUSED_CODEC;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 890a5be..b600d64 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -202,6 +202,7 @@
HAL_VIDEO_CODEC_VP7 = 0x00000800,
HAL_VIDEO_CODEC_VP8 = 0x00001000,
HAL_VIDEO_CODEC_HEVC = 0x00002000,
+ HAL_VIDEO_CODEC_HEVC_HYBRID = 0x00004000,
HAL_UNUSED_CODEC = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index de312f4..b5c431e 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -80,6 +80,7 @@
#define HFI_VIDEO_CODEC_SPARK 0x00000200
#define HFI_VIDEO_CODEC_VP8 0x00001000
#define HFI_VIDEO_CODEC_HEVC 0x00002000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID 0x00004000
#define HFI_H264_PROFILE_BASELINE 0x00000001
#define HFI_H264_PROFILE_MAIN 0x00000002
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a4498d2..3648d88 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -26,6 +26,12 @@
#include "sd.h"
#include "sd_ops.h"
+#define UHS_SDR104_MIN_DTR (100 * 1000 * 1000)
+#define UHS_DDR50_MIN_DTR (50 * 1000 * 1000)
+#define UHS_SDR50_MIN_DTR (50 * 1000 * 1000)
+#define UHS_SDR25_MIN_DTR (25 * 1000 * 1000)
+#define UHS_SDR12_MIN_DTR (12.5 * 1000 * 1000)
+
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
@@ -486,18 +492,22 @@
}
if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
+ (card->host->f_max > UHS_SDR104_MIN_DTR)) {
card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+ (card->host->f_max > UHS_DDR50_MIN_DTR)) {
card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
- SD_MODE_UHS_SDR50)) {
+ SD_MODE_UHS_SDR50) &&
+ (card->host->f_max > UHS_SDR50_MIN_DTR)) {
card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
+ (card->host->f_max > UHS_SDR25_MIN_DTR)) {
card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 44f86dd..9f06258 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -42,6 +42,11 @@
module_param_named(debug_enable, msm_rmnet_bam_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static unsigned long int msm_rmnet_bam_headroom_check_failure;
+module_param(msm_rmnet_bam_headroom_check_failure, ulong, S_IRUGO);
+MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
+ "Number of packets with insufficient headroom");
+
#define DEBUG_MASK_LVL0 (1U << 0)
#define DEBUG_MASK_LVL1 (1U << 1)
#define DEBUG_MASK_LVL2 (1U << 2)
@@ -287,6 +292,23 @@
((struct net_device *)dev)->name, __func__);
}
+static struct sk_buff *_rmnet_add_headroom(struct sk_buff **skb,
+ struct net_device *dev)
+{
+ struct sk_buff *skbn;
+
+ if (skb_headroom(*skb) < dev->needed_headroom) {
+ msm_rmnet_bam_headroom_check_failure++;
+ skbn = skb_realloc_headroom(*skb, dev->needed_headroom);
+ kfree_skb(*skb);
+ *skb = skbn;
+ } else {
+ skbn = *skb;
+ }
+
+ return skbn;
+}
+
static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rmnet_private *p = netdev_priv(dev);
@@ -295,6 +317,10 @@
u32 opmode;
unsigned long flags;
+ if (unlikely(!_rmnet_add_headroom(&skb, dev))) {
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
spin_lock_irqsave(&p->lock, flags);
opmode = p->operation_mode;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index aa29748..7d6e345 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -1797,6 +1797,7 @@
if (IS_ERR(penv->pil)) {
dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
ret = PTR_ERR(penv->pil);
+ wcnss_pronto_log_debug_regs();
penv->pil = NULL;
goto fail_pil;
}
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index b77c826..7d26bef 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -199,8 +199,15 @@
#define qpnp_check_gpled_lpg_channel(id) \
(id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START && \
id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+
#define QPNP_PWM_LUT_NOT_SUPPORTED 0x1
+/* Supported PWM sizes */
+#define QPNP_PWM_SIZE_6_BIT 6
+#define QPNP_PWM_SIZE_7_BIT 7
+#define QPNP_PWM_SIZE_8_BIT 8
+#define QPNP_PWM_SIZE_9_BIT 9
+
/* LPG revisions */
enum qpnp_lpg_revision {
QPNP_LPG_REVISION_0 = 0x0,
@@ -301,6 +308,7 @@
int pwm_period;
int pwm_duty;
struct pwm_period_config period;
+ int force_pwm_size;
};
/* Public facing structure */
@@ -418,14 +426,16 @@
* (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
*/
static void qpnp_lpg_calc_period(unsigned int period_us,
- struct qpnp_pwm_config *pwm_conf)
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
unsigned int last_err, cur_err, min_err;
unsigned int tmp_p, period_n;
- int id = pwm_conf->channel_id;
- struct pwm_period_config *period = &pwm_conf->period;
+ int id = pwm->pwm_config.channel_id;
+ int force_pwm_size = pwm->pwm_config.force_pwm_size;
+ struct qpnp_lpg_chip *chip = pwm->chip;
+ struct pwm_period_config *period = &pwm->pwm_config.period;
/* PWM Period / N */
if (qpnp_check_gpled_lpg_channel(id))
@@ -443,6 +453,15 @@
period_n = (period_us >> n) * NSEC_PER_USEC;
}
+ if (force_pwm_size != 0) {
+ if (n < force_pwm_size)
+ period_n = period_n >> (force_pwm_size - n);
+ else
+ period_n = period_n << (n - force_pwm_size);
+ n = force_pwm_size;
+ pr_info("LPG channel '%d' pwm size is forced to=%d\n", id, n);
+ }
+
min_err = last_err = (unsigned)(-1);
best_m = 0;
best_clk = 0;
@@ -476,19 +495,20 @@
}
/* Adapt to optimal pwm size, the higher the resolution the better */
- if (qpnp_check_gpled_lpg_channel(id)) {
- if (n == 7 && best_m >= 1) {
- n += 1;
- best_m -= 1;
- }
- } else {
- if (n == 6 && best_m >= 3) {
- n += 3;
- best_m -= 3;
- } else {
- if (n == 6) {
- n += best_m;
- best_m -= best_m;
+ if (!force_pwm_size) {
+ if (qpnp_check_gpled_lpg_channel(id)) {
+ if (n == 7 && best_m >= 1) {
+ n += 1;
+ best_m -= 1;
+ }
+ } else if (n == 6) {
+ if (best_m >= 3) {
+ n += 3;
+ best_m -= 3;
+ } else if (best_m >= 1 &&
+ chip->sub_type != QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+ n += 1;
+ best_m -= 1;
}
}
}
@@ -1075,7 +1095,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm_config);
+ qpnp_lpg_calc_period(period_us, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1131,7 +1151,7 @@
period = &pwm_config->period;
if (pwm_config->pwm_period != period_us) {
- qpnp_lpg_calc_period(period_us, pwm_config);
+ qpnp_lpg_calc_period(period_us, pwm);
qpnp_lpg_save_period(pwm);
pwm_config->pwm_period = period_us;
}
@@ -1715,6 +1735,7 @@
struct pwm_device *pwm_dev = &chip->pwm_dev;
struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
struct qpnp_lut_config *lut_config = &lpg_config->lut_config;
+ int force_pwm_size = 0;
rc = of_property_read_u32(of_node, "qcom,channel-id",
&pwm_dev->pwm_config.channel_id);
@@ -1724,6 +1745,27 @@
goto out;
}
+ /*
+ * For cetrain LPG channels PWM size can be forced. So that
+ * for every requested pwm period closest pwm frequency is
+ * selected in qpnp_lpg_calc_period() for the forced pwm size.
+ */
+ rc = of_property_read_u32(of_node, "qcom,force-pwm-size",
+ &force_pwm_size);
+ if (qpnp_check_gpled_lpg_channel(pwm_dev->pwm_config.channel_id)) {
+ if (!(force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+ force_pwm_size == QPNP_PWM_SIZE_8_BIT))
+ force_pwm_size = 0;
+ } else if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+ if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+ force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+ force_pwm_size = 0;
+ } else if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+ force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+ force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+ force_pwm_size = 0;
+
+ pwm_dev->pwm_config.force_pwm_size = force_pwm_size;
res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
QPNP_LPG_CHANNEL_BASE);
if (!res) {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 6706e0d..49e57b9 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -190,6 +190,7 @@
struct mutex vbat_monitor_mutex;
struct mutex soc_invalidation_mutex;
struct mutex last_soc_mutex;
+ struct mutex status_lock;
bool use_external_rsense;
bool use_ocv_thresholds;
@@ -295,6 +296,7 @@
static enum power_supply_property msm_bms_power_props[] = {
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
@@ -3110,6 +3112,7 @@
{
int status = get_battery_status(chip);
+ mutex_lock(&chip->status_lock);
if (chip->battery_status != status) {
pr_debug("status = %d, shadow status = %d\n",
status, chip->battery_status);
@@ -3126,6 +3129,7 @@
pr_debug("battery full\n");
enable_bms_irq(&chip->ocv_thr_irq);
enable_bms_irq(&chip->sw_cc_thr_irq);
+ recalculate_soc(chip);
} else if (chip->battery_status
== POWER_SUPPLY_STATUS_FULL) {
pr_debug("battery not full any more\n");
@@ -3138,6 +3142,7 @@
* recalculation to update the SoC */
schedule_work(&chip->recalc_work);
}
+ mutex_unlock(&chip->status_lock);
}
#define CALIB_WRKARND_DIG_MAJOR_MAX 0x03
@@ -3212,6 +3217,9 @@
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = get_prop_bms_capacity(chip);
break;
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = chip->battery_status;
+ break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = get_prop_bms_current_now(chip);
break;
@@ -3989,6 +3997,7 @@
mutex_init(&chip->vbat_monitor_mutex);
mutex_init(&chip->soc_invalidation_mutex);
mutex_init(&chip->last_soc_mutex);
+ mutex_init(&chip->status_lock);
init_waitqueue_head(&chip->bms_wait_queue);
warm_reset = qpnp_pon_is_warm_reset();
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f9e05fc..6e9dc57 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1693,7 +1693,7 @@
get_prop_capacity(struct qpnp_chg_chip *chip)
{
union power_supply_propval ret = {0,};
- int battery_status, charger_in;
+ int battery_status, bms_status, soc, charger_in;
if (chip->use_default_batt_values || !get_prop_batt_present(chip))
return DEFAULT_CAPACITY;
@@ -1701,28 +1701,32 @@
if (chip->bms_psy) {
chip->bms_psy->get_property(chip->bms_psy,
POWER_SUPPLY_PROP_CAPACITY, &ret);
+ soc = ret.intval;
battery_status = get_prop_batt_status(chip);
+ chip->bms_psy->get_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_STATUS, &ret);
+ bms_status = ret.intval;
charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
qpnp_chg_is_dc_chg_plugged_in(chip);
if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+ && bms_status != POWER_SUPPLY_STATUS_CHARGING
&& charger_in
&& !chip->resuming_charging
&& !chip->charging_disabled
&& chip->soc_resume_limit
- && ret.intval <= chip->soc_resume_limit) {
- pr_debug("resuming charging at %d%% soc\n",
- ret.intval);
+ && soc <= chip->soc_resume_limit) {
+ pr_debug("resuming charging at %d%% soc\n", soc);
chip->resuming_charging = true;
qpnp_chg_set_appropriate_vbatdet(chip);
qpnp_chg_charge_en(chip, !chip->charging_disabled);
}
- if (ret.intval == 0) {
+ if (soc == 0) {
if (!qpnp_chg_is_usb_chg_plugged_in(chip)
&& !qpnp_chg_is_usb_chg_plugged_in(chip))
pr_warn_ratelimited("Battery 0, CHG absent\n");
}
- return ret.intval;
+ return soc;
} else {
pr_debug("No BMS supply registered return 50\n");
}
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 3abc3b9..b7bf74e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -33,6 +33,7 @@
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/security.h>
#include "binder.h"
@@ -1488,6 +1489,10 @@
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}
+ if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+ return_error = BR_FAILED_REPLY;
+ goto err_invalid_target_handle;
+ }
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
tmp = thread->transaction_stack;
@@ -1633,6 +1638,10 @@
fp->cookie, node->cookie);
goto err_binder_get_ref_for_node_failed;
}
+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+ return_error = BR_FAILED_REPLY;
+ goto err_binder_get_ref_for_node_failed;
+ }
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
@@ -1662,6 +1671,10 @@
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+ return_error = BR_FAILED_REPLY;
+ goto err_binder_get_ref_failed;
+ }
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
@@ -1715,6 +1728,11 @@
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
+ if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+ fput(file);
+ return_error = BR_FAILED_REPLY;
+ goto err_get_unused_fd_failed;
+ }
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd < 0) {
fput(file);
@@ -2748,6 +2766,9 @@
ret = -EBUSY;
goto err;
}
+ ret = security_binder_set_context_mgr(proc->tsk);
+ if (ret < 0)
+ goto err;
if (binder_context_mgr_uid != -1) {
if (binder_context_mgr_uid != current->cred->euid) {
binder_debug(BINDER_DEBUG_TOP_ERRORS,
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d102c22..5d58f16 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -342,7 +342,7 @@
#define HSIC_DBG1_REG 0x38
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
{ /* VDD_CX CORNER Voting */
[VDD_NONE] = RPM_VREG_CORNER_NONE,
[VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
@@ -359,6 +359,8 @@
{
int ret = 0;
int none_vol, min_vol, max_vol;
+ u32 tmp[3];
+ int len = 0;
if (!mehci->hsic_vddcx) {
mehci->vdd_type = VDDCX_CORNER;
@@ -373,6 +375,22 @@
}
mehci->vdd_type = VDDCX;
}
+
+ if (mehci->dev->of_node) {
+ of_get_property(mehci->dev->of_node,
+ "hsic,vdd-voltage-level",
+ &len);
+ if (len == sizeof(tmp)) {
+ of_property_read_u32_array(mehci->dev->of_node,
+ "hsic,vdd-voltage-level",
+ tmp, len/sizeof(*tmp));
+ vdd_val[mehci->vdd_type][VDD_NONE] = tmp[0];
+ vdd_val[mehci->vdd_type][VDD_MIN] = tmp[1];
+ vdd_val[mehci->vdd_type][VDD_MAX] = tmp[2];
+ } else {
+ dev_dbg(mehci->dev, "Use default vdd config\n");
+ }
+ }
}
none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 0aecaad..dd04f49 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -40,6 +40,7 @@
#include <mach/msm_xo.h>
#include <mach/msm_iomap.h>
#include <linux/debugfs.h>
+#include <mach/rpm-regulator.h>
#define MSM_USB_BASE (hcd->regs)
@@ -76,6 +77,7 @@
int wakeup_int_cnt;
bool wakeup_irq_enabled;
int wakeup_irq;
+ enum usb_vdd_type vdd_type;
};
static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -96,26 +98,87 @@
#define HSUSB_PHY_1P8_VOL_MAX 1800000 /* uV */
#define HSUSB_PHY_1P8_HPM_LOAD 50000 /* uA */
+#define HSUSB_PHY_VDD_DIG_VOL_NONE 0 /* uV */
#define HSUSB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
#define HSUSB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
#define HSUSB_PHY_VDD_DIG_LOAD 49360 /* uA */
+#define HSUSB_PHY_SUSP_DIG_VOL_P50 500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75 750000
+enum hsusb_vdd_value {
+ VDD_MIN_NONE = 0,
+ VDD_MIN_P50,
+ VDD_MIN_P75,
+ VDD_MIN_OP,
+ VDD_MAX_OP,
+ VDD_VAL_MAX_OP,
+};
+
+static int hsusb_vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX_OP] = {
+ { /* VDD_CX CORNER Voting */
+ [VDD_MIN_NONE] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN_P50] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN_P75] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN_OP] = RPM_VREG_CORNER_NOMINAL,
+ [VDD_MAX_OP] = RPM_VREG_CORNER_HIGH,
+ },
+ { /* VDD_CX Voltage Voting */
+ [VDD_MIN_NONE] = HSUSB_PHY_VDD_DIG_VOL_NONE,
+ [VDD_MIN_P50] = HSUSB_PHY_SUSP_DIG_VOL_P50,
+ [VDD_MIN_P75] = HSUSB_PHY_SUSP_DIG_VOL_P75,
+ [VDD_MIN_OP] = HSUSB_PHY_VDD_DIG_VOL_MIN,
+ [VDD_MAX_OP] = HSUSB_PHY_VDD_DIG_VOL_MAX,
+ },
+};
+
static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
{
int ret = 0;
+ int none_vol, min_vol, max_vol;
+ u32 tmp[5];
+ int len = 0;
- if (!init)
+ if (!init) {
+ none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+ max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
goto disable_reg;
-
- mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
- if (IS_ERR(mhcd->hsusb_vddcx)) {
- dev_err(mhcd->dev, "unable to get ehci vddcx\n");
- return PTR_ERR(mhcd->hsusb_vddcx);
}
- ret = regulator_set_voltage(mhcd->hsusb_vddcx,
- HSUSB_PHY_VDD_DIG_VOL_MIN,
- HSUSB_PHY_VDD_DIG_VOL_MAX);
+ mhcd->vdd_type = VDDCX_CORNER;
+ mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "hsusb_vdd_dig");
+ if (IS_ERR(mhcd->hsusb_vddcx)) {
+ mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev,
+ "HSUSB_VDDCX");
+ if (IS_ERR(mhcd->hsusb_vddcx)) {
+ dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+ return PTR_ERR(mhcd->hsusb_vddcx);
+ }
+ mhcd->vdd_type = VDDCX;
+ }
+
+ if (mhcd->dev->of_node) {
+ of_get_property(mhcd->dev->of_node,
+ "qcom,vdd-voltage-level",
+ &len);
+ if (len == sizeof(tmp)) {
+ of_property_read_u32_array(mhcd->dev->of_node,
+ "qcom,vdd-voltage-level",
+ tmp, len/sizeof(*tmp));
+ hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE] = tmp[0];
+ hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50] = tmp[1];
+ hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75] = tmp[2];
+ hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP] = tmp[3];
+ hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP] = tmp[4];
+ } else {
+ dev_dbg(mhcd->dev, "Use default vdd config\n");
+ }
+ }
+
+ none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+ min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
+ max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
+
+ ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
if (ret) {
dev_err(mhcd->dev, "unable to set the voltage"
"for ehci vddcx\n");
@@ -143,8 +206,7 @@
reg_enable_err:
regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
reg_optimum_mode_err:
- regulator_set_voltage(mhcd->hsusb_vddcx, 0,
- HSUSB_PHY_VDD_DIG_VOL_MIN);
+ regulator_set_voltage(mhcd->hsusb_vddcx, none_vol, max_vol);
return ret;
}
@@ -194,24 +256,22 @@
}
#ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL_P50 500000
-#define HSUSB_PHY_SUSP_DIG_VOL_P75 750000
static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
{
struct msm_usb_host_platform_data *pdata;
- int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+ int max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
int min_vol;
int ret;
pdata = mhcd->dev->platform_data;
if (high)
- min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+ min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
else if (pdata && pdata->dock_connect_irq &&
!irq_read_line(pdata->dock_connect_irq))
- min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
+ min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75];
else
- min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
+ min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50];
ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
if (ret) {
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index bf5b643..ac3fd3a 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -1219,7 +1219,8 @@
if (!mdp3_session->dma->config_lut)
return -EINVAL;
- if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+ if (cmap->start > MDP_LUT_SIZE || cmap->len > MDP_LUT_SIZE ||
+ (cmap->start + cmap->len > MDP_LUT_SIZE)) {
pr_err("mdp3_ctrl_lut_update invalid arguments\n");
return -EINVAL;
}
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 5ed89e4..5874286 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -292,12 +292,7 @@
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy);
- /*
- * NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
- * the default 16 for MDP hang issue workaround
- */
- MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
-
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x40);
dma->source_config = *source_config;
dma->output_config = *output_config;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 9c0daa9..17280ed 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -242,12 +242,28 @@
return ret;
}
+static ssize_t mdss_mdp_show_blank_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ int ret;
+
+ pr_debug("fb%d panel_power_on = %d\n", mfd->index, mfd->panel_power_on);
+ ret = scnprintf(buf, PAGE_SIZE, "panel_power_on = %d\n",
+ mfd->panel_power_on);
+
+ return ret;
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
+static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_type.attr,
&dev_attr_msm_fb_split.attr,
+ &dev_attr_show_blank_event.attr,
NULL,
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 8e805da..fcc87f6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -827,7 +827,7 @@
int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdss_mdp_pipe *pipe, *next;
+ struct mdss_mdp_pipe *pipe;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_ctl *tmp;
int ret;
@@ -847,8 +847,7 @@
return ret;
}
- list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
- used_list) {
+ list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
struct mdss_mdp_data *buf;
/*
* When external is connected and no dedicated wfd is present,
@@ -886,12 +885,6 @@
pipe->params_changed++;
buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
- if (pipe->mixer && !mdss_mdp_pipe_is_staged(pipe) &&
- !list_empty(&pipe->used_list)) {
- list_del_init(&pipe->used_list);
- list_add(&pipe->cleanup_list,
- &mdp5_data->pipes_cleanup);
- }
continue;
} else if (pipe->front_buf.num_planes) {
buf = &pipe->front_buf;
@@ -1454,14 +1447,9 @@
if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
return -EOPNOTSUPP;
- rc = mutex_lock_interruptible(&ctl->lock);
- if (rc)
- return rc;
-
if (!ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
- mutex_unlock(&ctl->lock);
return -EPERM;
}
@@ -1474,8 +1462,6 @@
rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- mutex_unlock(&ctl->lock);
-
return rc;
}
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 5df022e..6716ce3 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -43,6 +43,15 @@
* @reset_gpio: reset gpio
* @panel_x: panel maximum values on the x
* @panel_y: panel maximum values on the y
+ * @disp_maxx: display panel maximum values on the x
+ * @disp_maxy: display panel maximum values on the y
+ * @disp_minx: display panel minimum values on the x
+ * @disp_miny: display panel minimum values on the y
+ * @panel_maxx: touch panel maximum values on the x
+ * @panel_maxy: touch panel maximum values on the y
+ * @panel_minx: touch panel minimum values on the x
+ * @panel_miny: touch panel minimum values on the y
+ * @reset_delay: reset delay
* @gpio_config: pointer to gpio configuration function
* @capacitance_button_map: pointer to 0d button map
*/
@@ -52,12 +61,20 @@
bool i2c_pull_up;
bool power_down_enable;
bool disable_gpios;
+ bool do_lockdown;
unsigned irq_gpio;
u32 irq_flags;
u32 reset_flags;
unsigned reset_gpio;
- unsigned panel_x;
- unsigned panel_y;
+ unsigned panel_minx;
+ unsigned panel_miny;
+ unsigned panel_maxx;
+ unsigned panel_maxy;
+ unsigned disp_minx;
+ unsigned disp_miny;
+ unsigned disp_maxx;
+ unsigned disp_maxy;
+ unsigned reset_delay;
const char *fw_image_name;
int (*gpio_config)(unsigned gpio, bool configure);
struct synaptics_rmi4_capacitance_button_map *capacitance_button_map;
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index e8ca1cd..853899e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -63,6 +63,10 @@
(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
#define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_SET_HW_DELAY_RX _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
+#define AUDIO_SET_HW_DELAY_TX _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+40)
/* ACDB structures */
@@ -96,6 +100,11 @@
int status;
};
+struct hw_delay {
+ uint32_t num_entries;
+ void *delay_info;
+};
+
/* For Real-Time Audio Calibration */
#define AUDIO_GET_RTAC_ADM_INFO _IOR(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/security.h b/include/linux/security.h
index 673afbb..b62f396 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1381,6 +1381,11 @@
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
+ int (*binder_set_context_mgr) (struct task_struct *mgr);
+ int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+ int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+ int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
int (*ptrace_traceme) (struct task_struct *parent);
int (*capget) (struct task_struct *target,
@@ -1664,6 +1669,10 @@
/* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
int security_ptrace_traceme(struct task_struct *parent);
int security_capget(struct task_struct *target,
@@ -1842,6 +1851,26 @@
return 0;
}
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+ return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+ return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+ return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+ return 0;
+}
+
static inline int security_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c9be394..e1c096b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -706,6 +706,7 @@
#define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
#define V4L2_QCOM_BUF_DROP_FRAME 0x100000
#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
+#define V4L2_QCOM_BUF_FLAG_EOS 0x2000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index feef77f..bbda72e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1968,6 +1968,14 @@
*/
} __packed;
+#define AFE_PARAM_ID_DEVICE_HW_DELAY 0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY 0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+ uint32_t device_hw_delay_minor_version;
+ uint32_t delay_in_us;
+} __packed;
+
union afe_port_config {
struct afe_param_id_pcm_cfg pcm;
struct afe_param_id_i2s_cfg i2s;
@@ -1976,6 +1984,7 @@
struct afe_param_id_rt_proxy_port_cfg rtproxy;
struct afe_param_id_internal_bt_fm_cfg int_bt_fm;
struct afe_param_id_pseudo_port_cfg pseudo_port;
+ struct afe_param_id_device_hw_delay_cfg hw_delay;
} __packed;
struct afe_audioif_config_command_no_payload {
@@ -2481,6 +2490,8 @@
#define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
+
#define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee0..818920f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -127,7 +127,7 @@
/* Commands for resetting the watchdog */
static void __touch_watchdog(void)
{
- int this_cpu = smp_processor_id();
+ int this_cpu = raw_smp_processor_id();
__this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
}
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0131170..3db5820 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -154,7 +154,7 @@
* down, but we are still initializing the system. Pages are given directly
* to the page allocator, no bootmem metadata is updated because it is gone.
*/
-void __init free_bootmem_late(unsigned long addr, unsigned long size)
+void free_bootmem_late(unsigned long addr, unsigned long size)
{
unsigned long cursor, end;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9cc2f45..46ccd2f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -745,7 +745,7 @@
local_irq_restore(flags);
}
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
{
unsigned int nr_pages = 1 << order;
unsigned int loop;
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1..fc991bc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,26 @@
#include <linux/security.h>
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+ return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+ return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+ return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+ return 0;
+}
+
static int cap_syslog(int type)
{
return 0;
@@ -877,6 +897,10 @@
void __init security_fixup_ops(struct security_operations *ops)
{
+ set_to_cap_if_null(ops, binder_set_context_mgr);
+ set_to_cap_if_null(ops, binder_transaction);
+ set_to_cap_if_null(ops, binder_transfer_binder);
+ set_to_cap_if_null(ops, binder_transfer_file);
set_to_cap_if_null(ops, ptrace_access_check);
set_to_cap_if_null(ops, ptrace_traceme);
set_to_cap_if_null(ops, capget);
diff --git a/security/security.c b/security/security.c
index bf619ff..cecd55e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -130,6 +130,26 @@
/* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+ return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+ return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+ return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+ return security_ops->binder_transfer_file(from, to, file);
+}
+
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
return security_ops->ptrace_access_check(child, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d85b793..b28b7eb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1818,6 +1818,67 @@
/* Hook functions begin here. */
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+ u32 mysid = current_sid();
+ u32 mgrsid = task_sid(mgr);
+
+ return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+ u32 mysid = current_sid();
+ u32 fromsid = task_sid(from);
+ u32 tosid = task_sid(to);
+ int rc;
+
+ if (mysid != fromsid) {
+ rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+ if (rc)
+ return rc;
+ }
+
+ return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+ u32 fromsid = task_sid(from);
+ u32 tosid = task_sid(to);
+ return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+ u32 sid = task_sid(to);
+ struct file_security_struct *fsec = file->f_security;
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct inode_security_struct *isec = inode->i_security;
+ struct common_audit_data ad;
+ struct selinux_audit_data sad = {0,};
+ int rc;
+
+ COMMON_AUDIT_DATA_INIT(&ad, PATH);
+ ad.u.path = file->f_path;
+ ad.selinux_audit_data = &sad;
+
+ if (sid != fsec->sid) {
+ rc = avc_has_perm(sid, fsec->sid,
+ SECCLASS_FD,
+ FD__USE,
+ &ad);
+ if (rc)
+ return rc;
+ }
+
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
+ return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+ &ad);
+}
+
static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
@@ -5523,6 +5584,11 @@
static struct security_operations selinux_ops = {
.name = "selinux",
+ .binder_set_context_mgr = selinux_binder_set_context_mgr,
+ .binder_transaction = selinux_binder_transaction,
+ .binder_transfer_binder = selinux_binder_transfer_binder,
+ .binder_transfer_file = selinux_binder_transfer_file,
+
.ptrace_access_check = selinux_ptrace_access_check,
.ptrace_traceme = selinux_ptrace_traceme,
.capget = selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c5372..4a4a9ae 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -149,5 +149,6 @@
{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
{ "tun_socket",
{ COMMON_SOCK_PERMS, NULL } },
+ { "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
{ NULL }
};
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index c9e38e0..9a2d4d3 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -36,6 +36,7 @@
#define NUM_VOCPROC_BLOCKS (6 * MAX_NETWORKS)
#define ACDB_TOTAL_VOICE_ALLOCATION (ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)
+#define MAX_HW_DELAY_ENTRIES 25
struct sidetone_atomic_cal {
atomic_t enable;
@@ -98,6 +99,10 @@
/* Speaker protection */
struct msm_spk_prot_cfg spk_prot_cfg;
+
+ /* Av sync delay info */
+ struct hw_delay hw_delay_rx;
+ struct hw_delay hw_delay_tx;
};
static struct acdb_data acdb_data;
@@ -371,6 +376,122 @@
return result;
}
+int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
+{
+ int i, result = 0;
+ struct hw_delay *delay = NULL;
+ struct hw_delay_entry *info = NULL;
+ pr_debug("%s,\n", __func__);
+
+ if (entry == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ result = -EINVAL;
+ goto ret;
+ }
+ if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ result = -EINVAL;
+ goto ret;
+ }
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (path == RX_CAL)
+ delay = &acdb_data.hw_delay_rx;
+ else if (path == TX_CAL)
+ delay = &acdb_data.hw_delay_tx;
+
+ if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
+ pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__);
+ result = -EINVAL;
+ goto done;
+ }
+
+ info = (struct hw_delay_entry *)(delay->delay_info);
+ if (info == NULL) {
+ pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
+ result = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < delay->num_entries; i++) {
+ if (info[i].sample_rate == entry->sample_rate) {
+ entry->delay_usec = info[i].delay_usec;
+ break;
+ }
+ }
+ if (i == delay->num_entries) {
+ pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
+ __func__, entry->sample_rate);
+ result = -EFAULT;
+ }
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ret:
+ pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
+ __func__, path, entry->sample_rate, entry->delay_usec, result);
+ return result;
+}
+
+int store_hw_delay(int32_t path, void *arg)
+{
+ int result = 0;
+ struct hw_delay delay;
+ struct hw_delay *delay_dest = NULL;
+ pr_debug("%s,\n", __func__);
+
+ if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
+ pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
+ __func__, path);
+ result = -EINVAL;
+ goto done;
+ }
+ result = copy_from_user((void *)&delay, (void *)arg,
+ sizeof(struct hw_delay));
+ if (result) {
+ pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
+ __func__, result, path);
+ result = -EFAULT;
+ goto done;
+ }
+ if ((delay.num_entries <= 0) ||
+ (delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
+ pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n",
+ __func__, delay.num_entries);
+ result = -EINVAL;
+ goto done;
+ }
+ if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ result = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
+ __func__, path, delay.num_entries);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (path == RX_CAL)
+ delay_dest = &acdb_data.hw_delay_rx;
+ else if (path == TX_CAL)
+ delay_dest = &acdb_data.hw_delay_tx;
+
+ delay_dest->num_entries = delay.num_entries;
+
+ result = copy_from_user(delay_dest->delay_info,
+ delay.delay_info,
+ (sizeof(struct hw_delay_entry)*
+ delay.num_entries));
+ if (result) {
+ pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
+ __func__, result, path);
+ result = -EFAULT;
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return result;
+}
+
int get_anc_cal(struct acdb_cal_block *cal_block)
{
int result = 0;
@@ -998,6 +1119,29 @@
atomic_set(&acdb_data.valid_adm_custom_top, 1);
atomic_set(&acdb_data.valid_asm_custom_top, 1);
atomic_inc(&usage_count);
+
+ /* Allocate memory for hw delay entries */
+ mutex_lock(&acdb_data.acdb_mutex);
+ acdb_data.hw_delay_rx.num_entries = 0;
+ acdb_data.hw_delay_tx.num_entries = 0;
+ acdb_data.hw_delay_rx.delay_info =
+ kmalloc(sizeof(struct hw_delay_entry)*
+ MAX_HW_DELAY_ENTRIES,
+ GFP_KERNEL);
+ if (acdb_data.hw_delay_rx.delay_info == NULL) {
+ pr_err("%s : Failed to allocate av sync delay entries rx\n",
+ __func__);
+ }
+ acdb_data.hw_delay_tx.delay_info =
+ kmalloc(sizeof(struct hw_delay_entry)*
+ MAX_HW_DELAY_ENTRIES,
+ GFP_KERNEL);
+ if (acdb_data.hw_delay_tx.delay_info == NULL) {
+ pr_err("%s : Failed to allocate av sync delay entries tx\n",
+ __func__);
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
return result;
}
@@ -1238,6 +1382,12 @@
case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
result = deregister_vocvol_table();
goto done;
+ case AUDIO_SET_HW_DELAY_RX:
+ result = store_hw_delay(RX_CAL, (void *)arg);
+ goto done;
+ case AUDIO_SET_HW_DELAY_TX:
+ result = store_hw_delay(TX_CAL, (void *)arg);
+ goto done;
}
if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1393,6 +1543,9 @@
else
result = deregister_memory();
+ kfree(acdb_data.hw_delay_rx.delay_info);
+ kfree(acdb_data.hw_delay_tx.delay_info);
+
return result;
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index d9c1210..e2ca395 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -41,6 +41,11 @@
atomic_t cal_paddr;
};
+struct hw_delay_entry {
+ uint32_t sample_rate;
+ uint32_t delay_usec;
+};
+
uint32_t get_voice_rx_topology(void);
uint32_t get_voice_tx_topology(void);
uint32_t get_adm_rx_topology(void);
@@ -65,5 +70,6 @@
int get_sidetone_cal(struct sidetone_cal *cal_data);
int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
int get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);
#endif
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 62cc5db..9d4257f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -192,7 +192,7 @@
topology_id = get_adm_tx_topology();
if (topology_id == 0)
- topology_id = DEFAULT_COPP_TOPOLOGY;
+ topology_id = NULL_COPP_TOPOLOGY;
return topology_id;
}
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index f7be34c..59113fe 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -632,6 +632,71 @@
}
}
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+ struct hw_delay_entry delay_entry;
+ struct afe_audioif_config_command config;
+ int index = 0;
+ int ret = -EINVAL;
+
+ pr_debug("%s\n", __func__);
+
+ delay_entry.sample_rate = rate;
+ if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+ ret = get_hw_delay(TX_CAL, &delay_entry);
+ else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+ ret = get_hw_delay(RX_CAL, &delay_entry);
+
+ if (ret != 0) {
+ pr_warn("%s: Failed to get hw delay info\n", __func__);
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(port_id);
+ if (index < 0) {
+ pr_debug("%s: AFE port index invalid!\n", __func__);
+ goto fail_cmd;
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+ config.pdata.param_size = sizeof(config.port);
+
+ config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+ config.port.hw_delay.device_hw_delay_minor_version =
+ AFE_API_VERSION_DEVICE_HW_DELAY;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE hw delay for port %#x failed\n",
+ __func__, port_id);
+ goto fail_cmd;
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+fail_cmd:
+ pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
+ __func__, port_id, rate, delay_entry.delay_usec, ret);
+ return ret;
+
+}
+
void afe_send_cal(u16 port_id)
{
pr_debug("%s\n", __func__);
@@ -1248,6 +1313,7 @@
return ret;
afe_send_cal(port_id);
+ afe_send_hw_delay(port_id, rate);
/* Start SW MAD module */
mad_type = afe_port_get_mad_type(port_id);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index d758a71..9c0c362 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1607,7 +1607,7 @@
open.preprocopo_id = get_asm_topology();
if (open.preprocopo_id == 0)
- open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+ open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
open.bits_per_sample = bits_per_sample;
open.mode_flags = 0x0;
@@ -1706,7 +1706,7 @@
open.postprocopo_id = get_asm_topology();
if (open.postprocopo_id == 0)
- open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+ open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
switch (format) {
case FORMAT_LINEAR_PCM:
@@ -1790,7 +1790,7 @@
/* source endpoint : matrix */
open.postprocopo_id = get_asm_topology();
if (open.postprocopo_id == 0)
- open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+ open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
switch (wr_format) {
case FORMAT_LINEAR_PCM:
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index de98feb..55f8dc8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,8 +3231,11 @@
mutex_init(&card->dapm_power_mutex);
ret = snd_soc_instantiate_card(card);
- if (ret != 0)
+ if (ret != 0) {
soc_cleanup_card_debugfs(card);
+ if (card->rtd)
+ kfree(card->rtd);
+ }
return ret;