diff options
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); |
