summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/spss_utils.txt4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi144
-rw-r--r--drivers/char/diag/diag_usb.c4
-rw-r--r--drivers/char/diag/diagchar.h2
-rw-r--r--drivers/char/diag/diagchar_core.c17
-rw-r--r--drivers/char/diag/diagfwd.c22
-rw-r--r--drivers/char/diag/diagfwd_cntl.c2
-rw-r--r--drivers/char/diag/diagfwd_socket.c108
-rw-r--r--drivers/char/diag/diagfwd_socket.h16
-rw-r--r--drivers/clk/qcom/clk-rcg.h2
-rw-r--r--drivers/clk/qcom/clk-rcg2.c97
-rw-r--r--drivers/crypto/msm/ice.c3
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c47
-rw-r--r--drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c23
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h12
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c74
-rw-r--r--drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h11
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c20
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c38
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c26
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c28
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c129
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c91
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/p2p.c160
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c110
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h25
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_crash_dump.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c159
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h586
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c19
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c17
-rw-r--r--drivers/regulator/cpr4-mmss-ldo-regulator.c12
-rw-r--r--drivers/soc/qcom/memshare/msm_memshare.c40
-rw-r--r--drivers/soc/qcom/pil-q6v5-mss.c2
-rw-r--r--drivers/soc/qcom/smcinvoke.c4
-rw-r--r--drivers/soc/qcom/spss_utils.c59
-rw-r--r--drivers/soc/qcom/subsys-pil-tz.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c292
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c98
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c512
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdcp_1x.c55
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c11
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c47
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c60
-rw-r--r--include/net/cfg80211.h1
-rw-r--r--include/uapi/media/msm_media_info.h16
-rw-r--r--net/ipc_router/ipc_router_core.c3
-rw-r--r--sound/soc/codecs/wcd9330.c7
-rw-r--r--sound/soc/codecs/wcd9335.c11
-rw-r--r--sound/soc/msm/qdsp6v2/msm-lsm-client.c131
-rw-r--r--sound/soc/msm/qdsp6v2/msm-qti-pp-config.c2
65 files changed, 2790 insertions, 653 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/spss_utils.txt b/Documentation/devicetree/bindings/arm/msm/spss_utils.txt
index 21b96377e5e4..61d3865b73d5 100644
--- a/Documentation/devicetree/bindings/arm/msm/spss_utils.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spss_utils.txt
@@ -15,13 +15,15 @@ Required properties:
-qcom,spss-fuse-bit: fuse relevant bit
-qcom,spss-test-firmware-name: test firmware file name
-qcom,spss-prod-firmware-name: production firmware file name
+-qcom,spss-debug-reg-addr: debug register physical address
Example:
qcom,spss_utils {
compatible = "qcom,spss-utils";
- qcom,spss-fuse-addr = <0x007841c4 0x4>; /* spss test fuse physical address */
+ qcom,spss-fuse-addr = <0x007841c4>; /* spss test fuse physical address */
qcom,spss-fuse-bit = <27>;
qcom,spss-test-firmware-name = "spss1t"; /* 8 chars max */
qcom,spss-prod-firmware-name = "spss1p"; /* 8 chars max */
+ qcom,spss-debug-reg-addr = <0x01d06020>;
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
index 976750d6a26f..799455a0de2e 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
@@ -574,9 +574,9 @@
0xaaa9aaa9
0xaaa9aaa9
0xaaa9aaa9>;
- vbif-entries = <3>;
- vbif-regs = <0x124 0xac 0xd0>;
- vbif-settings = <0x3 0x40 0x1010>;
+ vbif-entries = <1>;
+ vbif-regs = <0x124>;
+ vbif-settings = <0x3>;
ds-entries = <17>;
ds-regs = <0x424 0x428 0x42c 0x430 0x434
0x438 0x43c 0x440 0x444 0x448 0x44c
@@ -654,9 +654,9 @@
0xaaa9aaa9
0xaaa9aaa9
0xaaa9aaa9>;
- vbif-entries = <3>;
- vbif-regs = <0x124 0xac 0xd0>;
- vbif-settings = <0x3 0x40 0x1010>;
+ vbif-entries = <1>;
+ vbif-regs = <0x124>;
+ vbif-settings = <0x3>;
ds-entries = <17>;
ds-regs = <0x424 0x428 0x42c 0x430 0x434
0x438 0x43c 0x440 0x444 0x448 0x44c
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
index d29faacab5ee..a13475085e58 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-pm660.dtsi
@@ -239,3 +239,9 @@
#include "msm-pm660-rpm-regulator.dtsi"
#include "msm-pm660l-rpm-regulator.dtsi"
#include "sdm660-regulator.dtsi"
+
+&soc {
+ /* remove sdm660 MMSS CPR Controller node */
+ /delete-node/cpr4-ctrl@05061000;
+ /delete-node/regulator@01fcf004;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
index dd2efefe264f..845c96eb5ef4 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
@@ -170,6 +170,9 @@
<0x4a000 0x4a2bc>,
<0x55000 0x5522c>,
<0x57000 0x5722c>,
+ <0x61000 0x61014>,
+ <0x61800 0x61888>,
+ <0x62000 0x62088>,
<0x66000 0x662c0>,
<0x6b000 0x6b268>,
<0x6b800 0x6ba68>,
@@ -191,6 +194,7 @@
"LAYER_0", "LAYER_1", "LAYER_2",
"LAYER_3", "LAYER_4", "LAYER_5",
"DSPP_0", "DSPP_1",
+ "DEST_SCALER_OP", "DEST_SCALER_0", "DEST_SCALER_1",
"WB_2",
"INTF_0", "INTF_1", "INTF_2", "INTF_3",
"PP_0", "PP_1", "PP_4",
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index 7c3bb4101de7..068fd0901ca5 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -700,13 +700,13 @@
spi_4_active: spi_4_active {
mux {
pins = "gpio8", "gpio9",
- "gpio10", "gpio1";
+ "gpio10", "gpio11";
function = "blsp_spi4";
};
config {
pins = "gpio8", "gpio9",
- "gpio10", "gpio1";
+ "gpio10", "gpio11";
drive-strength = <6>;
bias-disable;
};
@@ -715,13 +715,13 @@
spi_4_sleep: spi_4_sleep {
mux {
pins = "gpio8", "gpio9",
- "gpio10", "gpio1";
+ "gpio10", "gpio11";
function = "blsp_spi4";
};
config {
pins = "gpio8", "gpio9",
- "gpio10", "gpio1";
+ "gpio10", "gpio11";
drive-strength = <6>;
bias-disable;
};
@@ -758,8 +758,8 @@
spi_5 {
spi_5_active: spi_5_active {
mux {
- pins = "gpio0", "gpio",
- "gpio2", "gpio3";
+ pins = "gpio85", "gpio86",
+ "gpio87", "gpio88";
function = "blsp_spi5";
};
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index ab835bf3aba1..91bd35a8ce07 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -1487,10 +1487,11 @@
spss_utils: qcom,spss_utils {
compatible = "qcom,spss-utils";
/* spss test fuse physical address */
- qcom,spss-fuse-addr = <0x007841c4 0x4>;
+ qcom,spss-fuse-addr = <0x007841c4>;
qcom,spss-fuse-bit = <27>;
qcom,spss-test-firmware-name = "spss"; /* default name */
qcom,spss-prod-firmware-name = "spss1p"; /* 8 chars max */
+ qcom,spss-debug-reg-addr = <0x01d06020>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index 4869a8af08d6..fc88c324e5e2 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -10,6 +10,10 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/clock/qcom,gpu-sdm660.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
&rpm_bus {
rpm-regulator-smpa4 {
status = "okay";
@@ -489,10 +493,144 @@
/* Stub regulators */
/ {
/* GFX Supply */
- gfx_vreg_corner: regulator-gfx-corner {
+ gfx_stub_vreg: regulator-gfx-stub {
compatible = "qcom,stub-regulator";
- regulator-name = "gfx_corner";
+ regulator-name = "gfx_stub_corner";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1070000>;
+ };
+};
+
+&soc {
+ /* MEM ACC regulators */
+ gfx_mem_acc_vreg: regulator@01fcf004 {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x01fcf004 0x4>;
+ reg-names = "acc-sel-l1";
+ regulator-name = "gfx_mem_acc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <7>;
+ regulator-max-microvolt = <2>;
+
+ qcom,corner-acc-map = <0x1 0x0>;
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,acc-sel-l1-bit-size = <1>;
+ };
+
+ gfx_ldo_vreg: ldo@0506e000 {
+ compatible = "qcom,sdm660-gfx-ldo";
+ reg = <0x0506e000 0x34>;
+ reg-names = "ldo_addr";
+ regulator-name = "msm_gfx_ldo";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <925000>;
+ };
+
+/* CPR controller regulators */
+ /* MMSS CPR Controller node */
+ gfx_cpr: cpr4-ctrl@05061000 {
+ compatible = "qcom,cpr4-sdm660-mmss-ldo-regulator";
+ reg = <0x05061000 0x4000>, <0x00784000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ clocks = <&clock_gfx GPUCC_RBCPR_CLK>,
+ <&clock_rpmcc RPM_CNOC_CLK>;
+ clock-names = "core_clk", "bus_clk";
+ interrupts = <GIC_SPI 285 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "cpr";
+ qcom,cpr-ctrl-name = "gfx";
+
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-step-quot-init-min = <12>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All at once */
+ qcom,cpr-count-repeat = <14>;
+
+ vdd-supply = <&gfx_stub_vreg>;
+ mem-acc-supply = <&gfx_mem_acc_vreg>;
+ system-supply = <&pm660l_s3_level>; /* vdd_cx */
+ qcom,voltage-step = <5000>;
+ vdd-thread0-ldo-supply = <&gfx_ldo_vreg>;
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ gfx_vreg_corner: regulator {
+ regulator-name = "gfx_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,cpr-fuse-corners = <6>;
+ qcom,cpr-fuse-combos = <8>;
+ qcom,cpr-corners = <7>;
+
+ qcom,cpr-corner-fmax-map = <1 2 3 4 5 6>;
+
+ qcom,cpr-voltage-ceiling =
+ <585000 645000 725000 790000
+ 870000 925000 1070000>;
+ qcom,cpr-voltage-floor =
+ <504000 504000 596000 652000
+ 712000 744000 1070000>;
+
+ qcom,mem-acc-voltage = <1 1 1 2 2 2 2>;
+ qcom,system-voltage =
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ qcom,corner-frequencies =
+ <160000000 266000000 370000000
+ 465000000 588000000 647000000
+ 800000000>;
+
+ qcom,cpr-target-quotients =
+ <0 0 0 0 0 0 202 193
+ 331 326 337 345 0 0 0 0>,
+ <0 0 0 0 0 0 202 193
+ 331 326 337 345 0 0 0 0>,
+ <0 0 0 0 0 0 317 300
+ 476 463 489 489 0 0 0 0>,
+ <0 0 0 0 0 0 411 387
+ 595 572 611 602 0 0 0 0>,
+ <0 0 0 0 0 0 522 489
+ 727 696 748 732 0 0 0 0>,
+ <0 0 0 0 0 0 606 568
+ 818 786 848 826 0 0 0 0>,
+ <0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0>;
+
+ qcom,cpr-ro-scaling-factor =
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 1740 1620
+ 2040 1960 2160 2040 0 0 0 0>,
+ < 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0>;
+
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ qcom,cpr-corner-allow-ldo-mode =
+ <0 0 0 0 0 0 0>;
+ qcom,cpr-corner-allow-closed-loop =
+ <0 0 0 0 0 0 0>;
+ };
+ };
};
};
diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c
index ca54b24ec604..0a0fc4400de5 100644
--- a/drivers/char/diag/diag_usb.c
+++ b/drivers/char/diag/diag_usb.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/ratelimit.h>
@@ -218,7 +219,8 @@ static void usb_disconnect(struct diag_usb_info *ch)
if (!ch)
return;
- if (!atomic_read(&ch->connected) && driver->usb_connected)
+ if (!atomic_read(&ch->connected) &&
+ driver->usb_connected && diag_mask_param())
diag_clear_masks(NULL);
if (ch && ch->ops && ch->ops->close)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 67db49badf21..409d2724042c 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -473,6 +473,7 @@ struct diagchar_dev {
int ref_count;
int mask_clear;
struct mutex diag_maskclear_mutex;
+ struct mutex diag_notifier_mutex;
struct mutex diagchar_mutex;
struct mutex diag_file_mutex;
wait_queue_head_t wait_q;
@@ -632,6 +633,7 @@ void diag_cmd_remove_reg(struct diag_cmd_reg_entry_t *entry, uint8_t proc);
void diag_cmd_remove_reg_by_pid(int pid);
void diag_cmd_remove_reg_by_proc(int proc);
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
+int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 76559633f387..7e63b7277d80 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -144,6 +144,14 @@ module_param(max_clients, uint, 0);
static struct timer_list drain_timer;
static int timer_in_progress;
+/*
+ * Diag Mask clear variable
+ * Used for clearing masks upon
+ * USB disconnection and stopping ODL
+ */
+static int diag_mask_clear_param = 1;
+module_param(diag_mask_clear_param, int, 0644);
+
struct diag_apps_data_t {
void *buf;
uint32_t len;
@@ -390,7 +398,10 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
return ret;
}
-
+int diag_mask_param(void)
+{
+ return diag_mask_clear_param;
+}
void diag_clear_masks(struct diag_md_session_t *info)
{
int ret;
@@ -423,7 +434,8 @@ static void diag_close_logging_process(const int pid)
if (!session_info)
return;
- diag_clear_masks(session_info);
+ if (diag_mask_clear_param)
+ diag_clear_masks(session_info);
mutex_lock(&driver->diag_maskclear_mutex);
driver->mask_clear = 1;
@@ -3400,6 +3412,7 @@ static int __init diagchar_init(void)
mutex_init(&driver->hdlc_disable_mutex);
mutex_init(&driver->diagchar_mutex);
mutex_init(&driver->diag_maskclear_mutex);
+ mutex_init(&driver->diag_notifier_mutex);
mutex_init(&driver->diag_file_mutex);
mutex_init(&driver->delayed_rsp_mutex);
mutex_init(&apps_data_mutex);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 876b455624b2..a7069bc0edf3 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1232,6 +1232,8 @@ static int diagfwd_mux_open(int id, int mode)
static int diagfwd_mux_close(int id, int mode)
{
+ uint8_t i;
+
switch (mode) {
case DIAG_USB_MODE:
driver->usb_connected = 0;
@@ -1252,10 +1254,22 @@ static int diagfwd_mux_close(int id, int mode)
*/
} else {
/*
- * With clearing of masks on ODL exit and
- * USB disconnection, closing of the channel is
- * not needed.This enables read and drop of stale packets.
- */
+ * With sysfs parameter to clear masks set,
+ * peripheral masks are cleared on ODL exit and
+ * USB disconnection and buffers are not marked busy.
+ * This enables read and drop of stale packets.
+ *
+ * With sysfs parameter to clear masks cleared,
+ * masks are not cleared and buffers are to be marked
+ * busy to ensure traffic generated by peripheral
+ * are not read
+ */
+ if (!(diag_mask_param())) {
+ for (i = 0; i < NUM_PERIPHERALS; i++) {
+ diagfwd_close(i, TYPE_DATA);
+ diagfwd_close(i, TYPE_CMD);
+ }
+ }
/* Re enable HDLC encoding */
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 9f43cb5427f0..62c8d0028af9 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -358,6 +358,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len,
feature_mask_len = FEATURE_MASK_LEN;
}
+ diag_cmd_remove_reg_by_proc(peripheral);
+
driver->feature[peripheral].rcvd_feature_mask = 1;
for (i = 0; i < feature_mask_len && read_len < len; i++) {
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index 217d20f72344..1b19e014af63 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -34,6 +34,9 @@
#include "diagfwd_socket.h"
#include "diag_ipc_logging.h"
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+
#define DIAG_SVC_ID 0x1001
#define MODEM_INST_BASE 0
@@ -50,6 +53,7 @@
#define INST_ID_DCI 4
struct diag_cntl_socket_info *cntl_socket;
+static uint64_t bootup_req[NUM_SOCKET_SUBSYSTEMS];
struct diag_socket_info socket_data[NUM_PERIPHERALS] = {
{
@@ -416,7 +420,7 @@ static void socket_open_client(struct diag_socket_info *info)
return;
}
__socket_open_channel(info);
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s opened client\n", info->name);
}
static void socket_open_server(struct diag_socket_info *info)
@@ -492,6 +496,13 @@ static void __socket_close_channel(struct diag_socket_info *info)
if (!atomic_read(&info->opened))
return;
+ if (bootup_req[info->peripheral] == PEPIPHERAL_SSR_UP) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s is up, stopping cleanup: bootup_req = %d\n",
+ info->name, (int)bootup_req[info->peripheral]);
+ return;
+ }
+
memset(&info->remote_addr, 0, sizeof(struct sockaddr_msm_ipc));
diagfwd_channel_close(info->fwd_ctxt);
@@ -610,7 +621,9 @@ static int cntl_socket_process_msg_client(uint32_t cmd, uint32_t node_id,
case CNTL_CMD_REMOVE_CLIENT:
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received remove client\n",
info->name);
+ mutex_lock(&driver->diag_notifier_mutex);
socket_close_channel(info);
+ mutex_unlock(&driver->diag_notifier_mutex);
break;
default:
return -EINVAL;
@@ -619,6 +632,25 @@ static int cntl_socket_process_msg_client(uint32_t cmd, uint32_t node_id,
return 0;
}
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
+
+struct restart_notifier_block {
+ unsigned processor;
+ char *name;
+ struct notifier_block nb;
+};
+
+static struct restart_notifier_block restart_notifiers[] = {
+ {SOCKET_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_ADSP, "adsp", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_SLPI, "slpi", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_CDSP, "cdsp", .nb.notifier_call = restart_notifier_cb},
+};
+
+
static void cntl_socket_read_work_fn(struct work_struct *work)
{
union cntl_port_msg msg;
@@ -626,7 +658,6 @@ static void cntl_socket_read_work_fn(struct work_struct *work)
struct kvec iov = { 0 };
struct msghdr read_msg = { 0 };
-
if (!cntl_socket)
return;
@@ -845,8 +876,11 @@ static int __diag_cntl_socket_init(void)
int diag_socket_init(void)
{
int err = 0;
+ int i;
int peripheral = 0;
+ void *handle;
struct diag_socket_info *info = NULL;
+ struct restart_notifier_block *nb;
for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
info = &socket_cntl[peripheral];
@@ -867,6 +901,17 @@ int diag_socket_init(void)
goto fail;
}
+ for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+ nb = &restart_notifiers[i];
+ if (nb) {
+ handle = subsys_notif_register_notifier(nb->name,
+ &nb->nb);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s: registering notifier for '%s', handle=%p\n",
+ __func__, nb->name, handle);
+ }
+ }
+
register_ipcrtr_af_init_notifier(&socket_notify);
fail:
return err;
@@ -902,6 +947,65 @@ static int socket_ready_notify(struct notifier_block *nb,
return 0;
}
+static int restart_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *_cmd)
+{
+ struct restart_notifier_block *notifier;
+
+ notifier = container_of(this,
+ struct restart_notifier_block, nb);
+ if (!notifier) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: invalid notifier block\n", __func__);
+ return NOTIFY_DONE;
+ }
+
+ mutex_lock(&driver->diag_notifier_mutex);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s: ssr for processor %d ('%s')\n",
+ __func__, notifier->processor, notifier->name);
+
+ switch (code) {
+
+ case SUBSYS_BEFORE_SHUTDOWN:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN;
+ break;
+
+ case SUBSYS_AFTER_SHUTDOWN:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_AFTER_SHUTDOWN\n", __func__);
+ break;
+
+ case SUBSYS_BEFORE_POWERUP:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_BEFORE_POWERUP\n", __func__);
+ break;
+
+ case SUBSYS_AFTER_POWERUP:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_AFTER_POWERUP\n", __func__);
+ if (!bootup_req[notifier->processor]) {
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN;
+ break;
+ }
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_UP;
+ break;
+
+ default:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: code: %lu\n", code);
+ break;
+ }
+ mutex_unlock(&driver->diag_notifier_mutex);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: bootup_req[%s] = %d\n",
+ notifier->name, (int)bootup_req[notifier->processor]);
+
+ return NOTIFY_DONE;
+}
+
int diag_socket_init_peripheral(uint8_t peripheral)
{
struct diag_socket_info *info = NULL;
diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h
index a2b922aa157c..a9487b1b3ac1 100644
--- a/drivers/char/diag/diagfwd_socket.h
+++ b/drivers/char/diag/diagfwd_socket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,10 +24,24 @@
#define PORT_TYPE_SERVER 0
#define PORT_TYPE_CLIENT 1
+#define PEPIPHERAL_AFTER_BOOT 0
+#define PEPIPHERAL_SSR_DOWN 1
+#define PEPIPHERAL_SSR_UP 2
+
#define CNTL_CMD_NEW_SERVER 4
#define CNTL_CMD_REMOVE_SERVER 5
#define CNTL_CMD_REMOVE_CLIENT 6
+enum {
+ SOCKET_MODEM,
+ SOCKET_ADSP,
+ SOCKET_WCNSS,
+ SOCKET_SLPI,
+ SOCKET_CDSP,
+ SOCKET_APPS,
+ NUM_SOCKET_SUBSYSTEMS,
+};
+
struct diag_socket_info {
uint8_t peripheral;
uint8_t type;
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index accdac9fb964..58fbd07e6f15 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -159,6 +159,7 @@ extern const struct clk_ops clk_dyn_rcg_ops;
* @parent_map: map from software's parent index to hardware's src_sel field
* @freq_tbl: frequency table
* @current_freq: last cached frequency when using branches with shared RCGs
+ * @enable_safe_config: When set, the RCG is parked at CXO when it's disabled
* @clkr: regmap clock handle
* @flags: set if RCG needs to be force enabled/disabled during
* power sequence.
@@ -173,6 +174,7 @@ struct clk_rcg2 {
unsigned long current_freq;
u32 new_index;
u32 curr_index;
+ bool enable_safe_config;
struct clk_regmap clkr;
u8 flags;
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 653722f9c4b0..c37716e8273d 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/rational.h>
#include <linux/math64.h>
+#include <linux/clk.h>
#include <asm/div64.h>
@@ -49,6 +50,14 @@
#define N_REG 0xc
#define D_REG 0x10
+static struct freq_tbl cxo_f = {
+ .freq = 19200000,
+ .src = 0,
+ .pre_div = 1,
+ .m = 0,
+ .n = 0,
+};
+
static int clk_rcg2_is_enabled(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -153,6 +162,17 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
return update_config(rcg);
}
+static void clk_rcg_clear_force_enable(struct clk_hw *hw)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+
+ /* force disable RCG - clear CMD_ROOT_EN bit */
+ regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+ CMD_ROOT_EN, 0);
+ /* Add a hardware mandate delay to disable the RCG */
+ udelay(100);
+}
+
/*
* Calculate m/n:d rate
*
@@ -184,6 +204,12 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
+ if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
+ if (!rcg->current_freq)
+ rcg->current_freq = cxo_f.freq;
+ return rcg->current_freq;
+ }
+
regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
if (rcg->mnd_width) {
@@ -425,14 +451,6 @@ static void disable_unprepare_rcg_srcs(struct clk_hw *hw, struct clk *curr,
clk_unprepare(new);
}
-static struct freq_tbl cxo_f = {
- .freq = 19200000,
- .src = 0,
- .pre_div = 1,
- .m = 0,
- .n = 0,
-};
-
static int clk_enable_disable_prepare_unprepare(struct clk_hw *hw, int cindex,
int nindex, bool enable)
{
@@ -452,6 +470,7 @@ static int clk_rcg2_enable(struct clk_hw *hw)
{
int ret = 0;
const struct freq_tbl *f;
+ unsigned long rate;
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
if (rcg->flags & FORCE_ENABLE_RCGR) {
@@ -477,9 +496,31 @@ static int clk_rcg2_enable(struct clk_hw *hw)
clk_enable_disable_prepare_unprepare(hw, rcg->curr_index,
rcg->new_index, false);
+
+ return ret;
}
- return ret;
+ if (!rcg->enable_safe_config)
+ return 0;
+
+ /*
+ * Switch from CXO to the stashed mux selection. Force enable and
+ * disable the RCG while configuring it to safeguard against any update
+ * signal coming from the downstream clock. The current parent has
+ * already been prepared and enabled at this point, and the CXO source
+ * is always on while APPS is online. Therefore, the RCG can safely be
+ * switched.
+ */
+ rate = clk_get_rate(hw->clk);
+ f = qcom_find_freq(rcg->freq_tbl, rate);
+ if (!f)
+ return -EINVAL;
+
+ clk_rcg_set_force_enable(hw);
+ clk_rcg2_configure(rcg, f);
+ clk_rcg_clear_force_enable(hw);
+
+ return 0;
}
static void clk_rcg2_disable(struct clk_hw *hw)
@@ -487,12 +528,31 @@ static void clk_rcg2_disable(struct clk_hw *hw)
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
if (rcg->flags & FORCE_ENABLE_RCGR) {
- /* force disable RCG - clear CMD_ROOT_EN bit */
- regmap_update_bits(rcg->clkr.regmap,
- rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0);
- /* Add a delay to disable the RCG */
- udelay(100);
+ clk_rcg_clear_force_enable(hw);
+ return;
}
+
+ if (!rcg->enable_safe_config)
+ return;
+ /*
+ * Park the RCG at a safe configuration - sourced off the CXO. This is
+ * needed for 2 reasons: In the case of RCGs sourcing PSCBCs, due to a
+ * default HW behavior, the RCG will turn on when its corresponding
+ * GDSC is enabled. We might also have cases when the RCG might be left
+ * enabled without the overlying SW knowing about it. This results from
+ * hard to track cases of downstream clocks being left enabled. In both
+ * these cases, scaling the RCG will fail since it's enabled but with
+ * its sources cut off.
+ *
+ * Save mux select and switch to CXO. Force enable and disable the RCG
+ * while configuring it to safeguard against any update signal coming
+ * from the downstream clock. The current parent is still prepared and
+ * enabled at this point, and the CXO source is always on while APPS is
+ * online. Therefore, the RCG can safely be switched.
+ */
+ clk_rcg_set_force_enable(hw);
+ clk_rcg2_configure(rcg, &cxo_f);
+ clk_rcg_clear_force_enable(hw);
}
@@ -506,6 +566,15 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
if (rcg->flags & FORCE_ENABLE_RCGR)
rcg->current_freq = clk_get_rate(hw->clk);
+ /*
+ * Return if the RCG is currently disabled. This configuration update
+ * will happen as part of the RCG enable sequence.
+ */
+ if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
+ rcg->current_freq = rate;
+ return 0;
+ }
+
f = qcom_find_freq(rcg->freq_tbl, rate);
if (!f)
return -EINVAL;
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index 795d553f3318..027a0d0bd0b8 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -1658,6 +1658,9 @@ int qcom_ice_setup_ice_hw(const char *storage_type, int enable)
struct ice_device *ice_dev = NULL;
ice_dev = get_ice_device_from_storage_type(storage_type);
+ if (ice_dev == ERR_PTR(-EPROBE_DEFER))
+ return -EPROBE_DEFER;
+
if (!ice_dev)
return ret;
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index fb2f27299417..11500fccc770 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -141,6 +141,7 @@ struct stm_drvdata {
bool enable;
DECLARE_BITMAP(entities, OST_ENTITY_MAX);
bool data_barrier;
+ uint32_t ch_alloc_fail_count;
};
static struct stm_drvdata *stmdrvdata;
@@ -385,19 +386,26 @@ static const struct coresight_ops stm_cs_ops = {
.source_ops = &stm_source_ops,
};
-static uint32_t stm_channel_alloc(uint32_t off)
+static uint32_t stm_channel_alloc(void)
{
struct stm_drvdata *drvdata = stmdrvdata;
- uint32_t ch;
- unsigned long flags;
+ uint32_t off, ch, num_ch_per_cpu;
+ int cpu;
- spin_lock_irqsave(&drvdata->spinlock, flags);
- do {
- ch = find_next_zero_bit(drvdata->chs.bitmap,
- NR_STM_CHANNEL, off);
- } while ((ch < NR_STM_CHANNEL) &&
- test_and_set_bit(ch, drvdata->chs.bitmap));
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ num_ch_per_cpu = NR_STM_CHANNEL/num_present_cpus();
+
+ cpu = get_cpu();
+
+ off = num_ch_per_cpu * cpu;
+ ch = find_next_zero_bit(drvdata->chs.bitmap,
+ NR_STM_CHANNEL, off);
+ if (ch > (off + num_ch_per_cpu)) {
+ put_cpu();
+ return NR_STM_CHANNEL;
+ }
+
+ set_bit(ch, drvdata->chs.bitmap);
+ put_cpu();
return ch;
}
@@ -405,11 +413,8 @@ static uint32_t stm_channel_alloc(uint32_t off)
static void stm_channel_free(uint32_t ch)
{
struct stm_drvdata *drvdata = stmdrvdata;
- unsigned long flags;
- spin_lock_irqsave(&drvdata->spinlock, flags);
clear_bit(ch, drvdata->chs.bitmap);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
}
static int stm_send(void *addr, const void *data, uint32_t size)
@@ -522,7 +527,14 @@ static inline int __stm_trace(uint32_t options, uint8_t entity_id,
unsigned long ch_addr;
/* allocate channel and get the channel address */
- ch = stm_channel_alloc(0);
+ ch = stm_channel_alloc();
+ if (ch >= NR_STM_CHANNEL) {
+ drvdata->ch_alloc_fail_count++;
+ dev_err_ratelimited(drvdata->dev,
+ "Channel allocation failed %d",
+ drvdata->ch_alloc_fail_count);
+ return 0;
+ }
ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
/* send the ost header */
@@ -789,15 +801,18 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
if (boot_nr_channel) {
res_size = min((resource_size_t)(boot_nr_channel *
BYTES_PER_CHANNEL), resource_size(&res));
- bitmap_size = boot_nr_channel * sizeof(long);
+ bitmap_size = (boot_nr_channel + sizeof(long) - 1) /
+ sizeof(long);
} else {
res_size = min((resource_size_t)(NR_STM_CHANNEL *
BYTES_PER_CHANNEL), resource_size(&res));
- bitmap_size = NR_STM_CHANNEL * sizeof(long);
+ bitmap_size = (NR_STM_CHANNEL + sizeof(long) - 1) /
+ sizeof(long);
}
drvdata->chs.base = devm_ioremap(dev, res.start, res_size);
if (!drvdata->chs.base)
return -ENOMEM;
+
drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
if (!drvdata->chs.bitmap)
return -ENOMEM;
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
index 6f438d59b30b..c243d587e308 100644
--- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
@@ -394,6 +394,12 @@ int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
+
+ if (cam_vreg == NULL) {
+ pr_err("%s:%d cam_vreg sequence invalid\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
index 31568da21fee..66eb3aebec83 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c
@@ -364,7 +364,7 @@ static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
msm_fd_hw_get(fd, ctx->settings.speed);
/* Get active buffer */
- active_buf = msm_fd_hw_get_active_buffer(fd);
+ active_buf = msm_fd_hw_get_active_buffer(fd, 1);
if (active_buf == NULL) {
dev_dbg(fd->dev, "no active buffer, return\n");
@@ -379,7 +379,7 @@ static int msm_fd_vbif_error_handler(void *handle, uint32_t error)
msm_fd_hw_add_buffer(fd, active_buf);
/* Schedule and restart */
- ret = msm_fd_hw_schedule_next_buffer(fd);
+ ret = msm_fd_hw_schedule_next_buffer(fd, 1);
if (ret) {
dev_err(fd->dev, "Cannot reschedule buffer, recovery failed\n");
fd->recovery_mode = 0;
@@ -1221,11 +1221,12 @@ static void msm_fd_wq_handler(struct work_struct *work)
int i;
fd = container_of(work, struct msm_fd_device, work);
-
- active_buf = msm_fd_hw_get_active_buffer(fd);
+ MSM_FD_SPIN_LOCK(fd->slock, 1);
+ active_buf = msm_fd_hw_get_active_buffer(fd, 0);
if (!active_buf) {
/* This should never happen, something completely wrong */
dev_err(fd->dev, "Oops no active buffer empty queue\n");
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
return;
}
ctx = vb2_get_drv_priv(active_buf->vb_v4l2_buf.vb2_buf.vb2_queue);
@@ -1254,8 +1255,10 @@ static void msm_fd_wq_handler(struct work_struct *work)
dev_dbg(fd->dev, "Got IRQ after Recovery\n");
}
- /* We have the data from fd hw, we can start next processing */
- msm_fd_hw_schedule_next_buffer(fd);
+ if (fd->state == MSM_FD_DEVICE_RUNNING) {
+ /* We have the data from fd hw, we can start next processing */
+ msm_fd_hw_schedule_next_buffer(fd, 0);
+ }
/* Return buffer to vb queue */
active_buf->vb_v4l2_buf.sequence = ctx->fh.sequence;
@@ -1270,8 +1273,12 @@ static void msm_fd_wq_handler(struct work_struct *work)
fd_event->frame_id = ctx->sequence;
v4l2_event_queue_fh(&ctx->fh, &event);
- /* Release buffer from the device */
- msm_fd_hw_buffer_done(fd, active_buf);
+ if (fd->state == MSM_FD_DEVICE_RUNNING) {
+ /* Release buffer from the device */
+ msm_fd_hw_buffer_done(fd, active_buf, 0);
+ }
+
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
}
/*
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
index 7505f0585d42..6eae2b8d56fb 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h
@@ -36,6 +36,18 @@
/* Max number of regulators defined in device tree */
#define MSM_FD_MAX_REGULATOR_NUM 3
+/* Conditional spin lock macro */
+#define MSM_FD_SPIN_LOCK(l, f) ({\
+ if (f) \
+ spin_lock(&l); \
+})
+
+/* Conditional spin unlock macro */
+#define MSM_FD_SPIN_UNLOCK(l, f) ({ \
+ if (f) \
+ spin_unlock(&l); \
+})
+
/*
* struct msm_fd_size - Structure contain FD size related values.
* @width: Image width.
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
index 21d42a77accb..ea0db4d64c6d 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c
@@ -1118,7 +1118,6 @@ static int msm_fd_hw_try_enable(struct msm_fd_device *fd,
int enabled = 0;
if (state == fd->state) {
-
fd->state = MSM_FD_DEVICE_RUNNING;
atomic_set(&buffer->active, 1);
@@ -1132,7 +1131,7 @@ static int msm_fd_hw_try_enable(struct msm_fd_device *fd,
* msm_fd_hw_next_buffer - Get next buffer from fd device processing queue.
* @fd: Fd device.
*/
-static struct msm_fd_buffer *msm_fd_hw_next_buffer(struct msm_fd_device *fd)
+struct msm_fd_buffer *msm_fd_hw_get_next_buffer(struct msm_fd_device *fd)
{
struct msm_fd_buffer *buffer = NULL;
@@ -1150,14 +1149,15 @@ static struct msm_fd_buffer *msm_fd_hw_next_buffer(struct msm_fd_device *fd)
void msm_fd_hw_add_buffer(struct msm_fd_device *fd,
struct msm_fd_buffer *buffer)
{
- spin_lock(&fd->slock);
+ MSM_FD_SPIN_LOCK(fd->slock, 1);
atomic_set(&buffer->active, 0);
init_completion(&buffer->completion);
INIT_LIST_HEAD(&buffer->list);
list_add_tail(&buffer->list, &fd->buf_queue);
- spin_unlock(&fd->slock);
+
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
}
/*
@@ -1173,8 +1173,7 @@ void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
struct msm_fd_buffer *active_buffer;
unsigned long time;
- spin_lock(&fd->slock);
-
+ MSM_FD_SPIN_LOCK(fd->slock, 1);
active_buffer = NULL;
list_for_each_entry_safe(curr_buff, temp, &fd->buf_queue, list) {
if (curr_buff->vb_v4l2_buf.vb2_buf.vb2_queue == vb2_q) {
@@ -1189,21 +1188,31 @@ void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
}
}
}
- spin_unlock(&fd->slock);
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
/* We need to wait active buffer to finish */
if (active_buffer) {
time = wait_for_completion_timeout(&active_buffer->completion,
msecs_to_jiffies(MSM_FD_PROCESSING_TIMEOUT_MS));
+
+ MSM_FD_SPIN_LOCK(fd->slock, 1);
if (!time) {
- /* Do a vb2 buffer done since it timed out */
- vb2_buffer_done(&active_buffer->vb_v4l2_buf.vb2_buf,
- VB2_BUF_STATE_DONE);
- /* Remove active buffer */
- msm_fd_hw_get_active_buffer(fd);
- /* Schedule if other buffers are present in device */
- msm_fd_hw_schedule_next_buffer(fd);
+ if (atomic_read(&active_buffer->active)) {
+ atomic_set(&active_buffer->active, 0);
+ /* Do a vb2 buffer done since it timed out */
+ vb2_buffer_done(
+ &active_buffer->vb_v4l2_buf.vb2_buf,
+ VB2_BUF_STATE_DONE);
+ /* Remove active buffer */
+ msm_fd_hw_get_active_buffer(fd, 0);
+ /* Schedule if other buffers are present */
+ msm_fd_hw_schedule_next_buffer(fd, 0);
+ } else {
+ dev_err(fd->dev, "activ buf no longer active\n");
+ }
}
+ fd->state = MSM_FD_DEVICE_IDLE;
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
}
return;
@@ -1215,22 +1224,19 @@ void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
* @buffer: Fd buffer.
*/
int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
- struct msm_fd_buffer *buffer)
+ struct msm_fd_buffer *buffer, u8 lock_flag)
{
int ret = 0;
-
- spin_lock(&fd->slock);
+ MSM_FD_SPIN_LOCK(fd->slock, lock_flag);
if (atomic_read(&buffer->active)) {
atomic_set(&buffer->active, 0);
complete_all(&buffer->completion);
} else {
- dev_err(fd->dev, "Buffer is not active\n");
ret = -1;
}
- spin_unlock(&fd->slock);
-
+ MSM_FD_SPIN_UNLOCK(fd->slock, lock_flag);
return ret;
}
@@ -1238,17 +1244,18 @@ int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
* msm_fd_hw_get_active_buffer - Get active buffer from fd processing queue.
* @fd: Fd device.
*/
-struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd)
+struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd,
+ u8 lock_flag)
{
struct msm_fd_buffer *buffer = NULL;
- spin_lock(&fd->slock);
+ MSM_FD_SPIN_LOCK(fd->slock, lock_flag);
if (!list_empty(&fd->buf_queue)) {
buffer = list_first_entry(&fd->buf_queue,
struct msm_fd_buffer, list);
list_del(&buffer->list);
}
- spin_unlock(&fd->slock);
+ MSM_FD_SPIN_UNLOCK(fd->slock, lock_flag);
return buffer;
}
@@ -1263,12 +1270,13 @@ int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd)
{
struct msm_fd_buffer *buf;
- spin_lock(&fd->slock);
- buf = msm_fd_hw_next_buffer(fd);
+ MSM_FD_SPIN_LOCK(fd->slock, 1);
+
+ buf = msm_fd_hw_get_next_buffer(fd);
if (buf)
msm_fd_hw_try_enable(fd, buf, MSM_FD_DEVICE_IDLE);
- spin_unlock(&fd->slock);
+ MSM_FD_SPIN_UNLOCK(fd->slock, 1);
msm_fd_hw_update_settings(fd, buf);
@@ -1281,26 +1289,26 @@ int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd)
*
* NOTE: This can be executed only when device is in running state.
*/
-int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd)
+int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd, u8 lock_flag)
{
struct msm_fd_buffer *buf;
int ret;
- spin_lock(&fd->slock);
+ MSM_FD_SPIN_LOCK(fd->slock, lock_flag);
/* We can schedule next buffer only in running state */
if (fd->state != MSM_FD_DEVICE_RUNNING) {
dev_err(fd->dev, "Can not schedule next buffer\n");
- spin_unlock(&fd->slock);
+ MSM_FD_SPIN_UNLOCK(fd->slock, lock_flag);
return -EBUSY;
}
- buf = msm_fd_hw_next_buffer(fd);
+ buf = msm_fd_hw_get_next_buffer(fd);
if (buf) {
ret = msm_fd_hw_try_enable(fd, buf, MSM_FD_DEVICE_RUNNING);
if (0 == ret) {
- dev_err(fd->dev, "Ouch can not process next buffer\n");
- spin_unlock(&fd->slock);
+ dev_err(fd->dev, "Can not process next buffer\n");
+ MSM_FD_SPIN_UNLOCK(fd->slock, lock_flag);
return -EBUSY;
}
} else {
@@ -1308,7 +1316,7 @@ int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd)
if (fd->recovery_mode)
dev_err(fd->dev, "No Buffer in recovery mode.Device Idle\n");
}
- spin_unlock(&fd->slock);
+ MSM_FD_SPIN_UNLOCK(fd->slock, lock_flag);
msm_fd_hw_update_settings(fd, buf);
diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h
index ea2e4cc1d117..62b381e5bfa6 100644
--- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h
+++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -71,12 +71,15 @@ void msm_fd_hw_remove_buffers_from_queue(struct msm_fd_device *fd,
struct vb2_queue *vb2_q);
int msm_fd_hw_buffer_done(struct msm_fd_device *fd,
- struct msm_fd_buffer *buffer);
+ struct msm_fd_buffer *buffer, u8 lock_flag);
+
+struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd,
+ u8 lock_flag);
-struct msm_fd_buffer *msm_fd_hw_get_active_buffer(struct msm_fd_device *fd);
+struct msm_fd_buffer *msm_fd_hw_get_next_buffer(struct msm_fd_device *fd);
int msm_fd_hw_schedule_and_start(struct msm_fd_device *fd);
-int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd);
+int msm_fd_hw_schedule_next_buffer(struct msm_fd_device *fd, u8 lock_flag);
#endif /* __MSM_FD_HW_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 13c6e000fefc..71ee9211a434 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -30,13 +30,10 @@
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#define VFE47_8996V1_VERSION 0x70000000
-#define VFE48_SDM660_VERSION 0x80000003
#define VFE47_BURST_LEN 3
-#define VFE48_SDM660_BURST_LEN 4
#define VFE47_FETCH_BURST_LEN 3
#define VFE47_STATS_BURST_LEN 3
-#define VFE48_SDM660_STATS_BURST_LEN 4
#define VFE47_UB_SIZE_VFE0 2048
#define VFE47_UB_SIZE_VFE1 1536
#define VFE47_UB_STATS_SIZE 144
@@ -1595,7 +1592,7 @@ void msm_vfe47_axi_cfg_wm_reg(
{
uint32_t val;
int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
- uint32_t wm_base, burst_len;
+ uint32_t wm_base;
wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]);
val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0x14);
@@ -1613,11 +1610,7 @@ void msm_vfe47_axi_cfg_wm_reg(
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C);
/* WR_BUFFER_CFG */
- if (vfe_dev->vfe_hw_version == VFE48_SDM660_VERSION)
- burst_len = VFE48_SDM660_BURST_LEN;
- else
- burst_len = VFE47_BURST_LEN;
- val = burst_len |
+ val = VFE47_BURST_LEN |
(stream_info->plane_cfg[vfe_idx][plane_idx].
output_height - 1) <<
2 |
@@ -2212,7 +2205,7 @@ void msm_vfe47_stats_clear_wm_reg(
void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev)
{
int i;
- uint32_t ub_offset = 0, stats_burst_len;
+ uint32_t ub_offset = 0;
uint32_t ub_size[VFE47_NUM_STATS_TYPE] = {
16, /* MSM_ISP_STATS_HDR_BE */
16, /* MSM_ISP_STATS_BG */
@@ -2231,14 +2224,9 @@ void msm_vfe47_stats_cfg_ub(struct vfe_device *vfe_dev)
else
pr_err("%s: incorrect VFE device\n", __func__);
- if (vfe_dev->vfe_hw_version == VFE48_SDM660_VERSION)
- stats_burst_len = VFE48_SDM660_STATS_BURST_LEN;
- else
- stats_burst_len = VFE47_STATS_BURST_LEN;
-
for (i = 0; i < VFE47_NUM_STATS_TYPE; i++) {
ub_offset -= ub_size[i];
- msm_camera_io_w(stats_burst_len << 30 |
+ msm_camera_io_w(VFE47_STATS_BURST_LEN << 30 |
ub_offset << 16 | (ub_size[i] - 1),
vfe_dev->vfe_base + VFE47_STATS_BASE(i) + 0x14);
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index b7724b4bf936..4527d6699b88 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -2913,15 +2913,14 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
break;
default: {
if (ioctl_ptr == NULL) {
- pr_err("Wrong ioctl_ptr %pK for cmd %u\n",
- ioctl_ptr, cmd);
+ pr_err("Wrong ioctl_ptr for cmd %u\n", cmd);
return -EINVAL;
}
*ioctl_ptr = arg;
if ((*ioctl_ptr == NULL) ||
((*ioctl_ptr)->ioctl_ptr == NULL)) {
- pr_err("Wrong arg %pK for cmd %u\n", arg, cmd);
+ pr_err("Error invalid ioctl argument cmd %u", cmd);
return -EINVAL;
}
break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index 800b2932854d..5376e1e4b6a4 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -502,6 +502,42 @@ static int32_t msm_flash_init(
return 0;
}
+#ifdef CONFIG_COMPAT
+static int32_t msm_flash_init_prepare(
+ struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ return msm_flash_init(flash_ctrl, flash_data);
+}
+#else
+static int32_t msm_flash_init_prepare(
+ struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ struct msm_flash_cfg_data_t flash_data_k;
+ struct msm_flash_init_info_t flash_init_info;
+ int32_t i = 0;
+
+ flash_data_k.cfg_type = flash_data->cfg_type;
+ for (i = 0; i < MAX_LED_TRIGGERS; i++) {
+ flash_data_k.flash_current[i] =
+ flash_data->flash_current[i];
+ flash_data_k.flash_duration[i] =
+ flash_data->flash_duration[i];
+ }
+
+ flash_data_k.cfg.flash_init_info = &flash_init_info;
+ if (copy_from_user(&flash_init_info,
+ (void *)(flash_data->cfg.flash_init_info),
+ sizeof(struct msm_flash_init_info_t))) {
+ pr_err("%s copy_from_user failed %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ return msm_flash_init(flash_ctrl, &flash_data_k);
+}
+#endif
+
static int32_t msm_flash_prepare(
struct msm_flash_ctrl_t *flash_ctrl)
{
@@ -665,7 +701,7 @@ static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl,
switch (flash_data->cfg_type) {
case CFG_FLASH_INIT:
- rc = msm_flash_init(flash_ctrl, flash_data);
+ rc = msm_flash_init_prepare(flash_ctrl, flash_data);
break;
case CFG_FLASH_RELEASE:
if (flash_ctrl->flash_state != MSM_CAMERA_FLASH_RELEASE) {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 57b4560acdb2..2fc130137c25 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -530,7 +530,7 @@ static int sde_rotator_import_buffer(struct sde_layer_buffer *buffer,
return ret;
}
-static int sde_rotator_secure_session_ctrl(struct sde_rot_entry *entry)
+static int sde_rotator_secure_session_ctrl(bool enable)
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
uint32_t sid_info;
@@ -546,8 +546,7 @@ static int sde_rotator_secure_session_ctrl(struct sde_rot_entry *entry)
desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
desc.args[2] = sizeof(uint32_t);
- if (!mdata->sec_cam_en &&
- (entry->item.flags & SDE_ROTATION_SECURE_CAMERA)) {
+ if (!mdata->sec_cam_en && enable) {
/*
* Enable secure camera operation
* Send SCM call to hypervisor to switch the
@@ -573,11 +572,8 @@ static int sde_rotator_secure_session_ctrl(struct sde_rot_entry *entry)
SDEROT_DBG("scm_call(1) ret=%d, resp=%x",
ret, resp);
- SDEROT_EVTLOG(1, entry->item.flags,
- entry->src_buf.p[0].addr,
- entry->dst_buf.p[0].addr);
- } else if (mdata->sec_cam_en && !(entry->item.flags &
- SDE_ROTATION_SECURE_CAMERA)) {
+ SDEROT_EVTLOG(1);
+ } else if (mdata->sec_cam_en && !enable) {
/*
* Disable secure camera operation
* Send SCM call to hypervisor to switch the
@@ -596,9 +592,7 @@ static int sde_rotator_secure_session_ctrl(struct sde_rot_entry *entry)
/* force smmu to reattach */
sde_smmu_secure_ctrl(1);
- SDEROT_EVTLOG(0, entry->item.flags,
- entry->src_buf.p[0].addr,
- entry->dst_buf.p[0].addr);
+ SDEROT_EVTLOG(0);
}
} else {
return 0;
@@ -618,6 +612,7 @@ static int sde_rotator_map_and_check_data(struct sde_rot_entry *entry)
struct sde_mdp_format_params *fmt;
struct sde_mdp_plane_sizes ps;
bool rotation;
+ bool secure;
input = &entry->item.input;
output = &entry->item.output;
@@ -628,7 +623,9 @@ static int sde_rotator_map_and_check_data(struct sde_rot_entry *entry)
if (IS_ERR_VALUE(ret))
return ret;
- ret = sde_rotator_secure_session_ctrl(entry);
+ secure = (entry->item.flags & SDE_ROTATION_SECURE_CAMERA) ?
+ true : false;
+ ret = sde_rotator_secure_session_ctrl(secure);
if (ret) {
SDEROT_ERR("failed secure session enabling/disabling %d\n",
ret);
@@ -2194,6 +2191,11 @@ static int sde_rotator_close(struct sde_rot_mgr *mgr,
return -EINVAL;
}
+ /*
+ * if secure camera session was enabled
+ * go back to non secure state
+ */
+ sde_rotator_secure_session_ctrl(false);
sde_rotator_release_rotator_perf_session(mgr, private);
list_del_init(&private->list);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 79013344b615..f2a9da737453 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1078,21 +1078,33 @@ static u32 sde_hw_rotator_wait_done_regdma(
spin_unlock_irqrestore(&rot->rotisr_lock, flags);
} else {
int cnt = 200;
+ bool pending;
do {
udelay(500);
- status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS);
+ last_isr = SDE_ROTREG_READ(rot->mdss_base,
+ REGDMA_CSR_REGDMA_INT_STATUS);
+ pending = sde_hw_rotator_pending_swts(rot, ctx, &swts);
cnt--;
- } while ((cnt > 0) && (status & ROT_BUSY_BIT)
- && ((status & ROT_ERROR_BIT) == 0));
+ } while ((cnt > 0) && pending &&
+ ((last_isr & REGDMA_INT_ERR_MASK) == 0));
- if (status & ROT_ERROR_BIT)
- SDEROT_ERR("Rotator error\n");
- else if (status & ROT_BUSY_BIT)
- SDEROT_ERR("Rotator busy\n");
+ if (last_isr & REGDMA_INT_ERR_MASK) {
+ SDEROT_ERR("Rotator error, ts:0x%X/0x%X status:%x\n",
+ ctx->timestamp, swts, last_isr);
+ sde_hw_rotator_dump_status(rot);
+ status = ROT_ERROR_BIT;
+ } else if (pending) {
+ SDEROT_ERR("Rotator timeout, ts:0x%X/0x%X status:%x\n",
+ ctx->timestamp, swts, last_isr);
+ sde_hw_rotator_dump_status(rot);
+ status = ROT_ERROR_BIT;
+ } else {
+ status = 0;
+ }
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR,
- 0xFFFF);
+ last_isr);
}
sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 17b419d408cd..8983b5f125c3 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -439,14 +439,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n",
__func__, wdev, wdev->iftype);
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
- wil_err(wil, "Already scanning\n");
- mutex_unlock(&wil->p2p_wdev_mutex);
- return -EAGAIN;
- }
- mutex_unlock(&wil->p2p_wdev_mutex);
-
/* check we are client side */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
@@ -463,12 +455,24 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY;
}
+ mutex_lock(&wil->mutex);
+
+ mutex_lock(&wil->p2p_wdev_mutex);
+ if (wil->scan_request || wil->p2p.discovery_started) {
+ wil_err(wil, "Already scanning\n");
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ rc = -EAGAIN;
+ goto out;
+ }
+ mutex_unlock(&wil->p2p_wdev_mutex);
+
/* social scan on P2P_DEVICE is handled as p2p search */
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
wil_p2p_is_social_scan(request)) {
if (!wil->p2p.p2p_dev_started) {
wil_err(wil, "P2P search requested on stopped P2P device\n");
- return -EIO;
+ rc = -EIO;
+ goto out;
}
wil->scan_request = request;
wil->radio_wdev = wdev;
@@ -477,7 +481,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
wil->radio_wdev = wil_to_wdev(wil);
wil->scan_request = NULL;
}
- return rc;
+ goto out;
}
(void)wil_p2p_stop_discovery(wil);
@@ -500,7 +504,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
if (rc) {
wil_err(wil, "set SSID for scan request failed: %d\n", rc);
- return rc;
+ goto out;
}
wil->scan_request = request;
@@ -533,7 +537,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
if (rc)
- goto out;
+ goto out_restore;
if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
cmd.cmd.discovery_mode = 1;
@@ -544,16 +548,45 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
-out:
+out_restore:
if (rc) {
del_timer_sync(&wil->scan_timer);
wil->radio_wdev = wil_to_wdev(wil);
wil->scan_request = NULL;
}
-
+out:
+ mutex_unlock(&wil->mutex);
return rc;
}
+static void wil_cfg80211_abort_scan(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+ wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
+
+ mutex_lock(&wil->mutex);
+ mutex_lock(&wil->p2p_wdev_mutex);
+
+ if (!wil->scan_request)
+ goto out;
+
+ if (wdev != wil->scan_request->wdev) {
+ wil_dbg_misc(wil, "abort scan was called on the wrong iface\n");
+ goto out;
+ }
+
+ if (wil->radio_wdev == wil->p2p_wdev)
+ wil_p2p_stop_radio_operations(wil);
+ else
+ wil_abort_scan(wil, true);
+
+out:
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->mutex);
+}
+
static void wil_print_crypto(struct wil6210_priv *wil,
struct cfg80211_crypto_settings *c)
{
@@ -759,6 +792,26 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return rc;
}
+static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ /* these parameters are explicitly not supported */
+ if (changed & (WIPHY_PARAM_RETRY_LONG |
+ WIPHY_PARAM_FRAG_THRESHOLD |
+ WIPHY_PARAM_RTS_THRESHOLD))
+ return -ENOTSUPP;
+
+ if (changed & WIPHY_PARAM_RETRY_SHORT) {
+ rc = wmi_set_mgmt_retry(wil, wiphy->retry_short);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie)
@@ -1025,16 +1078,8 @@ static int wil_remain_on_channel(struct wiphy *wiphy,
wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n",
__func__, chan->center_freq, duration, wdev->iftype);
- rc = wil_p2p_listen(wil, duration, chan, cookie);
- if (rc)
- return rc;
-
- wil->radio_wdev = wdev;
-
- cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
- GFP_KERNEL);
-
- return 0;
+ rc = wil_p2p_listen(wil, wdev, duration, chan, cookie);
+ return rc;
}
static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
@@ -1504,17 +1549,49 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
wil_dbg_misc(wil, "%s: entered\n", __func__);
mutex_lock(&wil->mutex);
+ mutex_lock(&wil->p2p_wdev_mutex);
wil_p2p_stop_radio_operations(wil);
p2p->p2p_dev_started = 0;
+ mutex_unlock(&wil->p2p_wdev_mutex);
mutex_unlock(&wil->mutex);
}
+static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ enum wmi_ps_profile_type ps_profile;
+ int rc;
+
+ if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) {
+ wil_err(wil, "set_power_mgmt not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ wil_dbg_misc(wil, "enabled=%d, timeout=%d\n",
+ enabled, timeout);
+
+ if (enabled)
+ ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT;
+ else
+ ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED;
+
+ rc = wmi_ps_dev_profile_cfg(wil, ps_profile);
+ if (rc)
+ wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc);
+
+ return rc;
+}
+
static struct cfg80211_ops wil_cfg80211_ops = {
.add_virtual_intf = wil_cfg80211_add_iface,
.del_virtual_intf = wil_cfg80211_del_iface,
.scan = wil_cfg80211_scan,
+ .abort_scan = wil_cfg80211_abort_scan,
.connect = wil_cfg80211_connect,
.disconnect = wil_cfg80211_disconnect,
+ .set_wiphy_params = wil_cfg80211_set_wiphy_params,
.change_virtual_intf = wil_cfg80211_change_iface,
.get_station = wil_cfg80211_get_station,
.dump_station = wil_cfg80211_dump_station,
@@ -1535,6 +1612,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
/* P2P device */
.start_p2p_device = wil_cfg80211_start_p2p_device,
.stop_p2p_device = wil_cfg80211_stop_p2p_device,
+ .set_power_mgmt = wil_cfg80211_set_power_mgmt,
};
static void wil_wiphy_init(struct wiphy *wiphy)
@@ -1551,7 +1629,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
BIT(NL80211_IFTYPE_MONITOR);
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
+ WIPHY_FLAG_PS_ON_BY_DEFAULT;
dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
__func__, wiphy->flags);
wiphy->probe_resp_offload =
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 5285ebc8b9af..fa061daa56d7 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -24,6 +24,7 @@
#include "boot_loader.h"
#define WAIT_FOR_HALP_VOTE_MS 100
+#define WAIT_FOR_SCAN_ABORT_MS 1000
bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
@@ -213,7 +214,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
memset(&sta->stats, 0, sizeof(sta->stats));
}
-static bool wil_ap_is_connected(struct wil6210_priv *wil)
+static bool wil_is_connected(struct wil6210_priv *wil)
{
int i;
@@ -267,7 +268,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
wil_bcast_fini(wil);
- netif_tx_stop_all_queues(ndev);
+ wil_update_net_queues_bh(wil, NULL, true);
netif_carrier_off(ndev);
if (test_bit(wil_status_fwconnected, wil->status)) {
@@ -283,8 +284,12 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
- if (!wil_ap_is_connected(wil))
+ if (!wil_is_connected(wil)) {
+ wil_update_net_queues_bh(wil, NULL, true);
clear_bit(wil_status_fwconnected, wil->status);
+ } else {
+ wil_update_net_queues_bh(wil, NULL, false);
+ }
break;
default:
break;
@@ -384,18 +389,19 @@ static void wil_fw_error_worker(struct work_struct *work)
wil->last_fw_recovery = jiffies;
+ wil_info(wil, "fw error recovery requested (try %d)...\n",
+ wil->recovery_count);
+ if (!no_fw_recovery)
+ wil->recovery_state = fw_recovery_running;
+ if (wil_wait_for_recovery(wil) != 0)
+ return;
+
mutex_lock(&wil->mutex);
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_MONITOR:
- wil_info(wil, "fw error recovery requested (try %d)...\n",
- wil->recovery_count);
- if (!no_fw_recovery)
- wil->recovery_state = fw_recovery_running;
- if (0 != wil_wait_for_recovery(wil))
- break;
-
+ /* silent recovery, upper layers will see disconnect */
__wil_down(wil);
__wil_up(wil);
break;
@@ -512,10 +518,13 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
+ INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock);
+ spin_lock_init(&wil->net_queue_lock);
+ wil->net_queue_stopped = 1;
init_waitqueue_head(&wil->wq);
wil_ftm_init(wil);
@@ -574,6 +583,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
cancel_work_sync(&wil->p2p.discovery_expired_work);
+ cancel_work_sync(&wil->p2p.delayed_listen_work);
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
mutex_unlock(&wil->mutex);
@@ -691,6 +701,19 @@ static int wil_target_reset(struct wil6210_priv *wil)
return 0;
}
+static void wil_collect_fw_info(struct wil6210_priv *wil)
+{
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+ u8 retry_short;
+ int rc;
+
+ rc = wmi_get_mgmt_retry(wil, &retry_short);
+ if (!rc) {
+ wiphy->retry_short = retry_short;
+ wil_dbg_misc(wil, "FW retry_short: %d\n", retry_short);
+ }
+}
+
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
le32_to_cpus(&r->base);
@@ -807,6 +830,31 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
return 0;
}
+void wil_abort_scan(struct wil6210_priv *wil, bool sync)
+{
+ int rc;
+
+ lockdep_assert_held(&wil->p2p_wdev_mutex);
+
+ if (!wil->scan_request)
+ return;
+
+ wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request);
+ del_timer_sync(&wil->scan_timer);
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ rc = wmi_abort_scan(wil);
+ if (!rc && sync)
+ wait_event_interruptible_timeout(wil->wq, !wil->scan_request,
+ msecs_to_jiffies(
+ WAIT_FOR_SCAN_ABORT_MS));
+
+ mutex_lock(&wil->p2p_wdev_mutex);
+ if (wil->scan_request) {
+ cfg80211_scan_done(wil->scan_request, true);
+ wil->scan_request = NULL;
+ }
+}
+
/*
* We reset all the structures, and we reset the UMAC.
* After calling this routine, you're expected to reload
@@ -859,13 +907,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
mutex_unlock(&wil->wmi_mutex);
mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
- wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
- wil->scan_request);
- del_timer_sync(&wil->scan_timer);
- cfg80211_scan_done(wil->scan_request, true);
- wil->scan_request = NULL;
- }
+ wil_abort_scan(wil, false);
mutex_unlock(&wil->p2p_wdev_mutex);
wil_mask_irq(wil);
@@ -876,7 +918,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
flush_workqueue(wil->wmi_wq);
wil_bl_crash_info(wil, false);
+ wil_disable_irq(wil);
rc = wil_target_reset(wil);
+ wil6210_clear_irq(wil);
+ wil_enable_irq(wil);
wil_rx_fini(wil);
if (rc) {
wil_bl_crash_info(wil, true);
@@ -942,6 +987,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
return rc;
}
+ wil_collect_fw_info(wil);
+
if (wil->platform_ops.notify) {
rc = wil->platform_ops.notify(wil->platform_handle,
WIL_PLATFORM_EVT_FW_RDY);
@@ -1058,17 +1105,11 @@ int __wil_down(struct wil6210_priv *wil)
}
wil_enable_irq(wil);
- wil_p2p_stop_radio_operations(wil);
wil_ftm_stop_operations(wil);
mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
- wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
- wil->scan_request);
- del_timer_sync(&wil->scan_timer);
- cfg80211_scan_done(wil->scan_request, true);
- wil->scan_request = NULL;
- }
+ wil_p2p_stop_radio_operations(wil);
+ wil_abort_scan(wil, false);
mutex_unlock(&wil->p2p_wdev_mutex);
wil_reset(wil, false);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index f4fca9d4eedf..05ecf3a00f57 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -235,7 +235,7 @@ int wil_if_add(struct wil6210_priv *wil)
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
- netif_tx_stop_all_queues(ndev);
+ wil_update_net_queues_bh(wil, NULL, true);
rc = register_netdev(ndev);
if (rc < 0) {
diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c
index 42148da111f1..24184cfc5da4 100644
--- a/drivers/net/wireless/ath/wil6210/p2p.c
+++ b/drivers/net/wireless/ath/wil6210/p2p.c
@@ -22,6 +22,43 @@
#define P2P_SEARCH_DURATION_MS 500
#define P2P_DEFAULT_BI 100
+static int wil_p2p_start_listen(struct wil6210_priv *wil)
+{
+ struct wil_p2p_info *p2p = &wil->p2p;
+ u8 channel = p2p->listen_chan.hw_value;
+ int rc;
+
+ lockdep_assert_held(&wil->mutex);
+
+ rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
+ if (rc) {
+ wil_err(wil, "wmi_p2p_cfg failed\n");
+ goto out;
+ }
+
+ rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
+ if (rc) {
+ wil_err(wil, "wmi_set_ssid failed\n");
+ goto out_stop;
+ }
+
+ rc = wmi_start_listen(wil);
+ if (rc) {
+ wil_err(wil, "wmi_start_listen failed\n");
+ goto out_stop;
+ }
+
+ INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
+ mod_timer(&p2p->discovery_timer,
+ jiffies + msecs_to_jiffies(p2p->listen_duration));
+out_stop:
+ if (rc)
+ wmi_stop_discovery(wil);
+
+out:
+ return rc;
+}
+
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
{
return (request->n_channels == 1) &&
@@ -46,7 +83,7 @@ int wil_p2p_search(struct wil6210_priv *wil,
wil_dbg_misc(wil, "%s: channel %d\n",
__func__, P2P_DMG_SOCIAL_CHANNEL);
- mutex_lock(&wil->mutex);
+ lockdep_assert_held(&wil->mutex);
if (p2p->discovery_started) {
wil_err(wil, "%s: search failed. discovery already ongoing\n",
@@ -103,22 +140,19 @@ out_stop:
wmi_stop_discovery(wil);
out:
- mutex_unlock(&wil->mutex);
return rc;
}
-int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
- struct ieee80211_channel *chan, u64 *cookie)
+int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
+ unsigned int duration, struct ieee80211_channel *chan,
+ u64 *cookie)
{
struct wil_p2p_info *p2p = &wil->p2p;
- u8 channel = P2P_DMG_SOCIAL_CHANNEL;
int rc;
if (!chan)
return -EINVAL;
- channel = chan->hw_value;
-
wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
mutex_lock(&wil->mutex);
@@ -129,35 +163,30 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
goto out;
}
- rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
- if (rc) {
- wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
- goto out;
- }
-
- rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
- if (rc) {
- wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
- goto out_stop;
- }
+ memcpy(&p2p->listen_chan, chan, sizeof(*chan));
+ *cookie = ++p2p->cookie;
+ p2p->listen_duration = duration;
- rc = wmi_start_listen(wil);
- if (rc) {
- wil_err(wil, "%s: wmi_start_listen failed\n", __func__);
- goto out_stop;
+ mutex_lock(&wil->p2p_wdev_mutex);
+ if (wil->scan_request) {
+ wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
+ p2p->pending_listen_wdev = wdev;
+ p2p->discovery_started = 1;
+ rc = 0;
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ goto out;
}
+ mutex_unlock(&wil->p2p_wdev_mutex);
- memcpy(&p2p->listen_chan, chan, sizeof(*chan));
- *cookie = ++p2p->cookie;
+ rc = wil_p2p_start_listen(wil);
+ if (rc)
+ goto out;
p2p->discovery_started = 1;
- INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
- mod_timer(&p2p->discovery_timer,
- jiffies + msecs_to_jiffies(duration));
+ wil->radio_wdev = wdev;
-out_stop:
- if (rc)
- wmi_stop_discovery(wil);
+ cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
+ GFP_KERNEL);
out:
mutex_unlock(&wil->mutex);
@@ -170,9 +199,14 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
u8 started = p2p->discovery_started;
if (p2p->discovery_started) {
- del_timer_sync(&p2p->discovery_timer);
+ if (p2p->pending_listen_wdev) {
+ /* discovery not really started, only pending */
+ p2p->pending_listen_wdev = NULL;
+ } else {
+ del_timer_sync(&p2p->discovery_timer);
+ wmi_stop_discovery(wil);
+ }
p2p->discovery_started = 0;
- wmi_stop_discovery(wil);
}
return started;
@@ -253,11 +287,57 @@ void wil_p2p_search_expired(struct work_struct *work)
if (started) {
mutex_lock(&wil->p2p_wdev_mutex);
- cfg80211_scan_done(wil->scan_request, 0);
- wil->scan_request = NULL;
- wil->radio_wdev = wil->wdev;
+ if (wil->scan_request) {
+ cfg80211_scan_done(wil->scan_request, 0);
+ wil->scan_request = NULL;
+ wil->radio_wdev = wil->wdev;
+ }
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ }
+}
+
+void wil_p2p_delayed_listen_work(struct work_struct *work)
+{
+ struct wil_p2p_info *p2p = container_of(work,
+ struct wil_p2p_info, delayed_listen_work);
+ struct wil6210_priv *wil = container_of(p2p,
+ struct wil6210_priv, p2p);
+ int rc;
+
+ mutex_lock(&wil->mutex);
+
+ wil_dbg_misc(wil, "Checking delayed p2p listen\n");
+ if (!p2p->discovery_started || !p2p->pending_listen_wdev)
+ goto out;
+
+ mutex_lock(&wil->p2p_wdev_mutex);
+ if (wil->scan_request) {
+ /* another scan started, wait again... */
mutex_unlock(&wil->p2p_wdev_mutex);
+ goto out;
}
+ mutex_unlock(&wil->p2p_wdev_mutex);
+
+ rc = wil_p2p_start_listen(wil);
+
+ mutex_lock(&wil->p2p_wdev_mutex);
+ if (rc) {
+ cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
+ p2p->cookie,
+ &p2p->listen_chan,
+ GFP_KERNEL);
+ wil->radio_wdev = wil->wdev;
+ } else {
+ cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
+ &p2p->listen_chan,
+ p2p->listen_duration, GFP_KERNEL);
+ wil->radio_wdev = p2p->pending_listen_wdev;
+ }
+ p2p->pending_listen_wdev = NULL;
+ mutex_unlock(&wil->p2p_wdev_mutex);
+
+out:
+ mutex_unlock(&wil->mutex);
}
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
@@ -265,8 +345,7 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
struct wil_p2p_info *p2p = &wil->p2p;
lockdep_assert_held(&wil->mutex);
-
- mutex_lock(&wil->p2p_wdev_mutex);
+ lockdep_assert_held(&wil->p2p_wdev_mutex);
if (wil->radio_wdev != wil->p2p_wdev)
goto out;
@@ -274,10 +353,8 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
if (!p2p->discovery_started) {
/* Regular scan on the p2p device */
if (wil->scan_request &&
- wil->scan_request->wdev == wil->p2p_wdev) {
- cfg80211_scan_done(wil->scan_request, 1);
- wil->scan_request = NULL;
- }
+ wil->scan_request->wdev == wil->p2p_wdev)
+ wil_abort_scan(wil, true);
goto out;
}
@@ -300,5 +377,4 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
out:
wil->radio_wdev = wil->wdev;
- mutex_unlock(&wil->p2p_wdev_mutex);
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 4c38520d4dd2..4ac9ba04afed 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -88,6 +88,18 @@ static inline int wil_vring_wmark_high(struct vring *vring)
return vring->size/4;
}
+/* returns true if num avail descriptors is lower than wmark_low */
+static inline int wil_vring_avail_low(struct vring *vring)
+{
+ return wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring);
+}
+
+/* returns true if num avail descriptors is higher than wmark_high */
+static inline int wil_vring_avail_high(struct vring *vring)
+{
+ return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring);
+}
+
/* wil_val_in_range - check if value in [min,max) */
static inline bool wil_val_in_range(int val, int min, int max)
{
@@ -1780,6 +1792,89 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return rc;
}
+/**
+ * Check status of tx vrings and stop/wake net queues if needed
+ *
+ * This function does one of two checks:
+ * In case check_stop is true, will check if net queues need to be stopped. If
+ * the conditions for stopping are met, netif_tx_stop_all_queues() is called.
+ * In case check_stop is false, will check if net queues need to be waked. If
+ * the conditions for waking are met, netif_tx_wake_all_queues() is called.
+ * vring is the vring which is currently being modified by either adding
+ * descriptors (tx) into it or removing descriptors (tx complete) from it. Can
+ * be null when irrelevant (e.g. connect/disconnect events).
+ *
+ * The implementation is to stop net queues if modified vring has low
+ * descriptor availability. Wake if all vrings are not in low descriptor
+ * availability and modified vring has high descriptor availability.
+ */
+static inline void __wil_update_net_queues(struct wil6210_priv *wil,
+ struct vring *vring,
+ bool check_stop)
+{
+ int i;
+
+ if (vring)
+ wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d",
+ (int)(vring - wil->vring_tx), check_stop,
+ wil->net_queue_stopped);
+ else
+ wil_dbg_txrx(wil, "check_stop=%d, stopped=%d",
+ check_stop, wil->net_queue_stopped);
+
+ if (check_stop == wil->net_queue_stopped)
+ /* net queues already in desired state */
+ return;
+
+ if (check_stop) {
+ if (!vring || unlikely(wil_vring_avail_low(vring))) {
+ /* not enough room in the vring */
+ netif_tx_stop_all_queues(wil_to_ndev(wil));
+ wil->net_queue_stopped = true;
+ wil_dbg_txrx(wil, "netif_tx_stop called\n");
+ }
+ return;
+ }
+
+ /* check wake */
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ struct vring *cur_vring = &wil->vring_tx[i];
+ struct vring_tx_data *txdata = &wil->vring_tx_data[i];
+
+ if (!cur_vring->va || !txdata->enabled || cur_vring == vring)
+ continue;
+
+ if (wil_vring_avail_low(cur_vring)) {
+ wil_dbg_txrx(wil, "vring %d full, can't wake\n",
+ (int)(cur_vring - wil->vring_tx));
+ return;
+ }
+ }
+
+ if (!vring || wil_vring_avail_high(vring)) {
+ /* enough room in the vring */
+ wil_dbg_txrx(wil, "calling netif_tx_wake\n");
+ netif_tx_wake_all_queues(wil_to_ndev(wil));
+ wil->net_queue_stopped = false;
+ }
+}
+
+void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
+ bool check_stop)
+{
+ spin_lock(&wil->net_queue_lock);
+ __wil_update_net_queues(wil, vring, check_stop);
+ spin_unlock(&wil->net_queue_lock);
+}
+
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
+ bool check_stop)
+{
+ spin_lock_bh(&wil->net_queue_lock);
+ __wil_update_net_queues(wil, vring, check_stop);
+ spin_unlock_bh(&wil->net_queue_lock);
+}
+
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1822,14 +1917,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
- /* do we still have enough room in the vring? */
- if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) {
- netif_tx_stop_all_queues(wil_to_ndev(wil));
- wil_dbg_txrx(wil, "netif_tx_stop : ring full\n");
- }
-
switch (rc) {
case 0:
+ /* shall we stop net queues? */
+ wil_update_net_queues_bh(wil, vring, true);
/* statistics will be updated on the tx_complete */
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -1978,10 +2069,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
txdata->last_idle = get_cycles();
}
- if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) {
- wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n");
- netif_tx_wake_all_queues(wil_to_ndev(wil));
- }
+ /* shall we wake net queues? */
+ if (done)
+ wil_update_net_queues(wil, vring, false);
return done;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a19dba5b9e5f..bab0ed20c8c4 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -280,10 +280,11 @@ struct fw_map {
u32 to; /* linker address - to, exclusive */
u32 host; /* PCI/Host address - BAR0 + 0x880000 */
const char *name; /* for debugfs */
+ bool fw; /* true if FW mapping, false if UCODE mapping */
};
/* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[8];
+extern const struct fw_map fw_mapping[10];
/**
* mk_cidxtid - construct @cidxtid field
@@ -465,8 +466,11 @@ struct wil_p2p_info {
u8 discovery_started;
u8 p2p_dev_started;
u64 cookie;
+ struct wireless_dev *pending_listen_wdev;
+ unsigned int listen_duration;
struct timer_list discovery_timer; /* listen/search duration */
struct work_struct discovery_expired_work; /* listen/search expire */
+ struct work_struct delayed_listen_work; /* listen after scan done */
};
enum wil_sta_status {
@@ -628,6 +632,8 @@ struct wil6210_priv {
* - consumed in thread by wmi_event_worker
*/
spinlock_t wmi_ev_lock;
+ spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
+ int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
struct napi_struct napi_rx;
struct napi_struct napi_tx;
/* keep alive */
@@ -823,6 +829,10 @@ int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
+int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
+ enum wmi_ps_profile_type ps_profile);
+int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
+int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl);
@@ -843,13 +853,15 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
void wil_p2p_discovery_timer_fn(ulong x);
int wil_p2p_search(struct wil6210_priv *wil,
struct cfg80211_scan_request *request);
-int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
- struct ieee80211_channel *chan, u64 *cookie);
+int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
+ unsigned int duration, struct ieee80211_channel *chan,
+ u64 *cookie);
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
void wil_p2p_listen_expired(struct work_struct *work);
void wil_p2p_search_expired(struct work_struct *work);
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil);
+void wil_p2p_delayed_listen_work(struct work_struct *work);
/* WMI for P2P */
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
@@ -877,6 +889,9 @@ int wmi_pcp_stop(struct wil6210_priv *wil);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
int wmi_aoa_meas(struct wil6210_priv *wil, const void *mac_addr, u8 chan,
u8 type);
+int wmi_abort_scan(struct wil6210_priv *wil);
+void wil_abort_scan(struct wil6210_priv *wil, bool sync);
+
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
void wil_probe_client_flush(struct wil6210_priv *wil);
@@ -894,6 +909,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
int wil_bcast_init(struct wil6210_priv *wil);
void wil_bcast_fini(struct wil6210_priv *wil);
+void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
+ bool should_stop);
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
+ bool check_stop);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int wil_tx_complete(struct wil6210_priv *wil, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
index b57d280946e0..d051eea47a54 100644
--- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
+++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
@@ -36,6 +36,9 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) {
map = &fw_mapping[i];
+ if (!map->fw)
+ continue;
+
if (map->host < host_min)
host_min = map->host;
@@ -73,6 +76,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
map = &fw_mapping[i];
+ if (!map->fw)
+ continue;
+
data = (void * __force)wil->csr + HOSTADDR(map->host);
len = map->to - map->from;
offset = map->host - host_min;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index f5575747d11e..24f42e3a6d92 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -85,19 +85,29 @@ MODULE_PARM_DESC(led_id,
* array size should be in sync with the declaration in the wil6210.h
*/
const struct fw_map fw_mapping[] = {
- {0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */
- {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */
- {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */
- {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
- {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
- {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
- {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */
- {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
- /*
- * 920000..930000 ucode code RAM
- * 930000..932000 ucode data RAM
- * 932000..949000 back-door debug data
+ /* FW code RAM 256k */
+ {0x000000, 0x040000, 0x8c0000, "fw_code", true},
+ /* FW data RAM 32k */
+ {0x800000, 0x808000, 0x900000, "fw_data", true},
+ /* periph data 128k */
+ {0x840000, 0x860000, 0x908000, "fw_peri", true},
+ /* various RGF 40k */
+ {0x880000, 0x88a000, 0x880000, "rgf", true},
+ /* AGC table 4k */
+ {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
+ /* Pcie_ext_rgf 4k */
+ {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
+ /* mac_ext_rgf 512b */
+ {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true},
+ /* upper area 548k */
+ {0x8c0000, 0x949000, 0x8c0000, "upper", true},
+ /* UCODE areas - accessible by debugfs blobs but not by
+ * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
*/
+ /* ucode code RAM 128k */
+ {0x000000, 0x020000, 0x920000, "uc_code", false},
+ /* ucode data RAM 16k */
+ {0x800000, 0x804000, 0x940000, "uc_data", false},
};
struct blink_on_off_time led_blink_time[] = {
@@ -109,7 +119,7 @@ struct blink_on_off_time led_blink_time[] = {
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
/**
- * return AHB address for given firmware/ucode internal (linker) address
+ * return AHB address for given firmware internal (linker) address
* @x - internal address
* If address have no valid AHB mapping, return 0
*/
@@ -118,7 +128,8 @@ static u32 wmi_addr_remap(u32 x)
uint i;
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
- if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
+ if (fw_mapping[i].fw &&
+ ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)))
return x + fw_mapping[i].host - fw_mapping[i].from;
}
@@ -428,9 +439,11 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
mutex_lock(&wil->p2p_wdev_mutex);
if (wil->scan_request) {
struct wmi_scan_complete_event *data = d;
- bool aborted = (data->status != WMI_SCAN_SUCCESS);
+ int status = le32_to_cpu(data->status);
+ bool aborted = (status != WMI_SCAN_SUCCESS) &&
+ (status != WMI_SCAN_ABORT_REJECTED);
- wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
+ wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
wil->scan_request, aborted);
@@ -438,6 +451,11 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
cfg80211_scan_done(wil->scan_request, aborted);
wil->radio_wdev = wil->wdev;
wil->scan_request = NULL;
+ wake_up_interruptible(&wil->wq);
+ if (wil->p2p.pending_listen_wdev) {
+ wil_dbg_misc(wil, "Scheduling delayed listen\n");
+ schedule_work(&wil->p2p.delayed_listen_work);
+ }
} else {
wil_err(wil, "SCAN_COMPLETE while not scanning\n");
}
@@ -547,7 +565,6 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (rc) {
- netif_tx_stop_all_queues(ndev);
netif_carrier_off(ndev);
wil_err(wil,
"%s: cfg80211_connect_result with failure\n",
@@ -587,7 +604,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
wil->sta[evt->cid].status = wil_sta_connected;
set_bit(wil_status_fwconnected, wil->status);
- netif_tx_wake_all_queues(ndev);
+ wil_update_net_queues_bh(wil, NULL, false);
out:
if (rc)
@@ -1595,6 +1612,112 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
return rc;
}
+int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
+ enum wmi_ps_profile_type ps_profile)
+{
+ int rc;
+ struct wmi_ps_dev_profile_cfg_cmd cmd = {
+ .ps_profile = ps_profile,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_ps_dev_profile_cfg_event evt;
+ } __packed reply;
+ u32 status;
+
+ wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile);
+
+ reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
+
+ rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
+ WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
+ 100);
+ if (rc)
+ return rc;
+
+ status = le32_to_cpu(reply.evt.status);
+
+ if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) {
+ wil_err(wil, "ps dev profile cfg failed with status %d\n",
+ status);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
+{
+ int rc;
+ struct wmi_set_mgmt_retry_limit_cmd cmd = {
+ .mgmt_retry_limit = retry_short,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_set_mgmt_retry_limit_event evt;
+ } __packed reply;
+
+ wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short);
+
+ if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
+ return -ENOTSUPP;
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
+ WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
+ 100);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "set mgmt retry limit failed with status %d\n",
+ reply.evt.status);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
+{
+ int rc;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_get_mgmt_retry_limit_event evt;
+ } __packed reply;
+
+ wil_dbg_wmi(wil, "getting mgmt retry short\n");
+
+ if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities))
+ return -ENOTSUPP;
+
+ reply.evt.mgmt_retry_limit = 0;
+ rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
+ WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
+ 100);
+ if (rc)
+ return rc;
+
+ if (retry_short)
+ *retry_short = reply.evt.mgmt_retry_limit;
+
+ return 0;
+}
+
+int wmi_abort_scan(struct wil6210_priv *wil)
+{
+ int rc;
+
+ wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
+
+ rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
+ if (rc)
+ wil_err(wil, "Failed to abort scan (%d)\n", rc);
+
+ return rc;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index f430e8a80603..d93a4d490d24 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -35,6 +35,7 @@
#define WMI_MAC_LEN (6)
#define WMI_PROX_RANGE_NUM (3)
#define WMI_MAX_LOSS_DMG_BEACONS (20)
+#define MAX_NUM_OF_SECTORS (128)
/* Mailbox interface
* used for commands and events
@@ -51,8 +52,10 @@ enum wmi_mid {
* the host
*/
enum wmi_fw_capability {
- WMI_FW_CAPABILITY_FTM = 0,
- WMI_FW_CAPABILITY_PS_CONFIG = 1,
+ WMI_FW_CAPABILITY_FTM = 0,
+ WMI_FW_CAPABILITY_PS_CONFIG = 1,
+ WMI_FW_CAPABILITY_RF_SECTORS = 2,
+ WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3,
WMI_FW_CAPABILITY_MAX,
};
@@ -66,137 +69,149 @@ struct wmi_cmd_hdr {
/* List of Commands */
enum wmi_command_id {
- WMI_CONNECT_CMDID = 0x01,
- WMI_DISCONNECT_CMDID = 0x03,
- WMI_DISCONNECT_STA_CMDID = 0x04,
- WMI_START_SCAN_CMDID = 0x07,
- WMI_SET_BSS_FILTER_CMDID = 0x09,
- WMI_SET_PROBED_SSID_CMDID = 0x0A,
- WMI_SET_LISTEN_INT_CMDID = 0x0B,
- WMI_BCON_CTRL_CMDID = 0x0F,
- WMI_ADD_CIPHER_KEY_CMDID = 0x16,
- WMI_DELETE_CIPHER_KEY_CMDID = 0x17,
- WMI_PCP_CONF_CMDID = 0x18,
- WMI_SET_APPIE_CMDID = 0x3F,
- WMI_SET_WSC_STATUS_CMDID = 0x41,
- WMI_PXMT_RANGE_CFG_CMDID = 0x42,
- WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43,
- WMI_MEM_READ_CMDID = 0x800,
- WMI_MEM_WR_CMDID = 0x801,
- WMI_ECHO_CMDID = 0x803,
- WMI_DEEP_ECHO_CMDID = 0x804,
- WMI_CONFIG_MAC_CMDID = 0x805,
- WMI_CONFIG_PHY_DEBUG_CMDID = 0x806,
- WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808,
- WMI_PHY_GET_STATISTICS_CMDID = 0x809,
- WMI_FS_TUNE_CMDID = 0x80A,
- WMI_CORR_MEASURE_CMDID = 0x80B,
- WMI_READ_RSSI_CMDID = 0x80C,
- WMI_TEMP_SENSE_CMDID = 0x80E,
- WMI_DC_CALIB_CMDID = 0x80F,
- WMI_SEND_TONE_CMDID = 0x810,
- WMI_IQ_TX_CALIB_CMDID = 0x811,
- WMI_IQ_RX_CALIB_CMDID = 0x812,
- WMI_SET_UCODE_IDLE_CMDID = 0x813,
- WMI_SET_WORK_MODE_CMDID = 0x815,
- WMI_LO_LEAKAGE_CALIB_CMDID = 0x816,
- WMI_MARLON_R_READ_CMDID = 0x818,
- WMI_MARLON_R_WRITE_CMDID = 0x819,
- WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A,
- MAC_IO_STATIC_PARAMS_CMDID = 0x81B,
- MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C,
- WMI_SILENT_RSSI_CALIB_CMDID = 0x81D,
- WMI_RF_RX_TEST_CMDID = 0x81E,
- WMI_CFG_RX_CHAIN_CMDID = 0x820,
- WMI_VRING_CFG_CMDID = 0x821,
- WMI_BCAST_VRING_CFG_CMDID = 0x822,
- WMI_VRING_BA_EN_CMDID = 0x823,
- WMI_VRING_BA_DIS_CMDID = 0x824,
- WMI_RCP_ADDBA_RESP_CMDID = 0x825,
- WMI_RCP_DELBA_CMDID = 0x826,
- WMI_SET_SSID_CMDID = 0x827,
- WMI_GET_SSID_CMDID = 0x828,
- WMI_SET_PCP_CHANNEL_CMDID = 0x829,
- WMI_GET_PCP_CHANNEL_CMDID = 0x82A,
- WMI_SW_TX_REQ_CMDID = 0x82B,
- WMI_READ_MAC_RXQ_CMDID = 0x830,
- WMI_READ_MAC_TXQ_CMDID = 0x831,
- WMI_WRITE_MAC_RXQ_CMDID = 0x832,
- WMI_WRITE_MAC_TXQ_CMDID = 0x833,
- WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834,
- WMI_MLME_PUSH_CMDID = 0x835,
- WMI_BEAMFORMING_MGMT_CMDID = 0x836,
- WMI_BF_TXSS_MGMT_CMDID = 0x837,
- WMI_BF_SM_MGMT_CMDID = 0x838,
- WMI_BF_RXSS_MGMT_CMDID = 0x839,
- WMI_BF_TRIG_CMDID = 0x83A,
- WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842,
- WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843,
- WMI_SET_SECTORS_CMDID = 0x849,
- WMI_MAINTAIN_PAUSE_CMDID = 0x850,
- WMI_MAINTAIN_RESUME_CMDID = 0x851,
- WMI_RS_MGMT_CMDID = 0x852,
- WMI_RF_MGMT_CMDID = 0x853,
- WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854,
- WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855,
- WMI_OTP_READ_CMDID = 0x856,
- WMI_OTP_WRITE_CMDID = 0x857,
- WMI_LED_CFG_CMDID = 0x858,
+ WMI_CONNECT_CMDID = 0x01,
+ WMI_DISCONNECT_CMDID = 0x03,
+ WMI_DISCONNECT_STA_CMDID = 0x04,
+ WMI_START_SCAN_CMDID = 0x07,
+ WMI_SET_BSS_FILTER_CMDID = 0x09,
+ WMI_SET_PROBED_SSID_CMDID = 0x0A,
+ WMI_SET_LISTEN_INT_CMDID = 0x0B,
+ WMI_BCON_CTRL_CMDID = 0x0F,
+ WMI_ADD_CIPHER_KEY_CMDID = 0x16,
+ WMI_DELETE_CIPHER_KEY_CMDID = 0x17,
+ WMI_PCP_CONF_CMDID = 0x18,
+ WMI_SET_APPIE_CMDID = 0x3F,
+ WMI_SET_WSC_STATUS_CMDID = 0x41,
+ WMI_PXMT_RANGE_CFG_CMDID = 0x42,
+ WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43,
+ WMI_MEM_READ_CMDID = 0x800,
+ WMI_MEM_WR_CMDID = 0x801,
+ WMI_ECHO_CMDID = 0x803,
+ WMI_DEEP_ECHO_CMDID = 0x804,
+ WMI_CONFIG_MAC_CMDID = 0x805,
+ WMI_CONFIG_PHY_DEBUG_CMDID = 0x806,
+ WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808,
+ WMI_PHY_GET_STATISTICS_CMDID = 0x809,
+ WMI_FS_TUNE_CMDID = 0x80A,
+ WMI_CORR_MEASURE_CMDID = 0x80B,
+ WMI_READ_RSSI_CMDID = 0x80C,
+ WMI_TEMP_SENSE_CMDID = 0x80E,
+ WMI_DC_CALIB_CMDID = 0x80F,
+ WMI_SEND_TONE_CMDID = 0x810,
+ WMI_IQ_TX_CALIB_CMDID = 0x811,
+ WMI_IQ_RX_CALIB_CMDID = 0x812,
+ WMI_SET_UCODE_IDLE_CMDID = 0x813,
+ WMI_SET_WORK_MODE_CMDID = 0x815,
+ WMI_LO_LEAKAGE_CALIB_CMDID = 0x816,
+ WMI_MARLON_R_READ_CMDID = 0x818,
+ WMI_MARLON_R_WRITE_CMDID = 0x819,
+ WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A,
+ MAC_IO_STATIC_PARAMS_CMDID = 0x81B,
+ MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C,
+ WMI_SILENT_RSSI_CALIB_CMDID = 0x81D,
+ WMI_RF_RX_TEST_CMDID = 0x81E,
+ WMI_CFG_RX_CHAIN_CMDID = 0x820,
+ WMI_VRING_CFG_CMDID = 0x821,
+ WMI_BCAST_VRING_CFG_CMDID = 0x822,
+ WMI_VRING_BA_EN_CMDID = 0x823,
+ WMI_VRING_BA_DIS_CMDID = 0x824,
+ WMI_RCP_ADDBA_RESP_CMDID = 0x825,
+ WMI_RCP_DELBA_CMDID = 0x826,
+ WMI_SET_SSID_CMDID = 0x827,
+ WMI_GET_SSID_CMDID = 0x828,
+ WMI_SET_PCP_CHANNEL_CMDID = 0x829,
+ WMI_GET_PCP_CHANNEL_CMDID = 0x82A,
+ WMI_SW_TX_REQ_CMDID = 0x82B,
+ WMI_READ_MAC_RXQ_CMDID = 0x830,
+ WMI_READ_MAC_TXQ_CMDID = 0x831,
+ WMI_WRITE_MAC_RXQ_CMDID = 0x832,
+ WMI_WRITE_MAC_TXQ_CMDID = 0x833,
+ WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834,
+ WMI_MLME_PUSH_CMDID = 0x835,
+ WMI_BEAMFORMING_MGMT_CMDID = 0x836,
+ WMI_BF_TXSS_MGMT_CMDID = 0x837,
+ WMI_BF_SM_MGMT_CMDID = 0x838,
+ WMI_BF_RXSS_MGMT_CMDID = 0x839,
+ WMI_BF_TRIG_CMDID = 0x83A,
+ WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842,
+ WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843,
+ WMI_SET_SECTORS_CMDID = 0x849,
+ WMI_MAINTAIN_PAUSE_CMDID = 0x850,
+ WMI_MAINTAIN_RESUME_CMDID = 0x851,
+ WMI_RS_MGMT_CMDID = 0x852,
+ WMI_RF_MGMT_CMDID = 0x853,
+ WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854,
+ WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855,
+ WMI_OTP_READ_CMDID = 0x856,
+ WMI_OTP_WRITE_CMDID = 0x857,
+ WMI_LED_CFG_CMDID = 0x858,
/* Performance monitoring commands */
- WMI_BF_CTRL_CMDID = 0x862,
- WMI_NOTIFY_REQ_CMDID = 0x863,
- WMI_GET_STATUS_CMDID = 0x864,
- WMI_GET_RF_STATUS_CMDID = 0x866,
- WMI_GET_BASEBAND_TYPE_CMDID = 0x867,
- WMI_UNIT_TEST_CMDID = 0x900,
- WMI_HICCUP_CMDID = 0x901,
- WMI_FLASH_READ_CMDID = 0x902,
- WMI_FLASH_WRITE_CMDID = 0x903,
+ WMI_BF_CTRL_CMDID = 0x862,
+ WMI_NOTIFY_REQ_CMDID = 0x863,
+ WMI_GET_STATUS_CMDID = 0x864,
+ WMI_GET_RF_STATUS_CMDID = 0x866,
+ WMI_GET_BASEBAND_TYPE_CMDID = 0x867,
+ WMI_UNIT_TEST_CMDID = 0x900,
+ WMI_HICCUP_CMDID = 0x901,
+ WMI_FLASH_READ_CMDID = 0x902,
+ WMI_FLASH_WRITE_CMDID = 0x903,
/* Power management */
- WMI_TRAFFIC_DEFERRAL_CMDID = 0x904,
- WMI_TRAFFIC_RESUME_CMDID = 0x905,
+ WMI_TRAFFIC_DEFERRAL_CMDID = 0x904,
+ WMI_TRAFFIC_RESUME_CMDID = 0x905,
/* P2P */
- WMI_P2P_CFG_CMDID = 0x910,
- WMI_PORT_ALLOCATE_CMDID = 0x911,
- WMI_PORT_DELETE_CMDID = 0x912,
- WMI_POWER_MGMT_CFG_CMDID = 0x913,
- WMI_START_LISTEN_CMDID = 0x914,
- WMI_START_SEARCH_CMDID = 0x915,
- WMI_DISCOVERY_START_CMDID = 0x916,
- WMI_DISCOVERY_STOP_CMDID = 0x917,
- WMI_PCP_START_CMDID = 0x918,
- WMI_PCP_STOP_CMDID = 0x919,
- WMI_GET_PCP_FACTOR_CMDID = 0x91B,
+ WMI_P2P_CFG_CMDID = 0x910,
+ WMI_PORT_ALLOCATE_CMDID = 0x911,
+ WMI_PORT_DELETE_CMDID = 0x912,
+ WMI_POWER_MGMT_CFG_CMDID = 0x913,
+ WMI_START_LISTEN_CMDID = 0x914,
+ WMI_START_SEARCH_CMDID = 0x915,
+ WMI_DISCOVERY_START_CMDID = 0x916,
+ WMI_DISCOVERY_STOP_CMDID = 0x917,
+ WMI_PCP_START_CMDID = 0x918,
+ WMI_PCP_STOP_CMDID = 0x919,
+ WMI_GET_PCP_FACTOR_CMDID = 0x91B,
/* Power Save Configuration Commands */
- WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C,
+ WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C,
/* Not supported yet */
- WMI_PS_DEV_CFG_CMDID = 0x91D,
+ WMI_PS_DEV_CFG_CMDID = 0x91D,
/* Not supported yet */
- WMI_PS_DEV_CFG_READ_CMDID = 0x91E,
+ WMI_PS_DEV_CFG_READ_CMDID = 0x91E,
/* Per MAC Power Save Configuration commands
* Not supported yet
*/
- WMI_PS_MID_CFG_CMDID = 0x91F,
+ WMI_PS_MID_CFG_CMDID = 0x91F,
/* Not supported yet */
- WMI_PS_MID_CFG_READ_CMDID = 0x920,
- WMI_RS_CFG_CMDID = 0x921,
- WMI_GET_DETAILED_RS_RES_CMDID = 0x922,
- WMI_AOA_MEAS_CMDID = 0x923,
- WMI_TOF_SESSION_START_CMDID = 0x991,
- WMI_TOF_GET_CAPABILITIES_CMDID = 0x992,
- WMI_TOF_SET_LCR_CMDID = 0x993,
- WMI_TOF_SET_LCI_CMDID = 0x994,
- WMI_TOF_CHANNEL_INFO_CMDID = 0x995,
- WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
- WMI_ABORT_SCAN_CMDID = 0xF007,
- WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
- WMI_GET_PMK_CMDID = 0xF048,
- WMI_SET_PASSPHRASE_CMDID = 0xF049,
- WMI_SEND_ASSOC_RES_CMDID = 0xF04A,
- WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B,
- WMI_MAC_ADDR_REQ_CMDID = 0xF04D,
- WMI_FW_VER_CMDID = 0xF04E,
- WMI_PMC_CMDID = 0xF04F,
+ WMI_PS_MID_CFG_READ_CMDID = 0x920,
+ WMI_RS_CFG_CMDID = 0x921,
+ WMI_GET_DETAILED_RS_RES_CMDID = 0x922,
+ WMI_AOA_MEAS_CMDID = 0x923,
+ WMI_SET_MGMT_RETRY_LIMIT_CMDID = 0x930,
+ WMI_GET_MGMT_RETRY_LIMIT_CMDID = 0x931,
+ WMI_TOF_SESSION_START_CMDID = 0x991,
+ WMI_TOF_GET_CAPABILITIES_CMDID = 0x992,
+ WMI_TOF_SET_LCR_CMDID = 0x993,
+ WMI_TOF_SET_LCI_CMDID = 0x994,
+ WMI_TOF_CHANNEL_INFO_CMDID = 0x995,
+ WMI_TOF_SET_TX_RX_OFFSET_CMDID = 0x997,
+ WMI_TOF_GET_TX_RX_OFFSET_CMDID = 0x998,
+ WMI_GET_RF_SECTOR_PARAMS_CMDID = 0x9A0,
+ WMI_SET_RF_SECTOR_PARAMS_CMDID = 0x9A1,
+ WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A2,
+ WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A3,
+ WMI_SET_RF_SECTOR_ON_CMDID = 0x9A4,
+ WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5,
+ WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6,
+ WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7,
+ WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
+ WMI_ABORT_SCAN_CMDID = 0xF007,
+ WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
+ WMI_GET_PMK_CMDID = 0xF048,
+ WMI_SET_PASSPHRASE_CMDID = 0xF049,
+ WMI_SEND_ASSOC_RES_CMDID = 0xF04A,
+ WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B,
+ WMI_MAC_ADDR_REQ_CMDID = 0xF04D,
+ WMI_FW_VER_CMDID = 0xF04E,
+ WMI_PMC_CMDID = 0xF04F,
};
/* WMI_CONNECT_CMDID */
@@ -879,6 +894,14 @@ struct wmi_aoa_meas_cmd {
__le32 meas_rf_mask;
} __packed;
+/* WMI_SET_MGMT_RETRY_LIMIT_CMDID */
+struct wmi_set_mgmt_retry_limit_cmd {
+ /* MAC retransmit limit for mgmt frames */
+ u8 mgmt_retry_limit;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
enum wmi_tof_burst_duration {
WMI_TOF_BURST_DURATION_250_USEC = 2,
WMI_TOF_BURST_DURATION_500_USEC = 3,
@@ -942,6 +965,15 @@ struct wmi_tof_channel_info_cmd {
__le32 channel_info_report_request;
} __packed;
+/* WMI_TOF_SET_TX_RX_OFFSET_CMDID */
+struct wmi_tof_set_tx_rx_offset_cmd {
+ /* TX delay offset */
+ __le32 tx_offset;
+ /* RX delay offset */
+ __le32 rx_offset;
+ __le32 reserved[2];
+} __packed;
+
/* WMI Events
* List of Events (target to host)
*/
@@ -1035,12 +1067,24 @@ enum wmi_event_id {
WMI_RS_CFG_DONE_EVENTID = 0x1921,
WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922,
WMI_AOA_MEAS_EVENTID = 0x1923,
+ WMI_SET_MGMT_RETRY_LIMIT_EVENTID = 0x1930,
+ WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931,
WMI_TOF_SESSION_END_EVENTID = 0x1991,
WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992,
WMI_TOF_SET_LCR_EVENTID = 0x1993,
WMI_TOF_SET_LCI_EVENTID = 0x1994,
WMI_TOF_FTM_PER_DEST_RES_EVENTID = 0x1995,
WMI_TOF_CHANNEL_INFO_EVENTID = 0x1996,
+ WMI_TOF_SET_TX_RX_OFFSET_EVENTID = 0x1997,
+ WMI_TOF_GET_TX_RX_OFFSET_EVENTID = 0x1998,
+ WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A0,
+ WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A1,
+ WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A2,
+ WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A3,
+ WMI_SET_RF_SECTOR_ON_DONE_EVENTID = 0x19A4,
+ WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5,
+ WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6,
+ WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
@@ -1166,6 +1210,7 @@ enum baseband_type {
BASEBAND_SPARROW_M_B0 = 0x05,
BASEBAND_SPARROW_M_C0 = 0x06,
BASEBAND_SPARROW_M_D0 = 0x07,
+ BASEBAND_TALYN_M_A0 = 0x08,
};
/* WMI_GET_BASEBAND_TYPE_EVENTID */
@@ -2070,6 +2115,22 @@ struct wmi_aoa_meas_event {
u8 meas_data[WMI_AOA_MAX_DATA_SIZE];
} __packed;
+/* WMI_SET_MGMT_RETRY_LIMIT_EVENTID */
+struct wmi_set_mgmt_retry_limit_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
+/* WMI_GET_MGMT_RETRY_LIMIT_EVENTID */
+struct wmi_get_mgmt_retry_limit_event {
+ /* MAC retransmit limit for mgmt frames */
+ u8 mgmt_retry_limit;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
/* WMI_TOF_GET_CAPABILITIES_EVENTID */
struct wmi_tof_get_capabilities_event {
u8 ftm_capability;
@@ -2184,4 +2245,283 @@ struct wmi_tof_channel_info_event {
u8 report[0];
} __packed;
+/* WMI_TOF_SET_TX_RX_OFFSET_EVENTID */
+struct wmi_tof_set_tx_rx_offset_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved[3];
+} __packed;
+
+/* WMI_TOF_GET_TX_RX_OFFSET_EVENTID */
+struct wmi_tof_get_tx_rx_offset_event {
+ /* enum wmi_fw_status */
+ u8 status;
+ u8 reserved1[3];
+ /* TX delay offset */
+ __le32 tx_offset;
+ /* RX delay offset */
+ __le32 rx_offset;
+ __le32 reserved2[2];
+} __packed;
+
+/* Result status codes for WMI commands */
+enum wmi_rf_sector_status {
+ WMI_RF_SECTOR_STATUS_SUCCESS = 0x00,
+ WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR = 0x01,
+ WMI_RF_SECTOR_STATUS_BUSY_ERROR = 0x02,
+ WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR = 0x03,
+};
+
+/* Types of the RF sector (TX,RX) */
+enum wmi_rf_sector_type {
+ WMI_RF_SECTOR_TYPE_RX = 0x00,
+ WMI_RF_SECTOR_TYPE_TX = 0x01,
+};
+
+/* Content of RF Sector (six 32-bits registers) */
+struct wmi_rf_sector_info {
+ /* Phase values for RF Chains[15-0] (2bits per RF chain) */
+ __le32 psh_hi;
+ /* Phase values for RF Chains[31-16] (2bits per RF chain) */
+ __le32 psh_lo;
+ /* ETYPE Bit0 for all RF chains[31-0] - bit0 of Edge amplifier gain
+ * index
+ */
+ __le32 etype0;
+ /* ETYPE Bit1 for all RF chains[31-0] - bit1 of Edge amplifier gain
+ * index
+ */
+ __le32 etype1;
+ /* ETYPE Bit2 for all RF chains[31-0] - bit2 of Edge amplifier gain
+ * index
+ */
+ __le32 etype2;
+ /* D-Type values (3bits each) for 8 Distribution amplifiers + X16
+ * switch bits
+ */
+ __le32 dtype_swch_off;
+} __packed;
+
+#define WMI_INVALID_RF_SECTOR_INDEX (0xFFFF)
+#define WMI_MAX_RF_MODULES_NUM (8)
+
+/* WMI_GET_RF_SECTOR_PARAMS_CMD */
+struct wmi_get_rf_sector_params_cmd {
+ /* Sector number to be retrieved */
+ __le16 sector_idx;
+ /* enum wmi_rf_sector_type - type of requested RF sector */
+ u8 sector_type;
+ /* bitmask vector specifying destination RF modules */
+ u8 rf_modules_vec;
+} __packed;
+
+/* \WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT */
+struct wmi_get_rf_sector_params_done_event {
+ /* result status of WMI_GET_RF_SECTOR_PARAMS_CMD (enum
+ * wmi_rf_sector_status)
+ */
+ u8 status;
+ /* align next field to U64 boundary */
+ u8 reserved[7];
+ /* TSF timestamp when RF sectors where retrieved */
+ __le64 tsf;
+ /* Content of RF sector retrieved from each RF module */
+ struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM];
+} __packed;
+
+/* WMI_SET_RF_SECTOR_PARAMS_CMD */
+struct wmi_set_rf_sector_params_cmd {
+ /* Sector number to be retrieved */
+ __le16 sector_idx;
+ /* enum wmi_rf_sector_type - type of requested RF sector */
+ u8 sector_type;
+ /* bitmask vector specifying destination RF modules */
+ u8 rf_modules_vec;
+ /* Content of RF sector to be written to each RF module */
+ struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM];
+} __packed;
+
+/* \WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT */
+struct wmi_set_rf_sector_params_done_event {
+ /* result status of WMI_SET_RF_SECTOR_PARAMS_CMD (enum
+ * wmi_rf_sector_status)
+ */
+ u8 status;
+} __packed;
+
+/* WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD - Get RF sector index selected by
+ * TXSS/BRP for communication with specified CID
+ */
+struct wmi_get_selected_rf_sector_index_cmd {
+ /* Connection/Station ID in [0:7] range */
+ u8 cid;
+ /* type of requested RF sector (enum wmi_rf_sector_type) */
+ u8 sector_type;
+ /* align to U32 boundary */
+ u8 reserved[2];
+} __packed;
+
+/* \WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Returns retrieved RF sector
+ * index selected by TXSS/BRP for communication with specified CID
+ */
+struct wmi_get_selected_rf_sector_index_done_event {
+ /* Retrieved sector index selected in TXSS (for TX sector request) or
+ * BRP (for RX sector request)
+ */
+ __le16 sector_idx;
+ /* result status of WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD (enum
+ * wmi_rf_sector_status)
+ */
+ u8 status;
+ /* align next field to U64 boundary */
+ u8 reserved[5];
+ /* TSF timestamp when result was retrieved */
+ __le64 tsf;
+} __packed;
+
+/* WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD - Force RF sector index for
+ * communication with specified CID. Assumes that TXSS/BRP is disabled by
+ * other command
+ */
+struct wmi_set_selected_rf_sector_index_cmd {
+ /* Connection/Station ID in [0:7] range */
+ u8 cid;
+ /* type of requested RF sector (enum wmi_rf_sector_type) */
+ u8 sector_type;
+ /* Forced sector index */
+ __le16 sector_idx;
+} __packed;
+
+/* \WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Success/Fail status for
+ * WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD
+ */
+struct wmi_set_selected_rf_sector_index_done_event {
+ /* result status of WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD (enum
+ * wmi_rf_sector_status)
+ */
+ u8 status;
+ /* align to U32 boundary */
+ u8 reserved[3];
+} __packed;
+
+/* WMI_SET_RF_SECTOR_ON_CMD - Activates specified sector for specified rf
+ * modules
+ */
+struct wmi_set_rf_sector_on_cmd {
+ /* Sector index to be activated */
+ __le16 sector_idx;
+ /* type of requested RF sector (enum wmi_rf_sector_type) */
+ u8 sector_type;
+ /* bitmask vector specifying destination RF modules */
+ u8 rf_modules_vec;
+} __packed;
+
+/* \WMI_SET_RF_SECTOR_ON_DONE_EVENT - Success/Fail status for
+ * WMI_SET_RF_SECTOR_ON_CMD
+ */
+struct wmi_set_rf_sector_on_done_event {
+ /* result status of WMI_SET_RF_SECTOR_ON_CMD (enum
+ * wmi_rf_sector_status)
+ */
+ u8 status;
+ /* align to U32 boundary */
+ u8 reserved[3];
+} __packed;
+
+enum wmi_sector_sweep_type {
+ WMI_SECTOR_SWEEP_TYPE_TXSS = 0x00,
+ WMI_SECTOR_SWEEP_TYPE_BCON = 0x01,
+ WMI_SECTOR_SWEEP_TYPE_TXSS_AND_BCON = 0x02,
+ WMI_SECTOR_SWEEP_TYPE_NUM = 0x03,
+};
+
+/* WMI_PRIO_TX_SECTORS_ORDER_CMDID
+ *
+ * Set the order of TX sectors in TXSS and/or Beacon(AP).
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_ORDER_EVENTID
+ */
+struct wmi_prio_tx_sectors_order_cmd {
+ /* tx sectors order to be applied, 0xFF for end of array */
+ u8 tx_sectors_priority_array[MAX_NUM_OF_SECTORS];
+ /* enum wmi_sector_sweep_type, TXSS and/or Beacon */
+ u8 sector_sweep_type;
+ /* needed only for TXSS configuration */
+ u8 cid;
+ /* alignment to 32b */
+ u8 reserved[2];
+} __packed;
+
+/* completion status codes */
+enum wmi_prio_tx_sectors_cmd_status {
+ WMI_PRIO_TX_SECT_CMD_STATUS_SUCCESS = 0x00,
+ WMI_PRIO_TX_SECT_CMD_STATUS_BAD_PARAM = 0x01,
+ /* other error */
+ WMI_PRIO_TX_SECT_CMD_STATUS_ERROR = 0x02,
+};
+
+/* WMI_PRIO_TX_SECTORS_ORDER_EVENTID */
+struct wmi_prio_tx_sectors_order_event {
+ /* enum wmi_prio_tx_sectors_cmd_status */
+ u8 status;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
+struct wmi_prio_tx_sectors_num_cmd {
+ /* [0-128], 0 = No changes */
+ u8 beacon_number_of_sectors;
+ /* [0-128], 0 = No changes */
+ u8 txss_number_of_sectors;
+ /* [0-8] needed only for TXSS configuration */
+ u8 cid;
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_NUMBER_CMDID
+ *
+ * Set the number of active sectors in TXSS and/or Beacon.
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_NUMBER_EVENTID
+ */
+struct wmi_prio_tx_sectors_number_cmd {
+ struct wmi_prio_tx_sectors_num_cmd active_sectors_num;
+ /* alignment to 32b */
+ u8 reserved;
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_NUMBER_EVENTID */
+struct wmi_prio_tx_sectors_number_event {
+ /* enum wmi_prio_tx_sectors_cmd_status */
+ u8 status;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID
+ *
+ * Set default sectors order and number (hard coded in board file)
+ * in TXSS and/or Beacon.
+ *
+ * Returned event:
+ * - WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID
+ */
+struct wmi_prio_tx_sectors_set_default_cfg_cmd {
+ /* enum wmi_sector_sweep_type, TXSS and/or Beacon */
+ u8 sector_sweep_type;
+ /* needed only for TXSS configuration */
+ u8 cid;
+ /* alignment to 32b */
+ u8 reserved[2];
+} __packed;
+
+/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID */
+struct wmi_prio_tx_sectors_set_default_cfg_event {
+ /* enum wmi_prio_tx_sectors_cmd_status */
+ u8 status;
+ /* alignment to 32b */
+ u8 reserved[3];
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index c2e43a62ab69..b1f27ceb492b 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -2573,7 +2573,7 @@ int rmnet_ipa_set_data_quota(struct wan_ioctl_set_data_quota *data)
*
* Return codes:
* 0: Success
- * -EFAULT: Invalid interface name provided
+ * -EFAULT: Invalid src/dst pipes provided
* other: See ipa_qmi_set_data_quota
*/
int rmnet_ipa_set_tether_client_pipe(
@@ -2581,6 +2581,23 @@ int rmnet_ipa_set_tether_client_pipe(
{
int number, i;
+ /* error checking if ul_src_pipe_len valid or not*/
+ if (data->ul_src_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->ul_src_pipe_len < 0) {
+ IPAWANERR("UL src pipes %d exceeding max %d\n",
+ data->ul_src_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+ /* error checking if dl_dst_pipe_len valid or not*/
+ if (data->dl_dst_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->dl_dst_pipe_len < 0) {
+ IPAWANERR("DL dst pipes %d exceeding max %d\n",
+ data->dl_dst_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+
IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
data->ipa_client,
data->ul_src_pipe_len,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 2101147e7d24..214ae08234a9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2301,13 +2301,17 @@ void ipa3_q6_post_shutdown_cleanup(void)
int client_idx;
IPADBG_LOW("ENTER\n");
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
if (!ipa3_ctx->uc_ctx.uc_loaded) {
IPAERR("uC is not loaded. Skipping\n");
return;
}
+ IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+ /* Handle the issue where SUSPEND was removed for some reason */
+ ipa3_q6_avoid_holb();
+
for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
if (ipa3_uc_is_gsi_channel_empty(client_idx)) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index ff197705d845..f042d19f196a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2736,6 +2736,23 @@ int rmnet_ipa3_set_tether_client_pipe(
{
int number, i;
+ /* error checking if ul_src_pipe_len valid or not*/
+ if (data->ul_src_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->ul_src_pipe_len < 0) {
+ IPAWANERR("UL src pipes %d exceeding max %d\n",
+ data->ul_src_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+ /* error checking if dl_dst_pipe_len valid or not*/
+ if (data->dl_dst_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->dl_dst_pipe_len < 0) {
+ IPAWANERR("DL dst pipes %d exceeding max %d\n",
+ data->dl_dst_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+
IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
data->ipa_client,
data->ul_src_pipe_len,
diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c
index 69c11a9e5da2..2843f71745fc 100644
--- a/drivers/regulator/cpr4-mmss-ldo-regulator.c
+++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c
@@ -122,12 +122,12 @@ static const struct cpr3_fuse_param sdm660_ldo_cpr_cl_enable_param[] = {
/* Open loop voltage fuse reference voltages in microvolts */
static const int sdm660_mmss_fuse_ref_volt[SDM660_MMSS_FUSE_CORNERS] = {
- 584000,
- 644000,
- 724000,
- 788000,
- 868000,
- 924000,
+ 585000,
+ 645000,
+ 725000,
+ 790000,
+ 870000,
+ 925000,
};
#define SDM660_MMSS_FUSE_STEP_VOLT 10000
diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
index dcca82fc25c6..5726c3277456 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.c
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -337,6 +337,21 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
bootup_request++;
break;
+ case SUBSYS_BEFORE_POWERUP:
+ if (_cmd)
+ notifdata = (struct notif_data *) _cmd;
+ else
+ break;
+
+ if (notifdata->enable_ramdump) {
+ pr_info("memshare: %s, Ramdump collection is enabled\n",
+ __func__);
+ ret = mem_share_do_ramdump();
+ if (ret)
+ pr_err("Ramdump collection failed\n");
+ }
+ break;
+
case SUBSYS_AFTER_POWERUP:
pr_debug("memshare: Modem has booted up\n");
for (i = 0; i < MAX_CLIENTS; i++) {
@@ -387,22 +402,6 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
bootup_request++;
break;
- case SUBSYS_RAMDUMP_NOTIFICATION:
- if (_cmd)
- notifdata = (struct notif_data *) _cmd;
- else
- break;
-
- if (!(notifdata->enable_ramdump)) {
- pr_info("In %s, Ramdump collection is disabled\n",
- __func__);
- } else {
- ret = mem_share_do_ramdump();
- if (ret)
- pr_err("Ramdump collection failed\n");
- }
- break;
-
default:
pr_debug("Memshare: code: %lu\n", code);
break;
@@ -511,6 +510,8 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h)
pr_err("memshare: %s client not found, requested client: %d, proc_id: %d\n",
__func__, alloc_req->client_id,
alloc_req->proc_id);
+ kfree(alloc_resp);
+ alloc_resp = NULL;
return -EINVAL;
}
@@ -555,6 +556,9 @@ static int handle_alloc_generic_req(void *req_h, void *req, void *conn_h)
if (rc < 0)
pr_err("In %s, Error sending the alloc request: %d\n",
__func__, rc);
+
+ kfree(alloc_resp);
+ alloc_resp = NULL;
return rc;
}
@@ -672,6 +676,8 @@ static int handle_query_size_req(void *req_h, void *req, void *conn_h)
pr_err("memshare: %s client not found, requested client: %d, proc_id: %d\n",
__func__, query_req->client_id,
query_req->proc_id);
+ kfree(query_resp);
+ query_resp = NULL;
return -EINVAL;
}
@@ -697,6 +703,8 @@ static int handle_query_size_req(void *req_h, void *req, void *conn_h)
pr_err("In %s, Error sending the query request: %d\n",
__func__, rc);
+ kfree(query_resp);
+ query_resp = NULL;
return rc;
}
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 8ed98e2cbd5e..5f01d30de8d9 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -38,7 +38,7 @@
#define MAX_VDD_MSS_UV 1150000
#define PROXY_TIMEOUT_MS 10000
-#define MAX_SSR_REASON_LEN 81U
+#define MAX_SSR_REASON_LEN 130U
#define STOP_ACK_TIMEOUT_MS 1000
#define subsys_to_drv(d) container_of(d, struct modem_data, subsys_desc)
diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c
index e920dfee8530..d0fef9d31755 100644
--- a/drivers/soc/qcom/smcinvoke.c
+++ b/drivers/soc/qcom/smcinvoke.c
@@ -192,9 +192,9 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len,
desc.arginfo = SMCINVOKE_TZ_PARAM_ID;
desc.args[0] = (uint64_t)virt_to_phys(in_buf);
- desc.args[1] = in_buf_len;
+ desc.args[1] = inbuf_flush_size;
desc.args[2] = (uint64_t)virt_to_phys(out_buf);
- desc.args[3] = out_buf_len;
+ desc.args[3] = outbuf_flush_size;
dmac_flush_range(in_buf, in_buf + inbuf_flush_size);
dmac_flush_range(out_buf, out_buf + outbuf_flush_size);
diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c
index e54819b4837b..c93a9a5c8a1c 100644
--- a/drivers/soc/qcom/spss_utils.c
+++ b/drivers/soc/qcom/spss_utils.c
@@ -48,6 +48,7 @@ static const char *test_firmware_name;
static const char *prod_firmware_name;
static const char *firmware_name;
static struct device *spss_dev;
+static u32 spss_debug_reg_addr; /* SP_SCSR_MBn_SP2CL_GPm(n,m) */
/*==========================================================================*/
/* Device Sysfs */
@@ -117,6 +118,51 @@ static ssize_t test_fuse_state_store(struct device *dev,
static DEVICE_ATTR(test_fuse_state, 0444,
test_fuse_state_show, test_fuse_state_store);
+static ssize_t spss_debug_reg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ void __iomem *spss_debug_reg = NULL;
+ int val1, val2;
+
+ if (!dev || !attr || !buf) {
+ pr_err("invalid param.\n");
+ return -EINVAL;
+ }
+
+ pr_debug("spss_debug_reg_addr [0x%x].\n", spss_debug_reg_addr);
+
+ spss_debug_reg = ioremap_nocache(spss_debug_reg_addr, 0x16);
+
+ if (!spss_debug_reg) {
+ pr_err("can't map debug reg addr.\n");
+ return -EFAULT;
+ }
+
+ val1 = readl_relaxed(spss_debug_reg);
+ val2 = readl_relaxed(((char *) spss_debug_reg) + 0x04);
+
+ ret = snprintf(buf, PAGE_SIZE, "val1 [0x%x] val2 [0x%x]", val1, val2);
+
+ iounmap(spss_debug_reg);
+
+ return ret;
+}
+
+static ssize_t spss_debug_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ pr_err("set debug reg is not allowed.\n");
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(spss_debug_reg, 0444,
+ spss_debug_reg_show, spss_debug_reg_store);
+
static int spss_create_sysfs(struct device *dev)
{
int ret;
@@ -133,6 +179,12 @@ static int spss_create_sysfs(struct device *dev)
return ret;
}
+ ret = device_create_file(dev, &dev_attr_spss_debug_reg);
+ if (ret < 0) {
+ pr_err("failed to create sysfs file for spss_debug_reg.\n");
+ return ret;
+ }
+
return 0;
}
@@ -201,6 +253,13 @@ static int spss_parse_dt(struct device_node *node)
iounmap(spss_fuse_reg);
+ ret = of_property_read_u32(node, "qcom,spss-debug-reg-addr",
+ &spss_debug_reg_addr);
+ if (ret < 0) {
+ pr_err("can't get debug regs addr.\n");
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index b8d096a9c057..769a683e3d8d 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -25,6 +25,7 @@
#include <linux/msm-bus-board.h>
#include <linux/msm-bus.h>
#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/ramdump.h>
@@ -613,6 +614,10 @@ static int pil_init_image_trusted(struct pil_desc *pil,
return -ENOMEM;
}
+ /* Make sure there are no mappings in PKMAP and fixmap */
+ kmap_flush_unused();
+ kmap_atomic_flush_unused();
+
memcpy(mdata_buf, metadata, size);
request.proc = d->pas_id;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 7076b36bb6b6..ccf8a0d34a6c 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -53,21 +53,12 @@ struct mdss_dp_attention_node {
};
#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3
-static u32 supported_modes[] = {
- HDMI_VFRMT_640x480p60_4_3,
- HDMI_VFRMT_720x480p60_4_3, HDMI_VFRMT_720x480p60_16_9,
- HDMI_VFRMT_1280x720p60_16_9,
- HDMI_VFRMT_1920x1080p60_16_9,
- HDMI_VFRMT_3840x2160p24_16_9, HDMI_VFRMT_3840x2160p30_16_9,
- HDMI_VFRMT_3840x2160p60_16_9,
- HDMI_VFRMT_4096x2160p24_256_135, HDMI_VFRMT_4096x2160p30_256_135,
- HDMI_VFRMT_4096x2160p60_256_135, HDMI_EVFRMT_4096x2160p24_16_9
-};
static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv);
static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata);
static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp);
static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp_drv);
+static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events);
static void mdss_dp_put_dt_clk_data(struct device *dev,
struct dss_module_power *module_power)
@@ -1003,7 +994,7 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic)
return -EINVAL;
}
- ret = hdmi_get_supported_mode(&timing, &dp_drv->ds_data, vic);
+ ret = hdmi_get_supported_mode(&timing, 0, vic);
pinfo = &dp_drv->panel_data.panel_info;
if (ret || !timing.supported || !pinfo) {
@@ -1234,6 +1225,15 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv)
dp_drv->power_on = true;
+ if (dp_drv->psm_enabled) {
+ ret = mdss_dp_aux_send_psm_request(dp_drv, false);
+ if (ret) {
+ pr_err("Failed to exit low power mode, rc=%d\n",
+ ret);
+ goto exit;
+ }
+ }
+
ret = mdss_dp_train_main_link(dp_drv);
mutex_unlock(&dp_drv->train_mutex);
@@ -1301,6 +1301,15 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
mdss_dp_configure_source_params(dp_drv, &ln_map);
+ if (dp_drv->psm_enabled) {
+ ret = mdss_dp_aux_send_psm_request(dp_drv, false);
+ if (ret) {
+ pr_err("Failed to exit low power mode, rc=%d\n", ret);
+ goto exit;
+ }
+ }
+
+
link_training:
dp_drv->power_on = true;
@@ -1387,6 +1396,7 @@ static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv)
wmb();
mdss_dp_disable_mainlink_clocks(dp_drv);
dp_drv->power_on = false;
+ dp_drv->sink_info_read = false;
mutex_unlock(&dp_drv->train_mutex);
complete_all(&dp_drv->irq_comp);
@@ -1434,6 +1444,8 @@ static int mdss_dp_off_hpd(struct mdss_dp_drv_pdata *dp_drv)
dp_drv->dp_initialized = false;
dp_drv->power_on = false;
+ dp_drv->sink_info_read = false;
+
mdss_dp_ack_state(dp_drv, false);
mutex_unlock(&dp_drv->train_mutex);
pr_debug("DP off done\n");
@@ -1506,13 +1518,8 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
panel_data);
- dp_drv->ds_data.ds_registered = true;
- dp_drv->ds_data.modes_num = ARRAY_SIZE(supported_modes);
- dp_drv->ds_data.modes = supported_modes;
-
dp_drv->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
edid_init_data.kobj = dp_drv->kobj;
- edid_init_data.ds_data = dp_drv->ds_data;
edid_init_data.max_pclk_khz = dp_drv->max_pclk_khz;
edid_data = hdmi_edid_init(&edid_init_data);
@@ -1545,7 +1552,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
panel_data);
if (dp_drv->dp_initialized) {
- pr_err("%s: host init done already\n", __func__);
+ pr_debug("%s: host init done already\n", __func__);
return 0;
}
@@ -1588,37 +1595,47 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
mdss_dp_phy_aux_setup(&dp_drv->phy_io);
mdss_dp_irq_enable(dp_drv);
- pr_debug("irq enabled\n");
- mdss_dp_dpcd_cap_read(dp_drv);
+ dp_drv->dp_initialized = true;
- ret = mdss_dp_edid_read(dp_drv);
+ return 0;
+
+clk_error:
+ mdss_dp_regulator_ctrl(dp_drv, false);
+ mdss_dp_config_gpios(dp_drv, false);
+vreg_error:
+ return ret;
+}
+
+static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp)
+{
+ int ret;
+
+ if (dp->sink_info_read)
+ return 0;
+
+ mdss_dp_dpcd_cap_read(dp);
+
+ ret = mdss_dp_edid_read(dp);
if (ret) {
- pr_info("edid read error, setting default resolution\n");
- mdss_dp_set_default_resolution(dp_drv);
- goto edid_error;
- }
+ pr_debug("edid read error, setting default resolution\n");
- pr_debug("edid_read success. buf_size=%d\n",
- dp_drv->edid_buf_size);
+ mdss_dp_set_default_resolution(dp);
+ goto end;
+ }
- ret = hdmi_edid_parser(dp_drv->panel_data.panel_info.edid_data);
+ ret = hdmi_edid_parser(dp->panel_data.panel_info.edid_data);
if (ret) {
- DEV_ERR("%s: edid parse failed\n", __func__);
- goto edid_error;
+ pr_err("edid parse failed\n");
+ goto end;
}
-edid_error:
- mdss_dp_update_cable_status(dp_drv, true);
- mdss_dp_notify_clients(dp_drv, true);
- dp_drv->dp_initialized = true;
+ dp->sink_info_read = true;
+end:
+ mdss_dp_update_cable_status(dp, true);
+ mdss_dp_notify_clients(dp, true);
return ret;
-clk_error:
- mdss_dp_regulator_ctrl(dp_drv, false);
- mdss_dp_config_gpios(dp_drv, false);
-vreg_error:
- return ret;
}
static int mdss_dp_check_params(struct mdss_dp_drv_pdata *dp, void *arg)
@@ -1637,7 +1654,7 @@ static int mdss_dp_check_params(struct mdss_dp_drv_pdata *dp, void *arg)
var_pinfo->xres, var_pinfo->yres,
pinfo->xres, pinfo->yres);
- new_vic = hdmi_panel_get_vic(var_pinfo, &dp->ds_data);
+ new_vic = hdmi_panel_get_vic(var_pinfo, 0);
if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) {
DEV_ERR("%s: invalid or not supported vic\n", __func__);
@@ -1855,13 +1872,191 @@ static ssize_t mdss_dp_sysfs_rda_s3d_mode(struct device *dev,
return ret;
}
+static bool mdss_dp_is_test_ongoing(struct mdss_dp_drv_pdata *dp)
+{
+ return dp->hpd_irq_clients_notified;
+}
+
+/**
+ * mdss_dp_psm_config() - Downstream device uPacket RX Power Management
+ * @dp: Display Port Driver data
+ *
+ * Perform required steps to configure the uPacket RX of a downstream
+ * connected device in a power-save mode.
+ */
+static int mdss_dp_psm_config(struct mdss_dp_drv_pdata *dp, bool enable)
+{
+ int ret = 0;
+
+ if (!dp) {
+ pr_err("invalid data\n");
+ return -EINVAL;
+ }
+
+ if (dp->psm_enabled == enable) {
+ pr_debug("No change in psm requested\n");
+ goto end;
+ }
+
+ pr_debug("Power save mode %s requested\n", enable ? "entry" : "exit");
+
+ if (enable) {
+ ret = mdss_dp_aux_send_psm_request(dp, true);
+ if (ret)
+ goto end;
+
+ /*
+ * If this configuration is requested as part of an
+ * automated test, then HPD notification has already been
+ * sent out. Just disable the main-link and turn off DP Tx.
+ *
+ * Otherwise, trigger a complete shutdown of the pipeline.
+ */
+ if (mdss_dp_is_test_ongoing(dp)) {
+ mdss_dp_mainlink_push_idle(&dp->panel_data);
+ mdss_dp_off_irq(dp);
+ } else {
+ mdss_dp_notify_clients(dp, false);
+ }
+ } else {
+ /*
+ * If this configuration is requested as part of an
+ * automated test, then just perform a link retraining.
+ *
+ * Otherwise, re-initialize the host and setup the complete
+ * pipeline from scratch by sending a connection notification
+ * to user modules.
+ */
+ if (mdss_dp_is_test_ongoing(dp)) {
+ mdss_dp_link_retraining(dp);
+ } else {
+ mdss_dp_host_init(&dp->panel_data);
+ mdss_dp_notify_clients(dp, true);
+ }
+ }
+
+end:
+ pr_debug("Power save mode %s %s\n",
+ dp->psm_enabled ? "entry" : "exit",
+ ret ? "failed" : "successful");
+
+ return ret;
+}
+
+static ssize_t mdss_dp_wta_psm(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int psm;
+ int rc;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev);
+
+ if (!dp) {
+ pr_err("invalid data\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ rc = kstrtoint(buf, 10, &psm);
+ if (rc) {
+ pr_err("kstrtoint failed. ret=%d\n", (int)ret);
+ goto end;
+ }
+
+ rc = mdss_dp_psm_config(dp, psm ? true : false);
+ if (rc) {
+ pr_err("failed to config Power Save Mode\n");
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static ssize_t mdss_dp_rda_psm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev);
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", dp->psm_enabled ? 1 : 0);
+ pr_debug("psm: %s\n", dp->psm_enabled ? "enabled" : "disabled");
+
+ return ret;
+}
+
+static ssize_t mdss_dp_wta_hpd(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int hpd;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev);
+
+ if (!dp) {
+ pr_err("invalid data\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = kstrtoint(buf, 10, &hpd);
+ if (ret) {
+ pr_err("kstrtoint failed. ret=%d\n", (int)ret);
+ goto end;
+ }
+
+ dp->hpd = !!hpd;
+ pr_debug("hpd=%d\n", dp->hpd);
+
+ if (dp->hpd && dp->cable_connected) {
+ if (dp->alt_mode.current_state & DP_CONFIGURE_DONE) {
+ mdss_dp_host_init(&dp->panel_data);
+ mdss_dp_process_hpd_high(dp);
+ } else {
+ dp_send_events(dp, EV_USBPD_DISCOVER_MODES);
+ }
+ } else if (!dp->hpd && dp->power_on) {
+ mdss_dp_notify_clients(dp, false);
+ }
+end:
+ return ret;
+}
+
+static ssize_t mdss_dp_rda_hpd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct mdss_dp_drv_pdata *dp = mdss_dp_get_drvdata(dev);
+
+ if (!dp) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", dp->hpd);
+ pr_debug("hpd: %d\n", dp->hpd);
+
+ return ret;
+}
+
static DEVICE_ATTR(connected, S_IRUGO, mdss_dp_rda_connected, NULL);
static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, mdss_dp_sysfs_rda_s3d_mode,
mdss_dp_sysfs_wta_s3d_mode);
+static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, mdss_dp_rda_hpd,
+ mdss_dp_wta_hpd);
+static DEVICE_ATTR(psm, S_IRUGO | S_IWUSR, mdss_dp_rda_psm,
+ mdss_dp_wta_psm);
+
static struct attribute *mdss_dp_fs_attrs[] = {
&dev_attr_connected.attr,
&dev_attr_s3d_mode.attr,
+ &dev_attr_hpd.attr,
+ &dev_attr_psm.attr,
NULL,
};
@@ -2328,8 +2523,9 @@ static void usbpd_connect_callback(struct usbpd_svid_handler *hdlr)
}
mdss_dp_update_cable_status(dp_drv, true);
- dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES);
- pr_debug("discover_mode event sent\n");
+
+ if (dp_drv->hpd)
+ dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES);
}
static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr)
@@ -2681,6 +2877,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
break;
case USBPD_SVDM_ATTENTION:
node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return;
node->vdo = *vdos;
mutex_lock(&dp_drv->attention_lock);
@@ -2703,8 +2901,10 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
dp_drv->alt_mode.current_state |= DP_CONFIGURE_DONE;
pr_debug("Configure: config USBPD to DP done\n");
+ mdss_dp_host_init(&dp_drv->panel_data);
+
if (dp_drv->alt_mode.dp_status.hpd_high)
- mdss_dp_host_init(&dp_drv->panel_data);
+ mdss_dp_process_hpd_high(dp_drv);
break;
default:
pr_err("unknown cmd: %d\n", cmd);
@@ -2752,12 +2952,12 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
- if (dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)
+ if (dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE) {
mdss_dp_host_init(&dp_drv->panel_data);
- else
+ mdss_dp_process_hpd_high(dp_drv);
+ } else {
dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
-
- pr_debug("exit\n");
+ }
}
static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp)
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 399ca61e0f46..b7a8583e5864 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -399,6 +399,9 @@ struct mdss_dp_drv_pdata {
bool core_clks_on;
bool link_clks_on;
bool power_on;
+ bool sink_info_read;
+ bool hpd;
+ bool psm_enabled;
/* dp specific */
unsigned char *base;
@@ -488,7 +491,6 @@ struct mdss_dp_drv_pdata {
u32 current_event;
spinlock_t event_lock;
spinlock_t lock;
- struct hdmi_util_ds_data ds_data;
struct switch_dev sdev;
struct kobject *kobj;
u32 max_pclk_khz;
@@ -681,6 +683,7 @@ void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up);
void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep);
char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt);
int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
+int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index b8be110f04f0..fa1af0d392e7 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -148,8 +148,11 @@ static int dp_cmd_fifo_tx(struct edp_buf *tp, unsigned char *base)
}
data = (tp->trans_num - 1);
- if (tp->i2c)
+ if (tp->i2c) {
data |= BIT(8); /* I2C */
+ data |= BIT(10); /* NO SEND ADDR */
+ data |= BIT(11); /* NO SEND STOP */
+ }
data |= BIT(9); /* GO */
dp_write(base + DP_AUX_TRANS_CTRL, data);
@@ -213,7 +216,7 @@ static int dp_aux_write_cmds(struct mdss_dp_drv_pdata *ep,
len = dp_cmd_fifo_tx(&ep->txp, ep->base);
- wait_for_completion(&ep->aux_comp);
+ wait_for_completion_timeout(&ep->aux_comp, HZ/4);
if (ep->aux_error_num == EDP_AUX_ERR_NONE)
ret = len;
@@ -269,7 +272,7 @@ static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep,
dp_cmd_fifo_tx(tp, ep->base);
- wait_for_completion(&ep->aux_comp);
+ wait_for_completion_timeout(&ep->aux_comp, HZ/4);
if (ep->aux_error_num == EDP_AUX_ERR_NONE) {
ret = dp_cmd_fifo_rx(rp, len, ep->base);
@@ -731,8 +734,10 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
int rlen, ret = 0;
int edid_blk = 0, blk_num = 0, retries = 10;
bool edid_parsing_done = false;
- const u8 cea_tag = 0x02;
+ const u8 cea_tag = 0x02, start_ext_blk = 0x1;
+ u32 const segment_addr = 0x30;
u32 checksum = 0;
+ char segment = 0x1;
ret = dp_aux_chan_ready(dp);
if (ret) {
@@ -761,7 +766,7 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
ret = dp_edid_buf_error(rp->data, rp->len);
if (ret) {
pr_err("corrupt edid block detected\n");
- goto end;
+ continue;
}
if (edid_parsing_done) {
@@ -779,7 +784,6 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
rp->data);
edid_parsing_done = true;
- checksum = rp->data[rp->len - 1];
} else {
edid_blk++;
blk_num++;
@@ -797,11 +801,17 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
memcpy(dp->edid_buf + (edid_blk * EDID_BLOCK_SIZE),
rp->data, EDID_BLOCK_SIZE);
+ checksum = rp->data[rp->len - 1];
+
+ /* break if no more extension blocks present */
if (edid_blk == dp->edid.ext_block_cnt)
- goto end;
+ break;
+
+ /* write segment number to read block 3 onwards */
+ if (edid_blk == start_ext_blk)
+ dp_aux_write_buf(dp, segment_addr, &segment, 1, 1);
} while (retries--);
-end:
if (dp->test_data.test_requested == TEST_EDID_READ) {
pr_debug("sending checksum %d\n", checksum);
dp_aux_send_checksum(dp, checksum);
@@ -1016,6 +1026,51 @@ int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len)
return len;
}
+/*
+ * mdss_dp_aux_send_psm_request() - sends a power save mode messge to sink
+ * @dp: Display Port Driver data
+ */
+int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable)
+{
+ u8 psm_request[4];
+ int rc = 0;
+
+ psm_request[0] = enable ? 2 : 1;
+
+ pr_debug("sending psm %s request\n", enable ? "entry" : "exit");
+ if (enable) {
+ dp_aux_write_buf(dp, 0x600, psm_request, 1, 0);
+ } else {
+ ktime_t timeout = ktime_add_ms(ktime_get(), 20);
+
+ /*
+ * It could take up to 1ms (20 ms of embedded sinks) till
+ * the sink is ready to reply to this AUX transaction. It is
+ * expected that the source keep retrying periodically during
+ * this time.
+ */
+ for (;;) {
+ rc = dp_aux_write_buf(dp, 0x600, psm_request, 1, 0);
+ if ((rc >= 0) ||
+ (ktime_compare(ktime_get(), timeout) > 0))
+ break;
+ usleep_range(100, 120);
+ }
+
+ /*
+ * if the aux transmission succeeded, then the function would
+ * return the number of bytes transmitted.
+ */
+ if (rc > 0)
+ rc = 0;
+ }
+
+ if (!rc)
+ dp->psm_enabled = enable;
+
+ return rc;
+}
+
/**
* mdss_dp_aux_send_test_response() - sends a test response to the sink
* @dp: Display Port Driver data
@@ -1499,18 +1554,18 @@ static void dp_host_train_set(struct mdss_dp_drv_pdata *ep, int train)
}
char vm_pre_emphasis[4][4] = {
- {0x00, 0x09, 0x11, 0x0C}, /* pe0, 0 db */
- {0x00, 0x0A, 0x10, 0xFF}, /* pe1, 3.5 db */
- {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */
- {0x00, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
+ {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */
+ {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */
+ {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */
+ {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
};
/* voltage swing, 0.2v and 1.0v are not support */
char vm_voltage_swing[4][4] = {
- {0x07, 0x0f, 0x12, 0x1E}, /* sw0, 0.4v */
+ {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */
{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
{0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
- {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
+ {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
};
static void dp_aux_set_voltage_and_pre_emphasis_lvl(
@@ -1524,6 +1579,14 @@ static void dp_aux_set_voltage_and_pre_emphasis_lvl(
value0 = vm_voltage_swing[(int)(dp->v_level)][(int)(dp->p_level)];
value1 = vm_pre_emphasis[(int)(dp->v_level)][(int)(dp->p_level)];
+ /* program default setting first */
+ dp_write(dp->phy_io.base + QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL, 0x2A);
+ dp_write(dp->phy_io.base + QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL, 0x2A);
+ dp_write(dp->phy_io.base + QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL,
+ 0x20);
+ dp_write(dp->phy_io.base + QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL,
+ 0x20);
+
/* Enable MUX to use Cursor values from these registers */
value0 |= BIT(5);
value1 |= BIT(5);
@@ -1590,10 +1653,10 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
pr_debug("Entered++");
- dp_host_train_set(ep, 0x01); /* train_1 */
dp_cap_lane_rate_set(ep);
dp_train_pattern_set_write(ep, 0x21); /* train_1 */
dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
+ dp_host_train_set(ep, 0x01); /* train_1 */
tries = 0;
old_v_level = ep->v_level;
@@ -1648,7 +1711,6 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
dp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */
do {
- dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
dp_host_train_set(ep, pattern);
usleep_time = ep->dpcd.training_read_interval;
@@ -1668,6 +1730,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
}
dp_sink_train_set_adjust(ep);
+ dp_aux_set_voltage_and_pre_emphasis_lvl(ep);
} while (1);
return ret;
@@ -1773,7 +1836,8 @@ clear:
mdss_dp_config_misc_settings(&dp->ctrl_io,
&dp->panel_data.panel_info);
mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate,
- dp->lane_cnt, dp->vic);
+ dp->lane_cnt, dp->vic,
+ &dp->panel_data.panel_info);
mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO);
pr_debug("State_ctrl set to SEND_VIDEO\n");
}
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index 3b294a11f555..a7f42ba8c261 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -208,6 +208,499 @@ void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data)
writel_relaxed(data, ctrl_io->base + DP_STATE_CTRL);
}
+static void mdss_dp_get_extra_req_bytes(u64 result_valid,
+ int valid_bdary_link,
+ u64 value1, u64 value2,
+ bool *negative, u64 *result,
+ u64 compare)
+{
+ *negative = false;
+ if (result_valid >= compare) {
+ if (valid_bdary_link
+ >= compare)
+ *result = value1 + value2;
+ else {
+ if (value1 < value2)
+ *negative = true;
+ *result = (value1 >= value2) ?
+ (value1 - value2) : (value2 - value1);
+ }
+ } else {
+ if (valid_bdary_link
+ >= compare) {
+ if (value1 >= value2)
+ *negative = true;
+ *result = (value1 >= value2) ?
+ (value1 - value2) : (value2 - value1);
+ } else {
+ *result = value1 + value2;
+ *negative = true;
+ }
+ }
+}
+
+static u64 roundup_u64(u64 x, u64 y)
+{
+ x += (y - 1);
+ return (div64_ul(x, y) * y);
+}
+
+static u64 rounddown_u64(u64 x, u64 y)
+{
+ u64 rem;
+
+ div64_u64_rem(x, y, &rem);
+ return (x - rem);
+}
+
+static void mdss_dp_calc_tu_parameters(u8 link_rate, u8 ln_cnt,
+ struct dp_vc_tu_mapping_table *tu_table,
+ struct mdss_panel_info *pinfo)
+{
+ u32 const multiplier = 1000000;
+ u64 pclk, lclk;
+ u8 bpp;
+ int run_idx = 0;
+ u32 lwidth, h_blank;
+ u32 fifo_empty = 0;
+ u32 ratio_scale = 1001;
+ u64 temp, ratio, original_ratio;
+ u64 temp2, reminder;
+ u64 temp3, temp4, result = 0;
+
+ u64 err = multiplier;
+ u64 n_err = 0, n_n_err = 0;
+ bool n_err_neg, nn_err_neg;
+ u8 hblank_margin = 16;
+
+ u8 tu_size, tu_size_desired, tu_size_minus1;
+ int valid_boundary_link;
+ u64 resulting_valid;
+ u64 total_valid;
+ u64 effective_valid;
+ u64 effective_valid_recorded;
+ int n_tus;
+ int n_tus_per_lane;
+ int paired_tus;
+ int remainder_tus;
+ int remainder_tus_upper, remainder_tus_lower;
+ int extra_bytes;
+ int filler_size;
+ int delay_start_link;
+ int boundary_moderation_en = 0;
+ int upper_bdry_cnt = 0;
+ int lower_bdry_cnt = 0;
+ int i_upper_bdry_cnt = 0;
+ int i_lower_bdry_cnt = 0;
+ int valid_lower_boundary_link = 0;
+ int even_distribution_bf = 0;
+ int even_distribution_legacy = 0;
+ int even_distribution = 0;
+ int min_hblank = 0;
+ int extra_pclk_cycles;
+ u8 extra_pclk_cycle_delay = 4;
+ int extra_pclk_cycles_in_link_clk;
+ u64 ratio_by_tu;
+ u64 average_valid2;
+ u64 extra_buffer_margin;
+ int new_valid_boundary_link;
+
+ u64 resulting_valid_tmp;
+ u64 ratio_by_tu_tmp;
+ int n_tus_tmp;
+ int extra_pclk_cycles_tmp;
+ int extra_pclk_cycles_in_lclk_tmp;
+ int extra_req_bytes_new_tmp;
+ int filler_size_tmp;
+ int lower_filler_size_tmp;
+ int delay_start_link_tmp;
+ int min_hblank_tmp = 0;
+ bool extra_req_bytes_is_neg = false;
+
+ u8 dp_brute_force = 1;
+ u64 brute_force_threshold = 10;
+ u64 diff_abs;
+
+ bpp = pinfo->bpp;
+ lwidth = pinfo->xres; /* active width */
+ h_blank = pinfo->lcdc.h_back_porch + pinfo->lcdc.h_front_porch +
+ pinfo->lcdc.h_pulse_width;
+ pclk = pinfo->clk_rate;
+
+ boundary_moderation_en = 0;
+ upper_bdry_cnt = 0;
+ lower_bdry_cnt = 0;
+ i_upper_bdry_cnt = 0;
+ i_lower_bdry_cnt = 0;
+ valid_lower_boundary_link = 0;
+ even_distribution_bf = 0;
+ even_distribution_legacy = 0;
+ even_distribution = 0;
+ min_hblank = 0;
+
+ lclk = link_rate * DP_LINK_RATE_MULTIPLIER;
+
+ pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
+ pclk, lwidth, h_blank);
+ pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt);
+ ratio = div64_u64_rem(pclk * bpp * multiplier,
+ 8 * ln_cnt * lclk, &reminder);
+ ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk));
+ original_ratio = ratio;
+
+ extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay
+ * lclk * multiplier, pclk), multiplier);
+ extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier);
+
+ /* To deal with cases where lines are not distributable */
+ if (((lwidth % ln_cnt) != 0) && ratio < multiplier) {
+ ratio = ratio * ratio_scale;
+ ratio = ratio < (1000 * multiplier)
+ ? ratio : (1000 * multiplier);
+ }
+ pr_debug("ratio = %lld\n", ratio);
+
+ for (tu_size = 32; tu_size <= 64; tu_size++) {
+ temp = ratio * tu_size;
+ temp2 = ((temp / multiplier) + 1) * multiplier;
+ n_err = roundup_u64(temp, multiplier) - temp;
+
+ if (n_err < err) {
+ err = n_err;
+ tu_size_desired = tu_size;
+ }
+ }
+ pr_debug("Info: tu_size_desired = %d\n", tu_size_desired);
+
+ tu_size_minus1 = tu_size_desired - 1;
+
+ valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier);
+ valid_boundary_link /= multiplier;
+ n_tus = rounddown((lwidth * bpp * multiplier)
+ / (8 * valid_boundary_link), multiplier) / multiplier;
+ even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0;
+ pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n",
+ valid_boundary_link, n_tus);
+
+ extra_bytes = roundup_u64((n_tus + 1)
+ * ((valid_boundary_link * multiplier)
+ - (original_ratio * tu_size_desired)), multiplier);
+ extra_bytes /= multiplier;
+ extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp,
+ multiplier);
+ extra_pclk_cycles /= multiplier;
+ extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles
+ * lclk * multiplier, pclk), multiplier);
+ extra_pclk_cycles_in_link_clk /= multiplier;
+ filler_size = roundup_u64((tu_size_desired - valid_boundary_link)
+ * multiplier, multiplier);
+ filler_size /= multiplier;
+ ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier);
+
+ pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n",
+ extra_pclk_cycles_in_link_clk, extra_bytes);
+ pr_debug("extra_pclk_cycles_in_link_clk=%d\n",
+ extra_pclk_cycles_in_link_clk);
+ pr_debug("filler_size=%d, extra_buffer_margin=%lld\n",
+ filler_size, extra_buffer_margin);
+
+ delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk)
+ ? extra_bytes
+ : extra_pclk_cycles_in_link_clk)
+ + filler_size + extra_buffer_margin;
+ resulting_valid = valid_boundary_link;
+ pr_debug("Info: delay_start_link=%d, filler_size=%d\n",
+ delay_start_link, filler_size);
+ pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n",
+ valid_boundary_link, ratio_by_tu);
+
+ diff_abs = (resulting_valid >= ratio_by_tu)
+ ? (resulting_valid - ratio_by_tu)
+ : (ratio_by_tu - resulting_valid);
+
+ if (err != 0 && ((diff_abs > brute_force_threshold)
+ || (even_distribution_legacy == 0)
+ || (dp_brute_force == 1))) {
+ err = multiplier;
+ for (tu_size = 32; tu_size <= 64; tu_size++) {
+ for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15;
+ i_upper_bdry_cnt++) {
+ for (i_lower_bdry_cnt = 1;
+ i_lower_bdry_cnt <= 15;
+ i_lower_bdry_cnt++) {
+ new_valid_boundary_link =
+ roundup_u64(ratio
+ * tu_size, multiplier);
+ average_valid2 = (i_upper_bdry_cnt
+ * new_valid_boundary_link
+ + i_lower_bdry_cnt
+ * (new_valid_boundary_link
+ - multiplier))
+ / (i_upper_bdry_cnt
+ + i_lower_bdry_cnt);
+ n_tus = rounddown_u64(div64_u64(lwidth
+ * multiplier * multiplier
+ * (bpp / 8), average_valid2),
+ multiplier);
+ n_tus /= multiplier;
+ n_tus_per_lane
+ = rounddown(n_tus
+ * multiplier
+ / ln_cnt, multiplier);
+ n_tus_per_lane /= multiplier;
+ paired_tus =
+ rounddown((n_tus_per_lane)
+ * multiplier
+ / (i_upper_bdry_cnt
+ + i_lower_bdry_cnt),
+ multiplier);
+ paired_tus /= multiplier;
+ remainder_tus = n_tus_per_lane
+ - paired_tus
+ * (i_upper_bdry_cnt
+ + i_lower_bdry_cnt);
+ if ((remainder_tus
+ - i_upper_bdry_cnt) > 0) {
+ remainder_tus_upper
+ = i_upper_bdry_cnt;
+ remainder_tus_lower =
+ remainder_tus
+ - i_upper_bdry_cnt;
+ } else {
+ remainder_tus_upper
+ = remainder_tus;
+ remainder_tus_lower = 0;
+ }
+ total_valid = paired_tus
+ * (i_upper_bdry_cnt
+ * new_valid_boundary_link
+ + i_lower_bdry_cnt
+ * (new_valid_boundary_link
+ - multiplier))
+ + (remainder_tus_upper
+ * new_valid_boundary_link)
+ + (remainder_tus_lower
+ * (new_valid_boundary_link
+ - multiplier));
+ n_err_neg = nn_err_neg = false;
+ effective_valid
+ = div_u64(total_valid,
+ n_tus_per_lane);
+ n_n_err = (effective_valid
+ >= (ratio * tu_size))
+ ? (effective_valid
+ - (ratio * tu_size))
+ : ((ratio * tu_size)
+ - effective_valid);
+ if (effective_valid < (ratio * tu_size))
+ nn_err_neg = true;
+ n_err = (average_valid2
+ >= (ratio * tu_size))
+ ? (average_valid2
+ - (ratio * tu_size))
+ : ((ratio * tu_size)
+ - average_valid2);
+ if (average_valid2 < (ratio * tu_size))
+ n_err_neg = true;
+ even_distribution =
+ n_tus % ln_cnt == 0 ? 1 : 0;
+ diff_abs =
+ resulting_valid >= ratio_by_tu
+ ? (resulting_valid
+ - ratio_by_tu)
+ : (ratio_by_tu
+ - resulting_valid);
+
+ resulting_valid_tmp = div64_u64(
+ (i_upper_bdry_cnt
+ * new_valid_boundary_link
+ + i_lower_bdry_cnt
+ * (new_valid_boundary_link
+ - multiplier)),
+ (i_upper_bdry_cnt
+ + i_lower_bdry_cnt));
+ ratio_by_tu_tmp =
+ original_ratio * tu_size;
+ ratio_by_tu_tmp /= multiplier;
+ n_tus_tmp = rounddown_u64(
+ div64_u64(lwidth
+ * multiplier * multiplier
+ * bpp / 8,
+ resulting_valid_tmp),
+ multiplier);
+ n_tus_tmp /= multiplier;
+
+ temp3 = (resulting_valid_tmp
+ >= (original_ratio * tu_size))
+ ? (resulting_valid_tmp
+ - original_ratio * tu_size)
+ : (original_ratio * tu_size)
+ - resulting_valid_tmp;
+ temp3 = (n_tus_tmp + 1) * temp3;
+ temp4 = (new_valid_boundary_link
+ >= (original_ratio * tu_size))
+ ? (new_valid_boundary_link
+ - original_ratio
+ * tu_size)
+ : (original_ratio * tu_size)
+ - new_valid_boundary_link;
+ temp4 = (i_upper_bdry_cnt
+ * ln_cnt * temp4);
+
+ temp3 = roundup_u64(temp3, multiplier);
+ temp4 = roundup_u64(temp4, multiplier);
+ mdss_dp_get_extra_req_bytes
+ (resulting_valid_tmp,
+ new_valid_boundary_link,
+ temp3, temp4,
+ &extra_req_bytes_is_neg,
+ &result,
+ (original_ratio * tu_size));
+ extra_req_bytes_new_tmp
+ = div64_ul(result, multiplier);
+ if ((extra_req_bytes_is_neg)
+ && (extra_req_bytes_new_tmp
+ > 1))
+ extra_req_bytes_new_tmp
+ = extra_req_bytes_new_tmp - 1;
+ if (extra_req_bytes_new_tmp == 0)
+ extra_req_bytes_new_tmp = 1;
+ extra_pclk_cycles_tmp =
+ (u64)(extra_req_bytes_new_tmp
+ * 8 * multiplier) / bpp;
+ extra_pclk_cycles_tmp /= multiplier;
+
+ if (extra_pclk_cycles_tmp <= 0)
+ extra_pclk_cycles_tmp = 1;
+ extra_pclk_cycles_in_lclk_tmp =
+ roundup_u64(div64_u64(
+ extra_pclk_cycles_tmp
+ * lclk * multiplier,
+ pclk), multiplier);
+ extra_pclk_cycles_in_lclk_tmp
+ /= multiplier;
+ filler_size_tmp = roundup_u64(
+ (tu_size * multiplier *
+ new_valid_boundary_link),
+ multiplier);
+ filler_size_tmp /= multiplier;
+ lower_filler_size_tmp =
+ filler_size_tmp + 1;
+ if (extra_req_bytes_is_neg)
+ temp3 = (extra_req_bytes_new_tmp
+ > extra_pclk_cycles_in_lclk_tmp
+ ? extra_pclk_cycles_in_lclk_tmp
+ : extra_req_bytes_new_tmp);
+ else
+ temp3 = (extra_req_bytes_new_tmp
+ > extra_pclk_cycles_in_lclk_tmp
+ ? extra_req_bytes_new_tmp :
+ extra_pclk_cycles_in_lclk_tmp);
+
+ temp4 = lower_filler_size_tmp
+ + extra_buffer_margin;
+ if (extra_req_bytes_is_neg)
+ delay_start_link_tmp
+ = (temp3 >= temp4)
+ ? (temp3 - temp4)
+ : (temp4 - temp3);
+ else
+ delay_start_link_tmp
+ = temp3 + temp4;
+
+ min_hblank_tmp = (int)div64_u64(
+ roundup_u64(
+ div64_u64(delay_start_link_tmp
+ * pclk * multiplier, lclk),
+ multiplier), multiplier)
+ + hblank_margin;
+
+ if (((even_distribution == 1)
+ || ((even_distribution_bf == 0)
+ && (even_distribution_legacy
+ == 0)))
+ && !n_err_neg && !nn_err_neg
+ && n_n_err < err
+ && (n_n_err < diff_abs
+ || (dp_brute_force == 1))
+ && (new_valid_boundary_link
+ - 1) > 0
+ && (h_blank >=
+ (u32)min_hblank_tmp)) {
+ upper_bdry_cnt =
+ i_upper_bdry_cnt;
+ lower_bdry_cnt =
+ i_lower_bdry_cnt;
+ err = n_n_err;
+ boundary_moderation_en = 1;
+ tu_size_desired = tu_size;
+ valid_boundary_link =
+ new_valid_boundary_link;
+ effective_valid_recorded
+ = effective_valid;
+ delay_start_link
+ = delay_start_link_tmp;
+ filler_size = filler_size_tmp;
+ min_hblank = min_hblank_tmp;
+ n_tus = n_tus_tmp;
+ even_distribution_bf = 1;
+
+ pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n",
+ upper_bdry_cnt,
+ lower_bdry_cnt, err,
+ tu_size_desired,
+ valid_boundary_link,
+ effective_valid);
+ }
+ }
+ }
+ }
+
+ if (boundary_moderation_en == 1) {
+ resulting_valid = (u64)(upper_bdry_cnt
+ *valid_boundary_link + lower_bdry_cnt
+ * (valid_boundary_link - 1))
+ / (upper_bdry_cnt + lower_bdry_cnt);
+ ratio_by_tu = original_ratio * tu_size_desired;
+ valid_lower_boundary_link =
+ (valid_boundary_link / multiplier) - 1;
+
+ tu_size_minus1 = tu_size_desired - 1;
+ even_distribution_bf = 1;
+ valid_boundary_link /= multiplier;
+ pr_debug("Info: Boundary_moderation enabled\n");
+ }
+ }
+
+ min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk
+ * multiplier, lclk), multiplier))
+ / multiplier + hblank_margin;
+ if (h_blank < (u32)min_hblank) {
+ pr_err(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n",
+ run_idx, h_blank, min_hblank);
+ }
+
+ if (fifo_empty) {
+ tu_size_minus1 = 31;
+ valid_boundary_link = 32;
+ delay_start_link = 0;
+ boundary_moderation_en = 0;
+ }
+
+ pr_debug("tu_size_minus1=%d valid_boundary_link=%d delay_start_link=%d boundary_moderation_en=%d\n upper_boundary_cnt=%d lower_boundary_cnt=%d valid_lower_boundary_link=%d min_hblank=%d\n",
+ tu_size_minus1, valid_boundary_link, delay_start_link,
+ boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt,
+ valid_lower_boundary_link, min_hblank);
+
+ tu_table->valid_boundary_link = valid_boundary_link;
+ tu_table->delay_start_link = delay_start_link;
+ tu_table->boundary_moderation_en = boundary_moderation_en;
+ tu_table->valid_lower_boundary_link = valid_lower_boundary_link;
+ tu_table->upper_boundary_count = upper_bdry_cnt;
+ tu_table->lower_boundary_count = lower_bdry_cnt;
+ tu_table->tu_size_minus1 = tu_size_minus1;
+}
+
void mdss_dp_timing_cfg(struct dss_io_data *ctrl_io,
struct mdss_panel_info *pinfo)
{
@@ -297,12 +790,13 @@ void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io,
}
void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate,
- u8 ln_cnt, u32 res)
+ u8 ln_cnt, u32 res, struct mdss_panel_info *pinfo)
{
u32 dp_tu = 0x0;
u32 valid_boundary = 0x0;
u32 valid_boundary2 = 0x0;
struct dp_vc_tu_mapping_table const *tu_entry = tu_table;
+ struct dp_vc_tu_mapping_table tu_calc_table;
for (; tu_entry != tu_table + ARRAY_SIZE(tu_table); ++tu_entry) {
if ((tu_entry->vic == res) &&
@@ -314,18 +808,18 @@ void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate,
if (tu_entry == tu_table + ARRAY_SIZE(tu_table)) {
pr_err("requested res=%d, ln_cnt=%d, lrate=0x%x not supported\n",
res, ln_cnt, link_rate);
- return;
}
- dp_tu |= tu_entry->tu_size_minus1;
- valid_boundary |= tu_entry->valid_boundary_link;
- valid_boundary |= (tu_entry->delay_start_link << 16);
+ mdss_dp_calc_tu_parameters(link_rate, ln_cnt, &tu_calc_table, pinfo);
+ dp_tu |= tu_calc_table.tu_size_minus1;
+ valid_boundary |= tu_calc_table.valid_boundary_link;
+ valid_boundary |= (tu_calc_table.delay_start_link << 16);
- valid_boundary2 |= (tu_entry->valid_lower_boundary_link << 1);
- valid_boundary2 |= (tu_entry->upper_boundary_count << 16);
- valid_boundary2 |= (tu_entry->lower_boundary_count << 20);
+ valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
+ valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
+ valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
- if (tu_entry->boundary_moderation_en)
+ if (tu_calc_table.boundary_moderation_en)
valid_boundary2 |= BIT(0);
writel_relaxed(valid_boundary, ctrl_io->base + DP_VALID_BOUNDARY);
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h
index c046deef48a3..fcb9a77db67c 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.h
+++ b/drivers/video/fbdev/msm/mdss_dp_util.h
@@ -284,7 +284,7 @@ void mdss_dp_phy_reset(struct dss_io_data *ctrl_io);
void mdss_dp_switch_usb3_phy_to_dp_mode(struct dss_io_data *tcsr_reg_io);
void mdss_dp_assert_phy_reset(struct dss_io_data *ctrl_io, bool assert);
void mdss_dp_setup_tr_unit(struct dss_io_data *ctrl_io, u8 link_rate,
- u8 ln_cnt, u32 res);
+ u8 ln_cnt, u32 res, struct mdss_panel_info *pinfo);
void mdss_dp_config_misc_settings(struct dss_io_data *ctrl_io,
struct mdss_panel_info *pinfo);
void mdss_dp_phy_aux_setup(struct dss_io_data *phy_io);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 35913a26317d..0f5a156d638c 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -3076,7 +3076,7 @@ static int mdss_fb_pan_display_ex(struct fb_info *info,
if (var->yoffset > (info->var.yres_virtual - info->var.yres))
return -EINVAL;
- ret = mdss_fb_wait_for_kickoff(mfd);
+ ret = mdss_fb_pan_idle(mfd);
if (ret) {
pr_err("wait_for_kick failed. rc=%d\n", ret);
return ret;
diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
index 212f3be96bf2..08307fe8eb16 100644
--- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c
+++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
@@ -195,7 +195,7 @@ struct hdcp_reg_set {
#define HDCP_DP_SINK_ADDR_MAP \
{{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
- {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 2}, \
+ {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 1}, \
{"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \
{"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \
{"an", 0x6800C, 8}, {"aksv", 0x68007, 5}, {"ainfo", 0x6803B, 1} }
@@ -1763,6 +1763,30 @@ static void hdcp_1x_update_client_reg_set(struct hdcp_1x *hdcp)
}
}
+static bool hdcp_1x_is_cp_irq_raised(struct hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = 0;
+ struct hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = hdcp_1x_read(hdcp, &sink, &buf, false);
+ if (IS_ERR_VALUE(ret))
+ pr_err("error reading irq_vector\n");
+
+ return buf & BIT(2) ? true : false;
+}
+
+static void hdcp_1x_clear_cp_irq(struct hdcp_1x *hdcp)
+{
+ int ret;
+ u8 buf = BIT(2);
+ struct hdcp_sink_addr sink = {"irq", 0x201, 1};
+
+ ret = hdcp_1x_write(hdcp, &sink, &buf);
+ if (IS_ERR_VALUE(ret))
+ pr_err("error clearing irq_vector\n");
+}
+
static int hdcp_1x_cp_irq(void *input)
{
struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
@@ -1771,14 +1795,19 @@ static int hdcp_1x_cp_irq(void *input)
if (!hdcp) {
pr_err("invalid input\n");
- goto end;
+ goto irq_not_handled;
+ }
+
+ if (!hdcp_1x_is_cp_irq_raised(hdcp)) {
+ pr_debug("cp_irq not raised\n");
+ goto irq_not_handled;
}
ret = hdcp_1x_read(hdcp, &hdcp->sink_addr.cp_irq_status,
&buf, false);
if (IS_ERR_VALUE(ret)) {
pr_err("error reading cp_irq_status\n");
- return ret;
+ goto irq_not_handled;
}
if ((buf & BIT(2)) || (buf & BIT(3))) {
@@ -1793,27 +1822,23 @@ static int hdcp_1x_cp_irq(void *input)
complete_all(&hdcp->sink_r0_available);
hdcp_1x_update_auth_status(hdcp);
-
- goto end;
- }
-
- if (buf & BIT(1)) {
+ } else if (buf & BIT(1)) {
pr_debug("R0' AVAILABLE\n");
hdcp->sink_r0_ready = true;
complete_all(&hdcp->sink_r0_available);
- goto end;
- }
-
- if ((buf & BIT(0))) {
+ } else if ((buf & BIT(0))) {
pr_debug("KSVs READY\n");
hdcp->ksv_ready = true;
- goto end;
+ } else {
+ pr_debug("spurious interrupt\n");
}
- return -EINVAL;
-end:
+ hdcp_1x_clear_cp_irq(hdcp);
return 0;
+
+irq_not_handled:
+ return -EINVAL;
}
void *hdcp_1x_init(struct hdcp_init_data *init_data)
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index bb8227a74a04..5744f7d037b4 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -3513,7 +3513,6 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl)
struct mdss_overlay_private *mdp5_data = NULL;
struct mdss_mdp_wb_data *cwb_data;
struct mdss_mdp_writeback_arg wb_args;
- struct mdss_mdp_ctl *sctl = NULL;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 opmode, data_point;
@@ -3575,14 +3574,11 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl)
/* Select MEM_SEL to WB */
ctl->opmode |= MDSS_MDP_CTL_OP_WFD_MODE;
- sctl = mdss_mdp_get_split_ctl(ctl);
- if (sctl)
- sctl->opmode |= MDSS_MDP_CTL_OP_WFD_MODE;
/* Select CWB data point */
data_point = (cwb->layer.flags & MDP_COMMIT_CWB_DSPP) ? 0x4 : 0;
writel_relaxed(data_point, mdata->mdp_base + mdata->ppb_ctl[2]);
- if (sctl)
+ if (ctl->mixer_right)
writel_relaxed(data_point + 1,
mdata->mdp_base + mdata->ppb_ctl[3]);
@@ -3591,11 +3587,6 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl)
opmode = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_TOP) | ctl->opmode;
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, opmode);
- if (sctl) {
- opmode = mdss_mdp_ctl_read(sctl, MDSS_MDP_REG_CTL_TOP) |
- sctl->opmode;
- mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_TOP, opmode);
- }
/* Increase commit count to signal CWB release fence */
atomic_inc(&cwb->cwb_sync_pt_data.commit_cnt);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 4852fc73f040..6d5927cf3cdc 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -2110,8 +2110,10 @@ static void mdss_mdp_cmd_dsc_reconfig(struct mdss_mdp_ctl *ctl)
}
}
- changed = ctl->mixer_left->roi_changed;
- if (is_split_lm(ctl->mfd))
+ if (ctl->mixer_left)
+ changed |= ctl->mixer_left->roi_changed;
+ if (is_split_lm(ctl->mfd) &&
+ ctl->mixer_right)
changed |= ctl->mixer_right->roi_changed;
if (changed)
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index 80549908beb6..9bebd72dce61 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -262,7 +262,7 @@ static void mdss_mdp_writeback_cwb_overflow(void *arg)
mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
CWB_PPB_0, NULL, NULL);
- if (mdss_mdp_get_split_ctl(ctl)) {
+ if (ctl->mixer_right) {
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
CWB_PPB_1);
mdss_mdp_set_intr_callback_nosync(
@@ -297,7 +297,7 @@ static void mdss_mdp_writeback_cwb_intr_done(void *arg)
mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
CWB_PPB_0, NULL, NULL);
- if (mdss_mdp_get_split_ctl(ctl)) {
+ if (ctl->mixer_right) {
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
CWB_PPB_1);
mdss_mdp_set_intr_callback_nosync(
@@ -477,21 +477,34 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_writeback_ctx *ctx = NULL;
struct mdp_layer_buffer *buffer = NULL;
struct mdss_mdp_cwb *cwb = NULL;
- struct mdss_mdp_ctl *sctl = NULL;
- int ret = 0;
+ int i, ret = 0;
+ unsigned long total_buf_len = 0;
+ struct mdss_mdp_data *data = NULL;
+ struct mdss_mdp_plane_sizes ps;
+ struct mdss_mdp_format_params *fmt;
+
+ if (!wb_arg->data)
+ return -EINVAL;
mdp5_data = mfd_to_mdp5_data(ctl->mfd);
cwb = &mdp5_data->cwb;
ctx = (struct mdss_mdp_writeback_ctx *)cwb->priv_data;
+ data = wb_arg->data;
buffer = &cwb->layer.buffer;
- ctx->opmode = 0;
- ctx->img_width = buffer->width;
+ /*
+ * client can program CWB output dimensions as only primary
+ * resolution, but output buffer allocated can be with bigger stride
+ * aligned for platform specific reasons & can interpret the output
+ * buffer in same stride. Program output stride based on client request
+ */
+ ctx->img_width = buffer->planes[0].stride;
ctx->img_height = buffer->height;
ctx->width = buffer->width;
ctx->height = buffer->height;
ctx->frame_rate = ctl->frame_rate;
+ ctx->opmode = 0;
ctx->dst_rect.x = 0;
ctx->dst_rect.y = 0;
ctx->dst_rect.w = ctx->width;
@@ -503,6 +516,23 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl,
return ret;
}
+ /*
+ * Need additional buffer size validation as we are
+ * updating img_width with buffer->planes[0].stride
+ */
+ fmt = mdss_mdp_get_format_params(buffer->format);
+ mdss_mdp_get_plane_sizes(fmt, ctx->img_width,
+ buffer->height, &ps, 0, 0);
+
+ for (i = 0; i < buffer->plane_count ; i++)
+ total_buf_len += data->p[i].len;
+
+ if (total_buf_len < ps.total_size) {
+ pr_err("Buffer size=%lu, expected size=%d\n", total_buf_len,
+ ps.total_size);
+ return -EINVAL;
+ }
+
ret = mdss_mdp_writeback_addr_setup(ctx, wb_arg->data);
if (ret) {
pr_err("cwb writeback data setup error\n");
@@ -516,11 +546,10 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl,
CWB_PPB_0, mdss_mdp_writeback_cwb_overflow, ctl);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0);
- sctl = mdss_mdp_get_split_ctl(ctl);
- if (sctl) {
+ if (ctl->mixer_right) {
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
CWB_PPB_1, mdss_mdp_writeback_cwb_overflow,
- sctl);
+ ctl);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 0731cbcafe7c..c53c8d293539 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -2823,6 +2823,8 @@ int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd,
}
mdp5_data->cwb.layer = *commit->output_layer;
+ mdp5_data->cwb.layer.flags |= (commit->flags & MDP_COMMIT_CWB_DSPP) ?
+ MDP_COMMIT_CWB_DSPP : 0;
mdp5_data->cwb.wb_idx = commit->output_layer->writeback_ndx;
mutex_lock(&mdp5_data->cwb.queue_lock);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 59a25ee95900..4ae91cf8e81d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1931,8 +1931,7 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe)
}
/**
- * __crop_adjust_pipe_rect() - Adjust pipe roi for dual partial
- * update feature.
+ * __adjust_pipe_rect() - Adjust pipe roi for dual partial update feature.
* @pipe: pipe to check against.
* @dual_roi: roi's for the dual partial roi.
*
@@ -1940,53 +1939,54 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe)
* by merging the two width aligned ROIs (first_roi and
* second_roi) vertically. So, the y-offset of all the
* pipes belonging to the second_roi needs to adjusted
- * accordingly. Also the cropping of the pipe's src/dst
- * rect has to be done with respect to the ROI the pipe
- * is intersecting with, before the adjustment.
+ * accordingly. Also check, if the pipe dest rect is
+ * totally within first or second ROI.
*/
-static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe,
+static int __adjust_pipe_rect(struct mdss_mdp_pipe *pipe,
struct mdss_dsi_dual_pu_roi *dual_roi)
{
u32 adjust_h;
- u32 roi_y_pos;
int ret = 0;
+ struct mdss_rect res_rect;
if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) {
- mdss_mdp_crop_rect(&pipe->src, &pipe->dst,
- &dual_roi->first_roi, false);
- pipe->restore_roi = true;
+ mdss_mdp_intersect_rect(&res_rect, &pipe->dst,
+ &dual_roi->first_roi);
+ if (!mdss_rect_cmp(&res_rect, &pipe->dst)) {
+ ret = -EINVAL;
+ goto end;
+ }
} else if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->second_roi)) {
- mdss_mdp_crop_rect(&pipe->src, &pipe->dst,
- &dual_roi->second_roi, false);
- adjust_h = dual_roi->second_roi.y;
- roi_y_pos = dual_roi->first_roi.y + dual_roi->first_roi.h;
-
- if (adjust_h > roi_y_pos) {
- adjust_h = adjust_h - roi_y_pos;
- pipe->dst.y -= adjust_h;
- } else {
- pr_err("wrong y-pos adjust_y:%d roi_y_pos:%d\n",
- adjust_h, roi_y_pos);
+ mdss_mdp_intersect_rect(&res_rect, &pipe->dst,
+ &dual_roi->second_roi);
+ if (!mdss_rect_cmp(&res_rect, &pipe->dst)) {
ret = -EINVAL;
+ goto end;
}
+
+ adjust_h = dual_roi->second_roi.y -
+ (dual_roi->first_roi.y + dual_roi->first_roi.h);
+ pipe->dst.y -= adjust_h;
pipe->restore_roi = true;
} else {
ret = -EINVAL;
+ goto end;
}
- pr_debug("crop/adjusted p:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d} r:%d\n",
+ pr_debug("adjusted p:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d} r:%d\n",
pipe->num, pipe->src.x, pipe->src.y,
pipe->src.w, pipe->src.h, pipe->dst.x,
pipe->dst.y, pipe->dst.w, pipe->dst.h,
pipe->restore_roi);
+end:
if (ret) {
- pr_err("dual roi error p%d dst{%d,%d,%d,%d}",
- pipe->num, pipe->dst.x, pipe->dst.y, pipe->dst.w,
- pipe->dst.h);
- pr_err(" roi1{%d,%d,%d,%d} roi2{%d,%d,%d,%d}\n",
+ pr_err("pipe:%d dst:{%d,%d,%d,%d} - not cropped for any PU ROI",
+ pipe->num, pipe->dst.x, pipe->dst.y,
+ pipe->dst.w, pipe->dst.h);
+ pr_err("ROI0:{%d,%d,%d,%d} ROI1:{%d,%d,%d,%d}\n",
dual_roi->first_roi.x, dual_roi->first_roi.y,
dual_roi->first_roi.w, dual_roi->first_roi.h,
dual_roi->second_roi.x, dual_roi->second_roi.y,
@@ -2109,7 +2109,7 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
pipe->dst.y, pipe->dst.w, pipe->dst.h);
if (dual_roi->enabled) {
- if (__crop_adjust_pipe_rect(pipe, dual_roi)) {
+ if (__adjust_pipe_rect(pipe, dual_roi)) {
skip_partial_update = true;
break;
}
@@ -2117,7 +2117,7 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
if (!__is_roi_valid(pipe, &l_roi, &r_roi)) {
skip_partial_update = true;
- pr_err("error. invalid pu config for pipe%d: %d,%d,%d,%d, dual_pu_roi:%d\n",
+ pr_err("error. invalid pu config for pipe:%d dst:{%d,%d,%d,%d} dual_pu_roi:%d\n",
pipe->num, pipe->dst.x, pipe->dst.y,
pipe->dst.w, pipe->dst.h,
dual_roi->enabled);
@@ -2288,7 +2288,7 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
int ret = 0;
struct mdss_mdp_commit_cb commit_cb;
- if (!ctl)
+ if (!ctl || !ctl->mixer_left)
return -ENODEV;
ATRACE_BEGIN(__func__);
@@ -2325,7 +2325,6 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
mdss_mdp_check_ctl_reset_status(ctl);
- __vsync_set_vsync_handler(mfd);
__validate_and_set_roi(mfd, data);
if (ctl->ops.wait_pingpong && mdp5_data->mdata->serialize_wait4pp)
@@ -2374,6 +2373,7 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
&commit_cb);
ATRACE_END("display_commit");
}
+ __vsync_set_vsync_handler(mfd);
/*
* release the commit pending flag; we are releasing this flag
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 733a479f3f17..94ace231b3bd 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -68,6 +68,7 @@ struct wiphy;
#define CFG80211_CONNECT_BSS 1
#define CFG80211_ABORT_SCAN 1
#define CFG80211_UPDATE_CONNECT_PARAMS 1
+#define CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT 1
/*
* wireless hardware capability structures
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index 50b8fc32b129..746eee61ad0e 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -986,6 +986,22 @@ static inline unsigned int VENUS_BUFFER_SIZE(
MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride);
size = MSM_MEDIA_ALIGN(size, 4096);
break;
+ case COLOR_FMT_P010_UBWC:
+ y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
+ uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
+ y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
+ y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height);
+ y_meta_plane = MSM_MEDIA_ALIGN(
+ y_meta_stride * y_meta_scanlines, 4096);
+ uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
+ uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height);
+ uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride *
+ uv_meta_scanlines, 4096);
+
+ size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
+ uv_meta_plane;
+ size = MSM_MEDIA_ALIGN(size, 4096);
+ break;
case COLOR_FMT_RGBA8888:
rgb_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096);
size = rgb_plane;
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index 008d034fcf8f..d23799a5b260 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -2809,6 +2809,9 @@ int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
if (!port_ptr || !name)
return -EINVAL;
+ if (port_ptr->type != CLIENT_PORT)
+ return -EINVAL;
+
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index fa396aa55ac9..1258c83e26a1 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -1536,6 +1536,13 @@ static int tomtom_mad_input_put(struct snd_kcontrol *kcontrol,
tomtom_mad_input = ucontrol->value.integer.value[0];
micb_4_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
+ if (tomtom_mad_input >= ARRAY_SIZE(tomtom_conn_mad_text)) {
+ dev_err(codec->dev,
+ "%s: tomtom_mad_input = %d out of bounds\n",
+ __func__, tomtom_mad_input);
+ return -EINVAL;
+ }
+
pr_debug("%s: tomtom_mad_input = %s\n", __func__,
tomtom_conn_mad_text[tomtom_mad_input]);
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 71858e268232..89357f32d288 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -7931,6 +7931,13 @@ static int tasha_mad_input_put(struct snd_kcontrol *kcontrol,
tasha_mad_input = ucontrol->value.integer.value[0];
+ if (tasha_mad_input >= ARRAY_SIZE(tasha_conn_mad_text)) {
+ dev_err(codec->dev,
+ "%s: tasha_mad_input = %d out of bounds\n",
+ __func__, tasha_mad_input);
+ return -EINVAL;
+ }
+
if (!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED1") ||
!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED2") ||
!strcmp(tasha_conn_mad_text[tasha_mad_input], "NOTUSED3") ||
@@ -13441,8 +13448,6 @@ static int tasha_post_reset_cb(struct wcd9xxx *wcd9xxx)
/* Class-H Init*/
wcd_clsh_init(&tasha->clsh_d);
- /* Default HPH Mode to Class-H HiFi */
- tasha->hph_mode = CLS_H_HIFI;
for (i = 0; i < TASHA_MAX_MICBIAS; i++)
tasha->micb_ref[i] = 0;
@@ -13450,8 +13455,6 @@ static int tasha_post_reset_cb(struct wcd9xxx *wcd9xxx)
tasha_update_reg_defaults(tasha);
tasha->codec = codec;
- for (i = 0; i < COMPANDER_MAX; i++)
- tasha->comp_enabled[i] = 0;
dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
__func__, control->mclk_rate);
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 52830c9cbecb..efb6644e551f 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -730,8 +730,13 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_LSM_SET_SESSION_DATA:
dev_dbg(rtd->dev, "%s: set session data\n", __func__);
- memcpy(&session_data, arg,
- sizeof(struct snd_lsm_session_data));
+ if (copy_from_user(&session_data, arg,
+ sizeof(session_data))) {
+ dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
+ __func__, "LSM_SET_SESSION_DATA");
+ return -EFAULT;
+ }
+
if (session_data.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
dev_err(rtd->dev,
"%s:Invalid App id %d for Listen client\n",
@@ -820,13 +825,6 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break;
case SNDRV_LSM_SET_PARAMS:
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s Invalid argument\n",
- __func__, "SNDRV_LSM_SET_PARAMS");
- return -EINVAL;
- }
-
dev_dbg(rtd->dev, "%s: set_params\n", __func__);
memcpy(&det_params, arg,
sizeof(det_params));
@@ -978,45 +976,43 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break;
}
case SNDRV_LSM_LAB_CONTROL: {
- u32 *enable = NULL;
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid param arg for ioctl %s session %d\n",
- __func__, "SNDRV_LSM_LAB_CONTROL",
- prtd->lsm_client->session);
- rc = -EINVAL;
- break;
+ u32 enable;
+
+ if (copy_from_user(&enable, arg, sizeof(enable))) {
+ dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
+ __func__, "LSM_LAB_CONTROL");
+ return -EFAULT;
}
- enable = (int *)arg;
+
dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
- __func__, "SNDRV_LSM_LAB_CONTROL", *enable);
+ __func__, "SNDRV_LSM_LAB_CONTROL", enable);
if (!prtd->lsm_client->started) {
- if (prtd->lsm_client->lab_enable == *enable) {
+ if (prtd->lsm_client->lab_enable == enable) {
dev_dbg(rtd->dev,
"%s: Lab for session %d already %s\n",
__func__, prtd->lsm_client->session,
- ((*enable) ? "enabled" : "disabled"));
+ enable ? "enabled" : "disabled");
rc = 0;
break;
}
- rc = q6lsm_lab_control(prtd->lsm_client, *enable);
+ rc = q6lsm_lab_control(prtd->lsm_client, enable);
if (rc) {
dev_err(rtd->dev,
"%s: ioctl %s failed rc %d to %s lab for session %d\n",
__func__, "SNDRV_LAB_CONTROL", rc,
- ((*enable) ? "enable" : "disable"),
+ enable ? "enable" : "disable",
prtd->lsm_client->session);
} else {
rc = msm_lsm_lab_buffer_alloc(prtd,
- ((*enable) ? LAB_BUFFER_ALLOC
- : LAB_BUFFER_DEALLOC));
+ enable ? LAB_BUFFER_ALLOC
+ : LAB_BUFFER_DEALLOC);
if (rc)
dev_err(rtd->dev,
"%s: msm_lsm_lab_buffer_alloc failed rc %d for %s",
__func__, rc,
- ((*enable) ? "ALLOC" : "DEALLOC"));
+ enable ? "ALLOC" : "DEALLOC");
if (!rc)
- prtd->lsm_client->lab_enable = *enable;
+ prtd->lsm_client->lab_enable = enable;
}
} else {
dev_err(rtd->dev, "%s: ioctl %s issued after start",
@@ -1057,12 +1053,6 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
return rc;
}
#ifdef CONFIG_COMPAT
-struct snd_lsm_event_status32 {
- u16 status;
- u16 payload_size;
- u8 payload[0];
-};
-
struct snd_lsm_sound_model_v2_32 {
compat_uptr_t data;
compat_uptr_t confidence_level;
@@ -1094,8 +1084,6 @@ struct snd_lsm_module_params_32 {
};
enum {
- SNDRV_LSM_EVENT_STATUS32 =
- _IOW('U', 0x02, struct snd_lsm_event_status32),
SNDRV_LSM_REG_SND_MODEL_V2_32 =
_IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
SNDRV_LSM_SET_PARAMS_32 =
@@ -1126,12 +1114,12 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
prtd = runtime->private_data;
switch (cmd) {
- case SNDRV_LSM_EVENT_STATUS32: {
- struct snd_lsm_event_status32 userarg32, *user32 = NULL;
- struct snd_lsm_event_status *user = NULL;
+ case SNDRV_LSM_EVENT_STATUS: {
+ struct snd_lsm_event_status *user = NULL, userarg32;
+ struct snd_lsm_event_status *user32 = NULL;
if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
- __func__, "SNDRV_LSM_EVENT_STATUS32");
+ __func__, "SNDRV_LSM_EVENT_STATUS");
return -EFAULT;
}
@@ -1285,13 +1273,6 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s: No Param data to set\n",
- __func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
- }
-
if (copy_from_user(&p_data_32, arg,
sizeof(p_data_32))) {
dev_err(rtd->dev,
@@ -1376,6 +1357,19 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
kfree(params32);
break;
}
+ case SNDRV_LSM_REG_SND_MODEL_V2:
+ case SNDRV_LSM_SET_PARAMS:
+ case SNDRV_LSM_SET_MODULE_PARAMS:
+ /*
+ * In ideal cases, the compat_ioctl should never be called
+ * with the above unlocked ioctl commands. Print error
+ * and return error if it does.
+ */
+ dev_err(rtd->dev,
+ "%s: Invalid cmd for compat_ioctl\n",
+ __func__);
+ err = -EINVAL;
+ break;
default:
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
@@ -1391,7 +1385,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
{
int err = 0;
u32 size = 0;
- struct snd_lsm_session_data session_data;
struct snd_pcm_runtime *runtime;
struct snd_soc_pcm_runtime *rtd;
struct lsm_priv *prtd;
@@ -1406,26 +1399,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
rtd = substream->private_data;
switch (cmd) {
- case SNDRV_LSM_SET_SESSION_DATA:
- dev_dbg(rtd->dev,
- "%s: SNDRV_LSM_SET_SESSION_DATA\n",
- __func__);
- if (copy_from_user(&session_data, (void *)arg,
- sizeof(struct snd_lsm_session_data))) {
- err = -EFAULT;
- dev_err(rtd->dev,
- "%s: copy from user failed, size %zd\n",
- __func__, sizeof(struct snd_lsm_session_data));
- break;
- }
- if (!err)
- err = msm_lsm_ioctl_shared(substream,
- cmd, &session_data);
- if (err)
- dev_err(rtd->dev,
- "%s REG_SND_MODEL failed err %d\n",
- __func__, err);
- break;
case SNDRV_LSM_REG_SND_MODEL_V2: {
struct snd_lsm_sound_model_v2 snd_model_v2;
@@ -1436,11 +1409,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid params snd_model\n", __func__);
- return -EINVAL;
- }
if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
err = -EFAULT;
dev_err(rtd->dev,
@@ -1469,12 +1437,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
}
pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s, Invalid params\n",
- __func__, "SNDRV_LSM_SET_PARAMS");
- return -EINVAL;
- }
if (copy_from_user(&det_params, arg,
sizeof(det_params))) {
@@ -1507,13 +1469,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s: No Param data to set\n",
- __func__, "SET_MODULE_PARAMS");
- return -EINVAL;
- }
-
if (copy_from_user(&p_data, arg,
sizeof(p_data))) {
dev_err(rtd->dev,
@@ -1571,12 +1526,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
struct snd_lsm_event_status *user = NULL, userarg;
dev_dbg(rtd->dev,
"%s: SNDRV_LSM_EVENT_STATUS\n", __func__);
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid params event status\n",
- __func__);
- return -EINVAL;
- }
if (copy_from_user(&userarg, arg, sizeof(userarg))) {
dev_err(rtd->dev,
"%s: err copyuser event_status\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 7c8af09a8793..832d7c0170f4 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -579,7 +579,7 @@ static int msm_qti_pp_set_sec_auxpcm_lb_vol_mixer(
static int msm_qti_pp_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
+ char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL] = {0};
int i;
adm_get_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);