summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/mdm-modem.txt8
-rw-r--r--Documentation/devicetree/bindings/pil/subsys-pil-tz.txt1
-rw-r--r--arch/arm/boot/Makefile2
-rw-r--r--arch/arm/boot/dts/qcom/external-mdm9640.dtsi52
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi5
-rw-r--r--arch/arm/configs/sdm660_defconfig6
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm64/configs/sdm660_defconfig6
-rw-r--r--drivers/char/adsprpc.c2
-rw-r--r--drivers/char/diag/diagfwd_glink.c15
-rw-r--r--drivers/char/diag/diagfwd_glink.h1
-rw-r--r--drivers/clk/clk.c55
-rw-r--r--drivers/esoc/esoc-mdm-4x.c278
-rw-r--r--drivers/esoc/esoc-mdm-drv.c44
-rw-r--r--drivers/esoc/esoc-mdm-pon.c84
-rw-r--r--drivers/esoc/esoc-mdm.h5
-rw-r--r--drivers/esoc/esoc.h16
-rw-r--r--drivers/esoc/esoc_bus.c2
-rw-r--r--drivers/esoc/esoc_dev.c8
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.c9
-rw-r--r--drivers/gpu/drm/msm/adreno/a4xx_gpu.c9
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c16
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c37
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h2
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c137
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h28
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c2
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c11
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c23
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c7
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h3
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h13
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c15
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c206
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c8
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h3
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c271
-rw-r--r--drivers/gpu/drm/msm/msm_mmu.h41
-rw-r--r--drivers/gpu/drm/msm/msm_prop.c67
-rw-r--r--drivers/gpu/drm/msm/msm_prop.h41
-rw-r--r--drivers/gpu/drm/msm/msm_smmu.c135
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c8
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c4
-rw-r--r--drivers/mmc/card/queue.c7
-rw-r--r--drivers/mmc/host/cmdq_hci.c15
-rw-r--r--drivers/pci/host/pci-msm.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c13
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c29
-rw-r--r--drivers/power/power_supply_sysfs.c4
-rw-r--r--drivers/power/supply/qcom/battery.c57
-rw-r--r--drivers/power/supply/qcom/battery.h17
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c98
-rw-r--r--drivers/power/supply/qcom/smb-lib.c131
-rw-r--r--drivers/power/supply/qcom/smb-lib.h9
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c76
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr.c29
-rw-r--r--drivers/soc/qcom/subsystem_restart.c74
-rw-r--r--drivers/usb/gadget/function/f_midi.c55
-rw-r--r--include/linux/ieee80211.h59
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/net/cfg80211.h155
-rw-r--r--include/soc/qcom/subsystem_restart.h3
-rw-r--r--include/trace/events/clk.h38
-rw-r--r--include/uapi/linux/esoc_ctrl.h3
-rw-r--r--include/uapi/linux/nl80211.h95
-rw-r--r--net/wireless/core.h20
-rw-r--r--net/wireless/mlme.c20
-rw-r--r--net/wireless/nl80211.c116
-rw-r--r--net/wireless/nl80211.h7
-rw-r--r--net/wireless/sme.c172
-rw-r--r--net/wireless/util.c12
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c19
-rw-r--r--sound/soc/msm/qdsp6v2/q6core.c30
77 files changed, 2198 insertions, 888 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
index a6537ebd2512..7d5e8a1c910a 100644
--- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
@@ -6,8 +6,8 @@ to be reset.
Required Properties:
- compatible: The bus devices need to be compatible with
- "qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom, ext-mdm9x45",
- "qcom,ext-mdm9x55".
+ "qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom,ext-mdm9x45",
+ "qcom,ext-mdm9x55", "qcom,ext-apq8096".
Required named gpio properties:
- qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor
@@ -110,6 +110,10 @@ Optional driver parameters:
on behalf of the subsystem driver.
- qcom,mdm-link-info: a string indicating additional info about the physical link.
For example: "devID_domain.bus.slot" in case of PCIe.
+- qcom,mdm-auto-boot: Boolean. To indicate this instance of esoc boots independently.
+- qcom,mdm-statusline-not-a-powersource: Boolean. If set, status line to esoc device is not a
+ power source.
+- qcom,mdm-userspace-handle-shutdown: Boolean. If set, userspace handles shutdown requests.
Example:
mdm0: qcom,mdm0 {
diff --git a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt
index d7edafc9a46b..4a69e03951b7 100644
--- a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt
+++ b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt
@@ -67,6 +67,7 @@ Optional properties:
- qcom,complete-ramdump: Boolean. If set, complete ramdump i.e. region between start address of
first segment to end address of last segment will be collected without
leaving any hole in between.
+- qcom,ignore-ssr-failure: Boolean. If set, SSR failures are not considered fatal.
Example:
qcom,venus@fdce0000 {
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 8849c2d20ac5..a5278293bd15 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -69,7 +69,7 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS) FORCE
$(call if_changed,cat)
- @echo ' Kernel: $@ is ready'
+ @$(kecho) ' Kernel: $@ is ready'
endif
diff --git a/arch/arm/boot/dts/qcom/external-mdm9640.dtsi b/arch/arm/boot/dts/qcom/external-mdm9640.dtsi
new file mode 100644
index 000000000000..4c0170a70bf5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/external-mdm9640.dtsi
@@ -0,0 +1,52 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ mdm0: qcom,mdm0 {
+ compatible = "qcom,ext-mdm9x45";
+ cell-index = <0>;
+ #address-cells = <0>;
+ interrupt-parent = <&mdm0>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-names =
+ "err_fatal_irq",
+ "status_irq";
+ status = "disabled";
+ };
+
+ mdm1: qcom,mdm1 {
+ compatible = "qcom,ext-mdm9x45";
+ cell-index = <0>;
+ #address-cells = <0>;
+ interrupt-parent = <&mdm1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-names =
+ "err_fatal_irq",
+ "status_irq";
+ status = "disabled";
+ };
+
+ mdm2: qcom,mdm2 {
+ compatible = "qcom,ext-mdm9x45";
+ cell-index = <0>;
+ #address-cells = <0>;
+ interrupt-parent = <&mdm2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-names =
+ "err_fatal_irq",
+ "status_irq";
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
index ecfff13f9355..da28e56bc2df 100644
--- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8998.dtsi
@@ -176,4 +176,16 @@
*/
iommus = <&mmss_smmu 42>;
};
+
+ iommu_coherent_test_device {
+ compatible = "iommu-debug-test";
+ /*
+ * 43 shouldn't be used by anyone on the mmss_smmu. We just
+ * need _something_ here to get this node recognized by the
+ * SMMU driver. Our test uses ATOS, which doesn't use SIDs
+ * anyways, so using a dummy value is ok.
+ */
+ iommus = <&mmss_smmu 43>;
+ dma-coherent;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index 220bad31d7f8..cdf4bede6eb3 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -585,6 +585,19 @@
bias-pull-down;
};
};
+
+ pcie0_wake_sleep: pcie0_wake_sleep {
+ mux {
+ pins = "gpio37";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio37";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
};
hph_en0_ctrl {
diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
index fc40da4023dc..be70f129e272 100644
--- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
@@ -411,7 +411,7 @@
rpm-regulator-ldoa24 {
status = "okay";
pm8998_l24: regulator-l24 {
- regulator-min-microvolt = <3088000>;
+ regulator-min-microvolt = <1848000>;
regulator-max-microvolt = <3088000>;
parent-supply = <&pm8998_l12>;
status = "okay";
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 9b5092cf7f14..c25f3ebcb113 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -2662,10 +2662,13 @@
0x800 0x00 0x00
0x808 0x03 0x00>;
- pinctrl-names = "default";
+ pinctrl-names = "default", "sleep";
pinctrl-0 = <&pcie0_clkreq_default
&pcie0_perst_default
&pcie0_wake_default>;
+ pinctrl-1 = <&pcie0_clkreq_default
+ &pcie0_perst_default
+ &pcie0_wake_sleep>;
perst-gpio = <&tlmm 35 0>;
wake-gpio = <&tlmm 37 0>;
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index 30a71904747f..bff4d8851203 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -3,6 +3,9 @@ CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -241,7 +244,7 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
CONFIG_QPNP_MISC=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
@@ -642,7 +645,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y
CONFIG_DEBUG_OBJECTS_WORK=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index 9a4841db89be..d293e1390e92 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -545,6 +545,7 @@ CONFIG_MSM_QMI_INTERFACE=y
CONFIG_MSM_RPM_SMD=y
CONFIG_QCOM_BUS_SCALING=y
CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_QCOM_DCC=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_SYSMON_GLINK_COMM=y
CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index 13ae21bdd562..3fe9e2bda6d2 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -4,6 +4,9 @@ CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -242,7 +245,7 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
-CONFIG_UID_CPUTIME=y
+CONFIG_UID_SYS_STATS=y
CONFIG_QPNP_MISC=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
@@ -653,7 +656,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y
CONFIG_DEBUG_OBJECTS_WORK=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
-CONFIG_SLUB_DEBUG_ON=y
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index c267d3b86237..7e44b38bbfca 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2792,7 +2792,7 @@ static int fastrpc_cb_probe(struct device *dev)
start = 0x60000000;
VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping =
arm_iommu_create_mapping(&platform_bus_type,
- start, 0x7fffffff)));
+ start, 0x70000000)));
if (err)
goto bail;
iommu_set_fault_handler(sess->smmu.mapping->domain,
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index 2784cf71cc2b..03d496c2dd91 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -487,6 +487,18 @@ static void diag_glink_remote_disconnect_work_fn(struct work_struct *work)
atomic_set(&glink_info->tx_intent_ready, 0);
}
+static void diag_glink_late_init_work_fn(struct work_struct *work)
+{
+ struct diag_glink_info *glink_info = container_of(work,
+ struct diag_glink_info,
+ late_init_work);
+ if (!glink_info || !glink_info->hdl)
+ return;
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d\n",
+ glink_info->peripheral, glink_info->type);
+ diagfwd_channel_open(glink_info->fwd_ctxt);
+}
+
static void diag_glink_transport_notify_state(void *handle, const void *priv,
unsigned event)
{
@@ -617,7 +629,7 @@ static void glink_late_init(struct diag_glink_info *glink_info)
glink_info->inited = 1;
if (atomic_read(&glink_info->opened))
- diagfwd_channel_open(glink_info->fwd_ctxt);
+ queue_work(glink_info->wq, &(glink_info->late_init_work));
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
glink_info->name);
@@ -665,6 +677,7 @@ static void __diag_glink_init(struct diag_glink_info *glink_info)
INIT_WORK(&(glink_info->connect_work), diag_glink_connect_work_fn);
INIT_WORK(&(glink_info->remote_disconnect_work),
diag_glink_remote_disconnect_work_fn);
+ INIT_WORK(&(glink_info->late_init_work), diag_glink_late_init_work_fn);
link_info.glink_link_state_notif_cb = diag_glink_notify_cb;
link_info.transport = NULL;
link_info.edge = glink_info->edge;
diff --git a/drivers/char/diag/diagfwd_glink.h b/drivers/char/diag/diagfwd_glink.h
index 5c1abeffd498..a84fa4edfca0 100644
--- a/drivers/char/diag/diagfwd_glink.h
+++ b/drivers/char/diag/diagfwd_glink.h
@@ -37,6 +37,7 @@ struct diag_glink_info {
struct work_struct read_work;
struct work_struct connect_work;
struct work_struct remote_disconnect_work;
+ struct work_struct late_init_work;
struct diagfwd_info *fwd_ctxt;
};
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 4a9e034f939f..4996f4f312f4 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2326,6 +2326,56 @@ static struct hlist_head *orphan_list[] = {
NULL,
};
+static void clk_state_subtree(struct clk_core *c)
+{
+ int vdd_level = 0;
+ struct clk_core *child;
+
+ if (!c)
+ return;
+
+ if (c->vdd_class) {
+ vdd_level = clk_find_vdd_level(c, c->rate);
+ if (vdd_level < 0)
+ vdd_level = 0;
+ }
+
+ trace_clk_state(c->name, c->prepare_count, c->enable_count,
+ c->rate, vdd_level);
+
+ hlist_for_each_entry(child, &c->children, child_node)
+ clk_state_subtree(child);
+}
+
+static int clk_state_show(struct seq_file *s, void *data)
+{
+ struct clk_core *c;
+ struct hlist_head **lists = (struct hlist_head **)s->private;
+
+ clk_prepare_lock();
+
+ for (; *lists; lists++)
+ hlist_for_each_entry(c, *lists, child_node)
+ clk_state_subtree(c);
+
+ clk_prepare_unlock();
+
+ return 0;
+}
+
+
+static int clk_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_state_show, inode->i_private);
+}
+
+static const struct file_operations clk_state_fops = {
+ .open = clk_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
int level)
{
@@ -3002,6 +3052,11 @@ static int __init clk_debug_init(void)
if (!d)
return -ENOMEM;
+ d = debugfs_create_file("trace_clocks", S_IRUGO, rootdir, &all_lists,
+ &clk_state_fops);
+ if (!d)
+ return -ENOMEM;
+
mutex_lock(&clk_debug_lock);
hlist_for_each_entry(core, &clk_debug_list, debug_node)
clk_debug_create_one(core, rootdir);
diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c
index 1e5f35d8422d..26f69fa61ba1 100644
--- a/drivers/esoc/esoc-mdm-4x.c
+++ b/drivers/esoc/esoc-mdm-4x.c
@@ -179,26 +179,48 @@ static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
struct device *dev = mdm->dev;
int ret;
bool graceful_shutdown = false;
+ u32 status, err_fatal;
switch (cmd) {
case ESOC_PWR_ON:
+ if (esoc->auto_boot) {
+ /*
+ * If esoc has already booted, we would have missed
+ * status change interrupt. Read status and err_fatal
+ * signals to arrive at the state of esoc.
+ */
+ esoc->clink_ops->get_status(&status, esoc);
+ esoc->clink_ops->get_err_fatal(&err_fatal, esoc);
+ if (err_fatal)
+ return -EIO;
+ if (status && !mdm->ready) {
+ mdm->ready = true;
+ esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
+ }
+ }
gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
- mdm_enable_irqs(mdm);
mdm->init = 1;
mdm_do_first_power_on(mdm);
+ mdm_enable_irqs(mdm);
break;
case ESOC_PWR_OFF:
mdm_disable_irqs(mdm);
mdm->debug = 0;
mdm->ready = false;
mdm->trig_cnt = 0;
+ if (esoc->primary)
+ break;
graceful_shutdown = true;
- ret = sysmon_send_shutdown(&esoc->subsys);
- if (ret) {
- dev_err(mdm->dev, "sysmon shutdown fail, ret = %d\n",
- ret);
- graceful_shutdown = false;
- goto force_poff;
+ if (!esoc->userspace_handle_shutdown) {
+ ret = sysmon_send_shutdown(&esoc->subsys);
+ if (ret) {
+ dev_err(mdm->dev,
+ "sysmon shutdown fail, ret = %d\n", ret);
+ graceful_shutdown = false;
+ goto force_poff;
+ }
+ } else {
+ esoc_clink_queue_request(ESOC_REQ_SEND_SHUTDOWN, esoc);
}
dev_dbg(mdm->dev, "Waiting for status gpio go low\n");
status_down = false;
@@ -228,12 +250,17 @@ force_poff:
esoc->subsys.sysmon_shutdown_ret);
}
+ if (esoc->primary)
+ break;
/*
* Force a shutdown of the mdm. This is required in order
* to prevent the mdm from immediately powering back on
- * after the shutdown
+ * after the shutdown. Avoid setting status to 0, if line is
+ * monitored by multiple mdms(might be wrongly interpreted as
+ * a primary crash).
*/
- gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
+ if (esoc->statusline_not_a_powersource == false)
+ gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc);
mdm_power_down(mdm);
mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG);
@@ -249,9 +276,12 @@ force_poff:
*/
mdm->ready = false;
cancel_delayed_work(&mdm->mdm2ap_status_check_work);
- gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
- dev_dbg(mdm->dev, "set ap2mdm errfatal to force reset\n");
- msleep(mdm->ramdump_delay_ms);
+ if (!mdm->esoc->auto_boot) {
+ gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
+ dev_dbg(mdm->dev,
+ "set ap2mdm errfatal to force reset\n");
+ msleep(mdm->ramdump_delay_ms);
+ }
break;
case ESOC_EXE_DEBUG:
mdm->debug = 1;
@@ -378,6 +408,8 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc)
status_down = false;
dev_dbg(dev, "signal apq err fatal for graceful restart\n");
gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
+ if (esoc->primary)
+ break;
timeout = local_clock();
do_div(timeout, NSEC_PER_MSEC);
timeout += MDM_MODEM_TIMEOUT;
@@ -420,7 +452,8 @@ static irqreturn_t mdm_errfatal(int irq, void *dev_id)
goto mdm_pwroff_irq;
esoc = mdm->esoc;
dev_err(dev, "%s: mdm sent errfatal interrupt\n",
- __func__);
+ __func__);
+ subsys_set_crash_status(esoc->subsys_dev, true);
/* disable irq ?*/
esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc);
return IRQ_HANDLED;
@@ -441,11 +474,26 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
return IRQ_HANDLED;
dev = mdm->dev;
esoc = mdm->esoc;
+ /*
+ * On auto boot devices, there is a possibility of receiving
+ * status change interrupt before esoc_clink structure is
+ * initialized. Ignore them.
+ */
+ if (!esoc)
+ return IRQ_HANDLED;
value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS));
if (value == 0 && mdm->ready) {
dev_err(dev, "unexpected reset external modem\n");
+ subsys_set_crash_status(esoc->subsys_dev, true);
esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc);
} else if (value == 1) {
+ /*
+ * In auto_boot cases, bailout early if mdm
+ * is up already.
+ */
+ if (esoc->auto_boot && mdm->ready)
+ return IRQ_HANDLED;
+
cancel_delayed_work(&mdm->mdm2ap_status_check_work);
dev_dbg(dev, "status = 1: mdm is now ready\n");
mdm->ready = true;
@@ -453,6 +501,8 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
queue_work(mdm->mdm_queue, &mdm->mdm_status_work);
if (mdm->get_restart_reason)
queue_work(mdm->mdm_queue, &mdm->restart_reason_work);
+ if (esoc->auto_boot)
+ esoc->clink_ops->notify(ESOC_BOOT_DONE, esoc);
}
return IRQ_HANDLED;
}
@@ -481,7 +531,7 @@ static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int mdm_get_status(u32 *status, struct esoc_clink *esoc)
+static void mdm_get_status(u32 *status, struct esoc_clink *esoc)
{
struct mdm_ctrl *mdm = get_esoc_clink_data(esoc);
@@ -489,7 +539,16 @@ static int mdm_get_status(u32 *status, struct esoc_clink *esoc)
*status = 0;
else
*status = 1;
- return 0;
+}
+
+static void mdm_get_err_fatal(u32 *status, struct esoc_clink *esoc)
+{
+ struct mdm_ctrl *mdm = get_esoc_clink_data(esoc);
+
+ if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)) == 0)
+ *status = 0;
+ else
+ *status = 1;
}
static void mdm_configure_debug(struct mdm_ctrl *mdm)
@@ -573,13 +632,21 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
&mdm->ramdump_delay_ms);
if (ret)
mdm->ramdump_delay_ms = DEF_RAMDUMP_DELAY;
- /* Multilple gpio_request calls are allowed */
+ /*
+ * In certain scenarios, multiple esoc devices are monitoring
+ * same AP2MDM_STATUS line. But only one of them will have a
+ * successful gpio_request call. Initialize gpio only if request
+ * succeeds.
+ */
if (gpio_request(MDM_GPIO(mdm, AP2MDM_STATUS), "AP2MDM_STATUS"))
dev_err(dev, "Failed to configure AP2MDM_STATUS gpio\n");
- /* Multilple gpio_request calls are allowed */
+ else
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
if (gpio_request(MDM_GPIO(mdm, AP2MDM_ERRFATAL), "AP2MDM_ERRFATAL"))
dev_err(dev, "%s Failed to configure AP2MDM_ERRFATAL gpio\n",
__func__);
+ else
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
if (gpio_request(MDM_GPIO(mdm, MDM2AP_STATUS), "MDM2AP_STATUS")) {
dev_err(dev, "%s Failed to configure MDM2AP_STATUS gpio\n",
__func__);
@@ -612,9 +679,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
}
}
- gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
- gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
-
if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY)))
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_CHNLRDY), 0);
@@ -748,6 +812,7 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
dev_err(mdm->dev, "cannot allocate esoc device\n");
return PTR_ERR(esoc);
}
+ esoc->pdev = pdev;
mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
if (!mdm->mdm_queue) {
dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -818,6 +883,7 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
dev_err(mdm->dev, "cannot allocate esoc device\n");
return PTR_ERR(esoc);
}
+ esoc->pdev = pdev;
mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
if (!mdm->mdm_queue) {
dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -888,6 +954,84 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
return 0;
}
+static int mdm9x45_setup_hw(struct mdm_ctrl *mdm,
+ const struct mdm_ops *ops,
+ struct platform_device *pdev)
+{
+ int ret;
+ struct esoc_clink *esoc;
+ const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
+ const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+ mdm->dev = &pdev->dev;
+ mdm->pon_ops = pon_ops;
+ esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(esoc)) {
+ dev_err(mdm->dev, "cannot allocate esoc device\n");
+ return PTR_ERR(esoc);
+ }
+ esoc->pdev = pdev;
+ mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+ if (!mdm->mdm_queue) {
+ dev_err(mdm->dev, "could not create mdm_queue\n");
+ return -ENOMEM;
+ }
+ mdm->irq_mask = 0;
+ mdm->ready = false;
+ ret = mdm_dt_parse_gpios(mdm);
+ if (ret)
+ return ret;
+ dev_err(mdm->dev, "parsing gpio done\n");
+ ret = mdm_pon_dt_init(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "pon dt init done\n");
+ ret = mdm_pinctrl_init(mdm);
+ if (ret)
+ return ret;
+ dev_err(mdm->dev, "pinctrl init done\n");
+ ret = mdm_pon_setup(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "pon setup done\n");
+ ret = mdm_configure_ipc(mdm, pdev);
+ if (ret)
+ return ret;
+ mdm_configure_debug(mdm);
+ dev_err(mdm->dev, "ipc configure done\n");
+ esoc->name = MDM9x45_LABEL;
+ esoc->link_name = MDM9x45_PCIE;
+ esoc->clink_ops = clink_ops;
+ esoc->parent = mdm->dev;
+ esoc->owner = THIS_MODULE;
+ esoc->np = pdev->dev.of_node;
+
+ esoc->auto_boot = of_property_read_bool(esoc->np,
+ "qcom,mdm-auto-boot");
+ esoc->statusline_not_a_powersource = of_property_read_bool(esoc->np,
+ "qcom,mdm-statusline-not-a-powersource");
+ esoc->userspace_handle_shutdown = of_property_read_bool(esoc->np,
+ "qcom,mdm-userspace-handle-shutdown");
+ set_esoc_clink_data(esoc, mdm);
+ ret = esoc_clink_register(esoc);
+ if (ret) {
+ dev_err(mdm->dev, "esoc registration failed\n");
+ return ret;
+ }
+ dev_dbg(mdm->dev, "esoc registration done\n");
+ init_completion(&mdm->debug_done);
+ INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+ INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+ INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+ mdm->get_restart_reason = false;
+ mdm->debug_fail = false;
+ mdm->esoc = esoc;
+ mdm->init = 0;
+ if (esoc->auto_boot)
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
+ return 0;
+}
+
static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
const struct mdm_ops *ops,
struct platform_device *pdev)
@@ -906,6 +1050,7 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
dev_err(mdm->dev, "cannot allocate esoc device\n");
return PTR_ERR(esoc);
}
+ esoc->pdev = pdev;
mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
if (!mdm->mdm_queue) {
dev_err(mdm->dev, "could not create mdm_queue\n");
@@ -963,9 +1108,86 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
return 0;
}
+static int apq8096_setup_hw(struct mdm_ctrl *mdm,
+ const struct mdm_ops *ops,
+ struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *node;
+ struct esoc_clink *esoc;
+ const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
+ const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+ mdm->dev = &pdev->dev;
+ mdm->pon_ops = pon_ops;
+ node = pdev->dev.of_node;
+ esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(esoc)) {
+ dev_err(mdm->dev, "cannot allocate esoc device\n");
+ return PTR_ERR(esoc);
+ }
+ esoc->pdev = pdev;
+ mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+ if (!mdm->mdm_queue) {
+ dev_err(mdm->dev, "could not create mdm_queue\n");
+ return -ENOMEM;
+ }
+ mdm->irq_mask = 0;
+ mdm->ready = false;
+ ret = mdm_dt_parse_gpios(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "parsing gpio done\n");
+ ret = mdm_pon_dt_init(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "pon dt init done\n");
+ ret = mdm_pinctrl_init(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "pinctrl init done\n");
+ ret = mdm_pon_setup(mdm);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "pon setup done\n");
+ ret = mdm_configure_ipc(mdm, pdev);
+ if (ret)
+ return ret;
+ dev_dbg(mdm->dev, "ipc configure done\n");
+ esoc->name = APQ8096_LABEL;
+ esoc->link_name = APQ8096_PCIE;
+ esoc->clink_ops = clink_ops;
+ esoc->parent = mdm->dev;
+ esoc->owner = THIS_MODULE;
+ esoc->np = pdev->dev.of_node;
+ esoc->auto_boot = of_property_read_bool(esoc->np,
+ "qcom,mdm-auto-boot");
+ esoc->primary = of_property_read_bool(esoc->np,
+ "qcom,mdm-primary");
+ set_esoc_clink_data(esoc, mdm);
+ ret = esoc_clink_register(esoc);
+ if (ret) {
+ dev_err(mdm->dev, "esoc registration failed\n");
+ return ret;
+ }
+ dev_dbg(mdm->dev, "esoc registration done\n");
+ init_completion(&mdm->debug_done);
+ INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+ INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+ INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+ mdm->get_restart_reason = false;
+ mdm->debug_fail = false;
+ mdm->esoc = esoc;
+ mdm->init = 0;
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
+ return 0;
+}
+
static struct esoc_clink_ops mdm_cops = {
.cmd_exe = mdm_cmd_exe,
.get_status = mdm_get_status,
+ .get_err_fatal = mdm_get_err_fatal,
.notify = mdm_notify,
};
@@ -981,6 +1203,18 @@ static struct mdm_ops mdm9x35_ops = {
.pon_ops = &mdm9x35_pon_ops,
};
+static struct mdm_ops mdm9x45_ops = {
+ .clink_ops = &mdm_cops,
+ .config_hw = mdm9x45_setup_hw,
+ .pon_ops = &mdm9x45_pon_ops,
+};
+
+static struct mdm_ops apq8096_ops = {
+ .clink_ops = &mdm_cops,
+ .config_hw = apq8096_setup_hw,
+ .pon_ops = &apq8096_pon_ops,
+};
+
static struct mdm_ops mdm9x55_ops = {
.clink_ops = &mdm_cops,
.config_hw = mdm9x55_setup_hw,
@@ -992,8 +1226,12 @@ static const struct of_device_id mdm_dt_match[] = {
.data = &mdm9x25_ops, },
{ .compatible = "qcom,ext-mdm9x35",
.data = &mdm9x35_ops, },
+ { .compatible = "qcom,ext-mdm9x45",
+ .data = &mdm9x45_ops, },
{ .compatible = "qcom,ext-mdm9x55",
.data = &mdm9x55_ops, },
+ { .compatible = "qcom,ext-apq8096",
+ .data = &apq8096_ops, },
{},
};
MODULE_DEVICE_TABLE(of, mdm_dt_match);
diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c
index 8697428eceb2..9c2c68dfef65 100644
--- a/drivers/esoc/esoc-mdm-drv.c
+++ b/drivers/esoc/esoc-mdm-drv.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/reboot.h>
+#include <linux/of.h>
#include "esoc.h"
#include "mdm-dbg.h"
@@ -72,7 +73,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
break;
case ESOC_UNEXPECTED_RESET:
case ESOC_ERR_FATAL:
- if (mdm_drv->mode == CRASH)
+ /*
+ * Modem can crash while we are waiting for boot_done during
+ * a subsystem_get(). Setting mode to CRASH will prevent a
+ * subsequent subsystem_get() from entering poweron ops. Avoid
+ * this by seting mode to CRASH only if device was up and
+ * running.
+ */
+ if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN)
return;
mdm_drv->mode = CRASH;
queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work);
@@ -161,8 +169,9 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
subsys);
struct mdm_drv *mdm_drv = esoc_get_drv_data(esoc_clink);
const struct esoc_clink_ops const *clink_ops = esoc_clink->clink_ops;
+ int timeout = INT_MAX;
- if (!esoc_req_eng_enabled(esoc_clink)) {
+ if (!esoc_clink->auto_boot && !esoc_req_eng_enabled(esoc_clink)) {
dev_dbg(&esoc_clink->dev, "Wait for req eng registration\n");
wait_for_completion(&mdm_drv->req_eng_wait);
}
@@ -187,8 +196,17 @@ static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
return ret;
}
}
- wait_for_completion(&mdm_drv->boot_done);
- if (mdm_drv->boot_fail) {
+
+ /*
+ * In autoboot case, it is possible that we can forever wait for
+ * boot completion, when esoc fails to boot. This is because there
+ * is no helper application which can alert esoc driver about boot
+ * failure. Prevent going to wait forever in such case.
+ */
+ if (esoc_clink->auto_boot)
+ timeout = 10 * HZ;
+ ret = wait_for_completion_timeout(&mdm_drv->boot_done, timeout);
+ if (mdm_drv->boot_fail || ret <= 0) {
dev_err(&esoc_clink->dev, "booting failed\n");
return -EIO;
}
@@ -216,10 +234,12 @@ static int mdm_subsys_ramdumps(int want_dumps,
static int mdm_register_ssr(struct esoc_clink *esoc_clink)
{
- esoc_clink->subsys.shutdown = mdm_subsys_shutdown;
- esoc_clink->subsys.ramdump = mdm_subsys_ramdumps;
- esoc_clink->subsys.powerup = mdm_subsys_powerup;
- esoc_clink->subsys.crash_shutdown = mdm_crash_shutdown;
+ struct subsys_desc *subsys = &esoc_clink->subsys;
+
+ subsys->shutdown = mdm_subsys_shutdown;
+ subsys->ramdump = mdm_subsys_ramdumps;
+ subsys->powerup = mdm_subsys_powerup;
+ subsys->crash_shutdown = mdm_crash_shutdown;
return esoc_clink_register_ssr(esoc_clink);
}
@@ -286,6 +306,14 @@ static struct esoc_compat compat_table[] = {
.name = "MDM9x55",
.data = NULL,
},
+ {
+ .name = "MDM9x45",
+ .data = NULL,
+ },
+ {
+ .name = "APQ8096",
+ .data = NULL,
+ },
};
static struct esoc_drv esoc_ssr_drv = {
diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c
index acda06485364..4ae3b7520f77 100644
--- a/drivers/esoc/esoc-mdm-pon.c
+++ b/drivers/esoc/esoc-mdm-pon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -60,6 +60,29 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
return 0;
}
+/* This function can be called from atomic context. */
+static int mdm9x45_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+ int soft_reset_direction_assert = 0,
+ soft_reset_direction_de_assert = 1;
+
+ if (mdm->soft_reset_inverted) {
+ soft_reset_direction_assert = 1;
+ soft_reset_direction_de_assert = 0;
+ }
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction_assert);
+ /*
+ * Allow PS hold assert to be detected
+ */
+ if (!atomic)
+ usleep_range(1000000, 1005000);
+ else
+ mdelay(1000);
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction_de_assert);
+ return 0;
+}
static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
{
@@ -68,6 +91,9 @@ static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
struct device *dev = mdm->dev;
dev_dbg(dev, "Powering on modem for the first time\n");
+ if (mdm->esoc->auto_boot)
+ return 0;
+
mdm_toggle_soft_reset(mdm, false);
/* Add a delay to allow PON sequence to complete*/
msleep(50);
@@ -132,8 +158,31 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm)
return 0;
}
+static int mdm9x45_power_down(struct mdm_ctrl *mdm)
+{
+ int soft_reset_direction_assert = 0,
+ soft_reset_direction_de_assert = 1;
+
+ if (mdm->soft_reset_inverted) {
+ soft_reset_direction_assert = 1;
+ soft_reset_direction_de_assert = 0;
+ }
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction_assert);
+ /*
+ * Allow PS hold assert to be detected
+ */
+ msleep(3003);
+ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+ soft_reset_direction_de_assert);
+ return 0;
+}
+
static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
{
+ if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
+ return;
+
dev_dbg(mdm->dev, "Triggering mdm cold reset");
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
!!mdm->soft_reset_inverted);
@@ -152,6 +201,11 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
!mdm->soft_reset_inverted);
}
+static int apq8096_pon_dt_init(struct mdm_ctrl *mdm)
+{
+ return 0;
+}
+
static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
{
int val;
@@ -183,6 +237,21 @@ static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
return 0;
}
+/* This function can be called from atomic context. */
+static int apq8096_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+ return 0;
+}
+
+static int apq8096_power_down(struct mdm_ctrl *mdm)
+{
+ return 0;
+}
+
+static void apq8096_cold_reset(struct mdm_ctrl *mdm)
+{
+}
+
struct mdm_pon_ops mdm9x25_pon_ops = {
.pon = mdm4x_do_first_power_on,
.soft_reset = mdm4x_toggle_soft_reset,
@@ -203,8 +272,8 @@ struct mdm_pon_ops mdm9x35_pon_ops = {
struct mdm_pon_ops mdm9x45_pon_ops = {
.pon = mdm4x_do_first_power_on,
- .soft_reset = mdm4x_toggle_soft_reset,
- .poff_force = mdm4x_power_down,
+ .soft_reset = mdm9x45_toggle_soft_reset,
+ .poff_force = mdm9x45_power_down,
.cold_reset = mdm4x_cold_reset,
.dt_init = mdm4x_pon_dt_init,
.setup = mdm4x_pon_setup,
@@ -218,3 +287,12 @@ struct mdm_pon_ops mdm9x55_pon_ops = {
.dt_init = mdm4x_pon_dt_init,
.setup = mdm4x_pon_setup,
};
+
+struct mdm_pon_ops apq8096_pon_ops = {
+ .pon = mdm4x_do_first_power_on,
+ .soft_reset = apq8096_toggle_soft_reset,
+ .poff_force = apq8096_power_down,
+ .cold_reset = apq8096_cold_reset,
+ .dt_init = apq8096_pon_dt_init,
+ .setup = mdm4x_pon_setup,
+};
diff --git a/drivers/esoc/esoc-mdm.h b/drivers/esoc/esoc-mdm.h
index ac811720b035..9343e49559f2 100644
--- a/drivers/esoc/esoc-mdm.h
+++ b/drivers/esoc/esoc-mdm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,8 @@
#define MDM9x45_PCIE "PCIe"
#define MDM9x55_LABEL "MDM9x55"
#define MDM9x55_PCIE "PCIe"
+#define APQ8096_LABEL "APQ8096"
+#define APQ8096_PCIE "PCIe"
#define MDM2AP_STATUS_TIMEOUT_MS 120000L
#define MDM_MODEM_TIMEOUT 3000
#define DEF_RAMDUMP_TIMEOUT 120000
@@ -153,4 +155,5 @@ extern struct mdm_pon_ops mdm9x25_pon_ops;
extern struct mdm_pon_ops mdm9x35_pon_ops;
extern struct mdm_pon_ops mdm9x45_pon_ops;
extern struct mdm_pon_ops mdm9x55_pon_ops;
+extern struct mdm_pon_ops apq8096_pon_ops;
#endif
diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h
index 755fb24bd60a..ee54908ce486 100644
--- a/drivers/esoc/esoc.h
+++ b/drivers/esoc/esoc.h
@@ -49,6 +49,7 @@ struct esoc_eng {
* @link_info: additional info about the physical link.
* @parent: parent device.
* @dev: device for userspace interface.
+ * @pdev: platform device to interface with SSR driver.
* @id: id of the external device.
* @owner: owner of the device.
* @clink_ops: control operations for the control link
@@ -59,6 +60,12 @@ struct esoc_eng {
* @subsys_desc: descriptor for subsystem restart
* @subsys_dev: ssr device handle.
* @np: device tree node for esoc_clink.
+ * @auto_boot: boots independently.
+ * @primary: primary esoc controls(reset/poweroff) all secondary
+ * esocs, but not otherway around.
+ * @statusline_not_a_powersource: True if status line to esoc is not a
+ * power source.
+ * @userspace_handle_shutdown: True if user space handles shutdown requests.
*/
struct esoc_clink {
const char *name;
@@ -66,6 +73,7 @@ struct esoc_clink {
const char *link_info;
struct device *parent;
struct device dev;
+ struct platform_device *pdev;
unsigned int id;
struct module *owner;
const struct esoc_clink_ops const *clink_ops;
@@ -77,17 +85,23 @@ struct esoc_clink {
struct subsys_desc subsys;
struct subsys_device *subsys_dev;
struct device_node *np;
+ bool auto_boot;
+ bool primary;
+ bool statusline_not_a_powersource;
+ bool userspace_handle_shutdown;
};
/**
* struct esoc_clink_ops: Operations to control external soc
* @cmd_exe: Execute control command
* @get_status: Get current status, or response to previous command
+ * @get_err_fatal: Get status of err fatal signal
* @notify_esoc: notify external soc of events
*/
struct esoc_clink_ops {
int (*cmd_exe)(enum esoc_cmd cmd, struct esoc_clink *dev);
- int (*get_status)(u32 *status, struct esoc_clink *dev);
+ void (*get_status)(u32 *status, struct esoc_clink *dev);
+ void (*get_err_fatal)(u32 *status, struct esoc_clink *dev);
void (*notify)(enum esoc_notify notify, struct esoc_clink *dev);
};
diff --git a/drivers/esoc/esoc_bus.c b/drivers/esoc/esoc_bus.c
index f925607511ba..94f52764c8c3 100644
--- a/drivers/esoc/esoc_bus.c
+++ b/drivers/esoc/esoc_bus.c
@@ -189,7 +189,7 @@ int esoc_clink_register_ssr(struct esoc_clink *esoc_clink)
snprintf(subsys_name, len, "esoc%d", esoc_clink->id);
esoc_clink->subsys.name = subsys_name;
esoc_clink->dev.of_node = esoc_clink->np;
- esoc_clink->subsys.dev = &esoc_clink->dev;
+ esoc_clink->subsys.dev = &esoc_clink->pdev->dev;
esoc_clink->subsys_dev = subsys_register(&esoc_clink->subsys);
if (IS_ERR_OR_NULL(esoc_clink->subsys_dev)) {
dev_err(&esoc_clink->dev, "failed to register ssr node\n");
diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c
index bbe1d24fb1f6..a1e7a52a8c26 100644
--- a/drivers/esoc/esoc_dev.c
+++ b/drivers/esoc/esoc_dev.c
@@ -224,9 +224,11 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
clink_ops->notify(esoc_cmd, esoc_clink);
break;
case ESOC_GET_STATUS:
- err = clink_ops->get_status(&status, esoc_clink);
- if (err)
- return err;
+ clink_ops->get_status(&status, esoc_clink);
+ put_user(status, (unsigned int __user *)uarg);
+ break;
+ case ESOC_GET_ERR_FATAL:
+ clink_ops->get_err_fatal(&status, esoc_clink);
put_user(status, (unsigned int __user *)uarg);
break;
case ESOC_WAIT_FOR_CRASH:
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index c4f886fd6037..a417e42944fc 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -466,6 +466,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
struct msm_gpu *gpu;
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
+ struct msm_gpu_config a3xx_config = { 0 };
int ret;
if (!pdev) {
@@ -491,7 +492,13 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
adreno_gpu->registers = a3xx_registers;
adreno_gpu->reg_offsets = a3xx_register_offsets;
- ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+ a3xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+ a3xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+ a3xx_config.nr_rings = 1;
+ a3xx_config.va_start = 0x300000;
+ a3xx_config.va_end = 0xffffffff;
+
+ ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a3xx_config);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
index 534a7c3fbdca..069823f054f7 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
@@ -543,6 +543,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
struct msm_gpu *gpu;
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
+ struct msm_gpu_config a4xx_config = { 0 };
int ret;
if (!pdev) {
@@ -568,7 +569,13 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
adreno_gpu->registers = a4xx_registers;
adreno_gpu->reg_offsets = a4xx_register_offsets;
- ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
+ a4xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+ a4xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+ a4xx_config.nr_rings = 1;
+ a4xx_config.va_start = 0x300000;
+ a4xx_config.va_end = 0xffffffff;
+
+ ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a4xx_config);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 9ceef8f437b5..98679e9bbea4 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1368,6 +1368,7 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
struct a5xx_gpu *a5xx_gpu = NULL;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
+ struct msm_gpu_config a5xx_config = { 0 };
int ret;
if (!pdev) {
@@ -1391,7 +1392,20 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
/* Check the efuses for some configuration */
a5xx_efuses_read(pdev, adreno_gpu);
- ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4);
+ a5xx_config.ioname = MSM_GPU_DEFAULT_IONAME;
+ a5xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME;
+
+ /* Set the number of rings to 4 - yay preemption */
+ a5xx_config.nr_rings = 4;
+
+ /*
+ * Set the user domain range to fall into the TTBR1 region for global
+ * objects
+ */
+ a5xx_config.va_start = 0x800000000;
+ a5xx_config.va_end = 0x8ffffffff;
+
+ ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a5xx_config);
if (ret) {
a5xx_destroy(&(a5xx_gpu->base.base));
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 19267b2a3b49..9952fa8dcda5 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -405,10 +405,6 @@ void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords)
ring->gpu->name, ring->id);
}
-static const char *iommu_ports[] = {
- "gfx3d_user",
-};
-
/* Read the set of powerlevels */
static int _adreno_get_pwrlevels(struct msm_gpu *gpu, struct device_node *node)
{
@@ -524,10 +520,10 @@ static int adreno_of_parse(struct platform_device *pdev, struct msm_gpu *gpu)
int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct adreno_gpu *adreno_gpu,
- const struct adreno_gpu_funcs *funcs, int nr_rings)
+ const struct adreno_gpu_funcs *funcs,
+ struct msm_gpu_config *gpu_config)
{
struct adreno_platform_config *config = pdev->dev.platform_data;
- struct msm_gpu_config adreno_gpu_config = { 0 };
struct msm_gpu *gpu = &adreno_gpu->base;
struct msm_mmu *mmu;
int ret;
@@ -541,26 +537,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
/* Get the rest of the target configuration from the device tree */
adreno_of_parse(pdev, gpu);
- adreno_gpu_config.ioname = "kgsl_3d0_reg_memory";
- adreno_gpu_config.irqname = "kgsl_3d0_irq";
- adreno_gpu_config.nr_rings = nr_rings;
-
- adreno_gpu_config.va_start = SZ_16M;
- adreno_gpu_config.va_end = 0xffffffff;
-
- if (adreno_gpu->revn >= 500) {
- /* 5XX targets use a 64 bit region */
- adreno_gpu_config.va_start = 0x800000000;
- adreno_gpu_config.va_end = 0x8ffffffff;
- } else {
- adreno_gpu_config.va_start = 0x300000;
- adreno_gpu_config.va_end = 0xffffffff;
- }
-
- adreno_gpu_config.nr_rings = nr_rings;
-
ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
- adreno_gpu->info->name, &adreno_gpu_config);
+ adreno_gpu->info->name, gpu_config);
if (ret)
return ret;
@@ -580,8 +558,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
mmu = gpu->aspace->mmu;
if (mmu) {
- ret = mmu->funcs->attach(mmu, iommu_ports,
- ARRAY_SIZE(iommu_ports));
+ ret = mmu->funcs->attach(mmu, NULL, 0);
if (ret)
return ret;
}
@@ -722,7 +699,7 @@ static struct adreno_counter_group *get_counter_group(struct msm_gpu *gpu,
return ERR_PTR(-ENODEV);
if (groupid >= adreno_gpu->nr_counter_groups)
- return ERR_PTR(-EINVAL);
+ return ERR_PTR(-ENODEV);
return (struct adreno_counter_group *)
adreno_gpu->counter_groups[groupid];
@@ -745,7 +722,7 @@ u64 adreno_read_counter(struct msm_gpu *gpu, u32 groupid, int counterid)
struct adreno_counter_group *group =
get_counter_group(gpu, groupid);
- if (!IS_ERR(group) && group->funcs.read)
+ if (!IS_ERR_OR_NULL(group) && group->funcs.read)
return group->funcs.read(gpu, group, counterid);
return 0;
@@ -756,6 +733,6 @@ void adreno_put_counter(struct msm_gpu *gpu, u32 groupid, int counterid)
struct adreno_counter_group *group =
get_counter_group(gpu, groupid);
- if (!IS_ERR(group) && group->funcs.put)
+ if (!IS_ERR_OR_NULL(group) && group->funcs.put)
group->funcs.put(gpu, group, counterid);
}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 8e8f3e5182d6..3f9bc655c383 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -257,7 +257,7 @@ struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu);
int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
- int nr_rings);
+ struct msm_gpu_config *config);
void adreno_gpu_cleanup(struct adreno_gpu *gpu);
void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot);
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 6a6d02c5444d..1ff3ee2bdca6 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -401,12 +401,111 @@ static const struct file_operations edid_vendor_name_fops = {
.read = _sde_hdmi_edid_vendor_name_read,
};
+static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in)
+{
+ u32 pclk_delta, pclk;
+ u64 pclk_clip = pclk_in;
+
+ /* as per standard, 0.5% of deviation is allowed */
+ pclk = mode->clock * HDMI_KHZ_TO_HZ;
+ pclk_delta = pclk * 5 / 1000;
+
+ if (pclk_in < (pclk - pclk_delta))
+ pclk_clip = pclk - pclk_delta;
+ else if (pclk_in > (pclk + pclk_delta))
+ pclk_clip = pclk + pclk_delta;
+
+ if (pclk_in != pclk_clip)
+ pr_warn("clip pclk from %lld to %lld\n", pclk_in, pclk_clip);
+
+ return pclk_clip;
+}
+
+/**
+ * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm
+ *
+ * @ppm: ppm is parts per million multiplied by 1000.
+ * return: 0 on success, non-zero in case of failure.
+ *
+ * The input ppm will be clipped if it's more than or less than 5% of the TMDS
+ * clock rate defined by HDMI spec.
+ */
+static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm)
+{
+ struct hdmi *hdmi = display->ctrl.ctrl;
+ struct drm_display_mode *current_mode = &display->mode;
+ u64 cur_pclk, dst_pclk;
+ u64 clip_pclk;
+ int rc = 0;
+
+ if (!hdmi->power_on || !display->connected) {
+ SDE_ERROR("HDMI display is not ready\n");
+ return -EINVAL;
+ }
+
+ /* get current pclk */
+ cur_pclk = hdmi->pixclock;
+ /* get desired pclk */
+ dst_pclk = cur_pclk * (1000000000 + ppm);
+ do_div(dst_pclk, 1000000000);
+
+ clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk);
+
+ /* update pclk */
+ if (clip_pclk != cur_pclk) {
+ SDE_DEBUG("PCLK changes from %llu to %llu when delta is %d\n",
+ cur_pclk, clip_pclk, ppm);
+
+ rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk);
+ if (rc < 0) {
+ SDE_ERROR("PLL update failed, reset clock rate\n");
+ return rc;
+ }
+
+ hdmi->pixclock = clip_pclk;
+ }
+
+ return rc;
+}
+
+static ssize_t _sde_hdmi_debugfs_pll_delta_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[10];
+ int ppm = 0;
+
+ if (!display)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ if (kstrtoint(buf, 0, &ppm))
+ return -EFAULT;
+
+ if (ppm)
+ _sde_hdmi_update_pll_delta(display, ppm);
+
+ return count;
+}
+
+static const struct file_operations pll_delta_fops = {
+ .open = simple_open,
+ .write = _sde_hdmi_debugfs_pll_delta_write,
+};
+
static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
{
int rc = 0;
struct dentry *dir, *dump_file, *edid_modes;
struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info;
- struct dentry *edid_vcdb_info, *edid_vendor_name;
+ struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file;
dir = debugfs_create_dir(display->name, NULL);
if (!dir) {
@@ -423,7 +522,19 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
&dump_info_fops);
if (IS_ERR_OR_NULL(dump_file)) {
rc = PTR_ERR(dump_file);
- SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ SDE_ERROR("[%s]debugfs create dump_info file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ pll_file = debugfs_create_file("pll_delta",
+ 0644,
+ dir,
+ display,
+ &pll_delta_fops);
+ if (IS_ERR_OR_NULL(pll_file)) {
+ rc = PTR_ERR(pll_file);
+ SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n",
display->name, rc);
goto error_remove_dir;
}
@@ -1324,6 +1435,28 @@ int sde_hdmi_get_info(struct msm_display_info *info,
return rc;
}
+int sde_hdmi_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ int property_index,
+ uint64_t value,
+ void *display)
+{
+ int rc = 0;
+
+ if (!connector || !display) {
+ SDE_ERROR("connector=%pK or display=%pK is NULL\n",
+ connector, display);
+ return 0;
+ }
+
+ SDE_DEBUG("\n");
+
+ if (property_index == CONNECTOR_PROP_PLL_DELTA)
+ rc = _sde_hdmi_update_pll_delta(display, value);
+
+ return rc;
+}
+
u32 sde_hdmi_get_num_of_displays(void)
{
u32 count = 0;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index bb3061a6ed00..ecdace10d0c3 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -80,6 +80,7 @@ struct sde_hdmi_ctrl {
* @non_pluggable: If HDMI display is non pluggable
* @num_of_modes: Number of modes supported by display if non pluggable.
* @mode_list: Mode list if non pluggable.
+ * @mode: Current display mode.
* @connected: If HDMI display is connected.
* @is_tpg_enabled: TPG state.
* @hpd_work: HPD work structure.
@@ -103,6 +104,7 @@ struct sde_hdmi {
bool non_pluggable;
u32 num_of_modes;
struct list_head mode_list;
+ struct drm_display_mode mode;
bool connected;
bool is_tpg_enabled;
@@ -270,6 +272,22 @@ int sde_hdmi_get_info(struct msm_display_info *info,
void *display);
/**
+ * sde_hdmi_set_property() - set the connector properties
+ * @connector: Handle to the connector.
+ * @state: Handle to the connector state.
+ * @property_index: property index.
+ * @value: property value.
+ * @display: Handle to the display.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ int property_index,
+ uint64_t value,
+ void *display);
+
+/**
* sde_hdmi_bridge_init() - init sde hdmi bridge
* @hdmi: Handle to the hdmi.
*
@@ -453,5 +471,15 @@ static inline int sde_hdmi_get_info(struct msm_display_info *info,
{
return 0;
}
+
+static inline int sde_hdmi_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ int property_index,
+ uint64_t value,
+ void *display)
+{
+ return 0;
+}
+
#endif /*#else of CONFIG_DRM_SDE_HDMI*/
#endif /* _SDE_HDMI_H_ */
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c
index 13ea49cfa42d..48a3a9316a41 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_audio.c
@@ -30,8 +30,6 @@
#define HDMI_AUDIO_INFO_FRAME_PACKET_VERSION 0x1
#define HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH 0x0A
-#define HDMI_KHZ_TO_HZ 1000
-#define HDMI_MHZ_TO_HZ 1000000
#define HDMI_ACR_N_MULTIPLIER 128
#define DEFAULT_AUDIO_SAMPLE_RATE_HZ 48000
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index c76e42c67885..6c82c3d4826d 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -568,6 +568,15 @@ static void _sde_hdmi_bridge_set_spd_infoframe(struct hdmi *hdmi,
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, packet_control);
}
+static inline void _sde_hdmi_save_mode(struct hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
+
+ drm_mode_copy(&display->mode, mode);
+}
+
static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -640,6 +649,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
DRM_DEBUG("hdmi setup info frame\n");
}
_sde_hdmi_bridge_setup_scrambler(hdmi, mode);
+
+ _sde_hdmi_save_mode(hdmi, mode);
}
static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index b6cddee0cf34..119221eacb43 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -184,8 +184,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file);
if (aspace) {
- aspace->mmu->funcs->detach(aspace->mmu,
- iommu_ports, ARRAY_SIZE(iommu_ports));
+ aspace->mmu->funcs->detach(aspace->mmu);
msm_gem_address_space_destroy(aspace);
}
}
@@ -202,8 +201,7 @@ static void mdp4_destroy(struct msm_kms *kms)
drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo);
if (aspace) {
- aspace->mmu->funcs->detach(aspace->mmu,
- iommu_ports, ARRAY_SIZE(iommu_ports));
+ aspace->mmu->funcs->detach(aspace->mmu);
msm_gem_address_space_put(aspace);
}
@@ -416,10 +414,6 @@ fail:
return ret;
}
-static const char *iommu_ports[] = {
- "mdp_port0_cb0", "mdp_port1_cb0",
-};
-
struct msm_kms *mdp4_kms_init(struct drm_device *dev)
{
struct platform_device *pdev = dev->platformdev;
@@ -515,15 +509,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
mdelay(16);
if (config->iommu) {
- struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
-
- if (IS_ERR(mmu)) {
- ret = PTR_ERR(mmu);
- goto fail;
- }
+ config->iommu->geometry.aperture_start = 0x1000;
+ config->iommu->geometry.aperture_end = 0xffffffff;
aspace = msm_gem_address_space_create(&pdev->dev,
- mmu, "mdp4", 0x1000, 0xffffffff);
+ config->iommu, MSM_IOMMU_DOMAIN_DEFAULT, "mdp4");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
goto fail;
@@ -531,8 +521,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
mdp4_kms->aspace = aspace;
- ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
- ARRAY_SIZE(iommu_ports));
+ ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0);
if (ret)
goto fail;
} else {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index e4e69ebd116e..4dbf456504b7 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -22,10 +22,6 @@
#include "msm_mmu.h"
#include "mdp5_kms.h"
-static const char *iommu_ports[] = {
- "mdp_0",
-};
-
static int mdp5_hw_init(struct msm_kms *kms)
{
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
@@ -613,8 +609,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
mdp5_kms->aspace = aspace;
- ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
- ARRAY_SIZE(iommu_ports));
+ ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "failed to attach iommu: %d\n",
ret);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 943d73fa544d..bd75a1ba1f8b 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -148,6 +148,7 @@ enum msm_mdp_conn_property {
CONNECTOR_PROP_DST_Y,
CONNECTOR_PROP_DST_W,
CONNECTOR_PROP_DST_H,
+ CONNECTOR_PROP_PLL_DELTA,
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -412,7 +413,7 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
/* For GPU and legacy display */
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name);
+ int type, const char *name);
struct msm_gem_address_space *
msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name,
uint64_t start, uint64_t end);
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 2045dc34c20a..0b19d11bc666 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -25,21 +25,12 @@
/* Additional internal-use only BO flags: */
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
-struct msm_gem_aspace_ops {
- int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *,
- struct sg_table *sgt, void *priv, unsigned int flags);
-
- void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *,
- struct sg_table *sgt, void *priv);
-
- void (*destroy)(struct msm_gem_address_space *);
-};
-
struct msm_gem_address_space {
const char *name;
struct msm_mmu *mmu;
- const struct msm_gem_aspace_ops *ops;
struct kref kref;
+ struct drm_mm mm;
+ u64 va_len;
};
struct msm_gem_vma {
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 52fc81420690..8e0f15c416fd 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -82,13 +82,16 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
void __user *userptr =
to_user_ptr(args->bos + (i * sizeof(submit_bo)));
- ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
- if (unlikely(ret)) {
+ if (copy_from_user_inatomic(&submit_bo, userptr,
+ sizeof(submit_bo))) {
pagefault_enable();
spin_unlock(&file->table_lock);
- ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
- if (ret)
+ if (copy_from_user(&submit_bo, userptr,
+ sizeof(submit_bo))) {
+ ret = -EFAULT;
goto out;
+ }
+
spin_lock(&file->table_lock);
pagefault_disable();
}
@@ -283,8 +286,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
uint32_t off;
bool valid;
- ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
- if (ret)
+ if (copy_from_user(&submit_reloc, userptr,
+ sizeof(submit_reloc)))
return -EFAULT;
if (submit_reloc.submit_offset % 4) {
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index a227f1ba0573..47f7436854fb 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -25,8 +25,10 @@ msm_gem_address_space_destroy(struct kref *kref)
struct msm_gem_address_space *aspace = container_of(kref,
struct msm_gem_address_space, kref);
- if (aspace->ops->destroy)
- aspace->ops->destroy(aspace);
+ if (aspace->va_len)
+ drm_mm_takedown(&aspace->mm);
+
+ aspace->mmu->funcs->destroy(aspace->mmu);
kfree(aspace);
}
@@ -37,57 +39,9 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace)
kref_put(&aspace->kref, msm_gem_address_space_destroy);
}
-/* SDE address space operations */
-static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt,
- void *priv)
-{
- struct dma_buf *buf = priv;
-
- if (buf)
- aspace->mmu->funcs->unmap_dma_buf(aspace->mmu,
- sgt, buf, DMA_BIDIRECTIONAL);
- else
- aspace->mmu->funcs->unmap_sg(aspace->mmu, sgt,
- DMA_BIDIRECTIONAL);
-
- vma->iova = 0;
-
- msm_gem_address_space_put(aspace);
-}
-
-
-static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt,
- void *priv, unsigned int flags)
-{
- struct dma_buf *buf = priv;
- int ret;
-
- if (buf)
- ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf,
- DMA_BIDIRECTIONAL);
- else
- ret = aspace->mmu->funcs->map_sg(aspace->mmu, sgt,
- DMA_BIDIRECTIONAL);
-
- if (!ret)
- vma->iova = sg_dma_address(sgt->sgl);
-
- /* Get a reference to the aspace to keep it around */
- kref_get(&aspace->kref);
-
- return ret;
-}
-
-static const struct msm_gem_aspace_ops smmu_aspace_ops = {
- .map = smmu_aspace_map_vma,
- .unmap = smmu_aspace_unmap_vma,
-};
-
-struct msm_gem_address_space *
-msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
- const char *name)
+static struct msm_gem_address_space *
+msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
+ uint64_t start, uint64_t end)
{
struct msm_gem_address_space *aspace;
@@ -100,57 +54,28 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
aspace->name = name;
aspace->mmu = mmu;
- aspace->ops = &smmu_aspace_ops;
-
- kref_init(&aspace->kref);
-
- return aspace;
-}
-/* GPU address space operations */
-struct msm_iommu_aspace {
- struct msm_gem_address_space base;
- struct drm_mm mm;
-};
+ aspace->va_len = end - start;
-#define to_iommu_aspace(aspace) \
- ((struct msm_iommu_aspace *) \
- container_of(aspace, struct msm_iommu_aspace, base))
+ if (aspace->va_len)
+ drm_mm_init(&aspace->mm, (start >> PAGE_SHIFT),
+ (end >> PAGE_SHIFT) - 1);
-static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
-{
- if (!vma->iova)
- return;
-
- if (aspace->mmu)
- aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt);
-
- drm_mm_remove_node(&vma->node);
-
- vma->iova = 0;
+ kref_init(&aspace->kref);
- msm_gem_address_space_put(aspace);
+ return aspace;
}
-static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, void *priv,
- unsigned int flags)
+static int allocate_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma, struct sg_table *sgt,
+ u64 *iova)
{
- struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
- size_t size = 0;
struct scatterlist *sg;
+ size_t size = 0;
int ret, i;
- int iommu_flags = IOMMU_READ;
-
- if (!(flags & MSM_BO_GPU_READONLY))
- iommu_flags |= IOMMU_WRITE;
- if (flags & MSM_BO_PRIVILEGED)
- iommu_flags |= IOMMU_PRIV;
-
- if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(aspace->mmu))
- iommu_flags |= IOMMU_CACHE;
+ if (!aspace->va_len)
+ return 0;
if (WARN_ON(drm_mm_node_allocated(&vma->node)))
return 0;
@@ -158,84 +83,73 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
for_each_sg(sgt->sgl, sg, sgt->nents, i)
size += sg->length + sg->offset;
- ret = drm_mm_insert_node(&local->mm, &vma->node, size >> PAGE_SHIFT,
+ ret = drm_mm_insert_node(&aspace->mm, &vma->node, size >> PAGE_SHIFT,
0, DRM_MM_SEARCH_DEFAULT);
- if (ret)
- return ret;
-
- vma->iova = vma->node.start << PAGE_SHIFT;
-
- if (aspace->mmu)
- ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
- iommu_flags);
- /* Get a reference to the aspace to keep it around */
- kref_get(&aspace->kref);
+ if (!ret && iova)
+ *iova = vma->node.start << PAGE_SHIFT;
return ret;
}
-static void iommu_aspace_destroy(struct msm_gem_address_space *aspace)
+int msm_gem_map_vma(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma, struct sg_table *sgt,
+ void *priv, unsigned int flags)
{
- struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
-
- drm_mm_takedown(&local->mm);
- aspace->mmu->funcs->destroy(aspace->mmu);
-}
-
-static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = {
- .map = iommu_aspace_map_vma,
- .unmap = iommu_aspace_unmap_vma,
- .destroy = iommu_aspace_destroy,
-};
+ u64 iova = 0;
+ int ret;
-static struct msm_gem_address_space *
-msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
- uint64_t start, uint64_t end)
-{
- struct msm_iommu_aspace *local;
+ if (!aspace)
+ return -EINVAL;
- if (!mmu)
- return ERR_PTR(-EINVAL);
+ ret = allocate_iova(aspace, vma, sgt, &iova);
+ if (ret)
+ return ret;
- local = kzalloc(sizeof(*local), GFP_KERNEL);
- if (!local)
- return ERR_PTR(-ENOMEM);
+ ret = aspace->mmu->funcs->map(aspace->mmu, iova, sgt,
+ flags, priv);
- drm_mm_init(&local->mm, (start >> PAGE_SHIFT),
- (end >> PAGE_SHIFT) - 1);
+ if (ret) {
+ if (drm_mm_node_allocated(&vma->node))
+ drm_mm_remove_node(&vma->node);
- local->base.name = name;
- local->base.mmu = mmu;
- local->base.ops = &msm_iommu_aspace_ops;
+ return ret;
+ }
- kref_init(&local->base.kref);
+ vma->iova = sg_dma_address(sgt->sgl);
+ kref_get(&aspace->kref);
- return &local->base;
+ return 0;
}
-int msm_gem_map_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt,
- void *priv, unsigned int flags)
+void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
{
- if (aspace && aspace->ops->map)
- return aspace->ops->map(aspace, vma, sgt, priv, flags);
+ if (!aspace || !vma->iova)
+ return;
- return -EINVAL;
+ aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
+
+ if (drm_mm_node_allocated(&vma->node))
+ drm_mm_remove_node(&vma->node);
+
+ vma->iova = 0;
+
+ msm_gem_address_space_put(aspace);
}
-void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+struct msm_gem_address_space *
+msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
+ const char *name)
{
- if (aspace && aspace->ops->unmap)
- aspace->ops->unmap(aspace, vma, sgt, priv);
+ return msm_gem_address_space_new(mmu, name, 0, 0);
}
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name)
+ int type, const char *name)
{
- struct msm_mmu *mmu = msm_iommu_new(dev, domain);
+ struct msm_mmu *mmu = msm_iommu_new(dev, type, domain);
if (IS_ERR(mmu))
return (struct msm_gem_address_space *) mmu;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 5a505a8bf328..2f01db8b08c3 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -183,6 +183,9 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
+ if (gpu->aspace && gpu->aspace->mmu)
+ msm_mmu_enable(gpu->aspace->mmu);
+
return 0;
}
@@ -203,6 +206,9 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
if (WARN_ON(gpu->active_cnt < 0))
return -EINVAL;
+ if (gpu->aspace && gpu->aspace->mmu)
+ msm_mmu_disable(gpu->aspace->mmu);
+
ret = disable_axi(gpu);
if (ret)
return ret;
@@ -837,7 +843,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
dev_info(drm->dev, "%s: using IOMMU\n", name);
gpu->aspace = msm_gem_address_space_create(&pdev->dev,
- iommu, "gpu");
+ iommu, MSM_IOMMU_DOMAIN_USER, "gpu");
if (IS_ERR(gpu->aspace)) {
ret = PTR_ERR(gpu->aspace);
dev_err(drm->dev, "failed to init iommu: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 3fac423929c5..29e2e59b580b 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -29,6 +29,9 @@
struct msm_gem_submit;
struct msm_gpu_perfcntr;
+#define MSM_GPU_DEFAULT_IONAME "kgsl_3d0_reg_memory"
+#define MSM_GPU_DEFAULT_IRQNAME "kgsl_3d0_irq"
+
struct msm_gpu_config {
const char *ioname;
const char *irqname;
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index 3af24646f4f1..b52c4752c5fe 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/of_address.h>
+#include <soc/qcom/secure_buffer.h>
#include "msm_drv.h"
#include "msm_iommu.h"
@@ -27,31 +28,17 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
return 0;
}
-/*
- * Get and enable the IOMMU clocks so that we can make
- * sure they stay on the entire duration so that we can
- * safely change the pagetable from the GPU
- */
-static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
+static void iommu_get_clocks(struct msm_iommu *iommu, struct device *dev)
{
- struct msm_iommu *iommu = to_msm_iommu(mmu);
- struct device *dev;
struct property *prop;
const char *name;
int i = 0;
- if (WARN_ON(!pdev))
- return;
-
- dev = &pdev->dev;
-
iommu->nr_clocks =
of_property_count_strings(dev->of_node, "clock-names");
- if (iommu->nr_clocks < 0) {
- iommu->nr_clocks = 0;
+ if (iommu->nr_clocks < 0)
return;
- }
if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks)))
iommu->nr_clocks = ARRAY_SIZE(iommu->clocks);
@@ -60,78 +47,58 @@ static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
if (i == iommu->nr_clocks)
break;
- iommu->clocks[i] = clk_get(dev, name);
- if (iommu->clocks[i])
- clk_prepare_enable(iommu->clocks[i]);
-
- i++;
+ iommu->clocks[i++] = clk_get(dev, name);
}
}
-static int _attach_iommu_device(struct msm_mmu *mmu,
- struct iommu_domain *domain, const char **names, int cnt)
+
+static void msm_iommu_clocks_enable(struct msm_mmu *mmu)
{
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
int i;
- /* See if there is a iommus member in the current device. If not, look
- * for the names and see if there is one in there.
- */
+ if (!iommu->nr_clocks)
+ iommu_get_clocks(iommu, mmu->dev->parent);
- if (of_find_property(mmu->dev->of_node, "iommus", NULL))
- return iommu_attach_device(domain, mmu->dev);
-
- /* Look through the list of names for a target */
- for (i = 0; i < cnt; i++) {
- struct device_node *node =
- of_find_node_by_name(mmu->dev->of_node, names[i]);
-
- if (!node)
- continue;
-
- if (of_find_property(node, "iommus", NULL)) {
- struct platform_device *pdev;
-
- /* Get the platform device for the node */
- of_platform_populate(node->parent, NULL, NULL,
- mmu->dev);
-
- pdev = of_find_device_by_node(node);
-
- if (!pdev)
- continue;
-
- _get_iommu_clocks(mmu,
- of_find_device_by_node(node->parent));
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_prepare_enable(iommu->clocks[i]);
+ }
+}
- mmu->dev = &pdev->dev;
+static void msm_iommu_clocks_disable(struct msm_mmu *mmu)
+{
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
+ int i;
- return iommu_attach_device(domain, mmu->dev);
- }
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_disable_unprepare(iommu->clocks[i]);
}
+}
- dev_err(mmu->dev, "Couldn't find a IOMMU device\n");
- return -ENODEV;
+static int msm_iommu_attach(struct msm_mmu *mmu, const char **names,
+ int cnt)
+{
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
+
+ return iommu_attach_device(iommu->domain, mmu->dev);
}
-static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
+static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names,
+ int cnt)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int val = 1, ret;
+ int ret, val = 1;
/* Hope springs eternal */
- iommu->allow_dynamic = true;
-
- /* per-instance pagetables need TTBR1 support in the IOMMU driver */
- ret = iommu_domain_set_attr(iommu->domain,
- DOMAIN_ATTR_ENABLE_TTBR1, &val);
- if (ret)
- iommu->allow_dynamic = false;
+ iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain,
+ DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false;
/* Mark the GPU as I/O coherent if it is supported */
iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node);
- /* Attach the device to the domain */
- ret = _attach_iommu_device(mmu, iommu->domain, names, cnt);
+ ret = iommu_attach_device(iommu->domain, mmu->dev);
if (ret)
return ret;
@@ -176,17 +143,25 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names,
return 0;
}
+static int msm_iommu_attach_secure(struct msm_mmu *mmu, const char **names,
+ int cnt)
+{
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
+ int ret, vmid = VMID_CP_PIXEL;
+
+ ret = iommu_domain_set_attr(iommu->domain, DOMAIN_ATTR_SECURE_VMID,
+ &vmid);
+ if (ret)
+ return ret;
+
+ return iommu_attach_device(iommu->domain, mmu->dev);
+}
+
static void msm_iommu_detach(struct msm_mmu *mmu)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int i;
iommu_detach_device(iommu->domain, mmu->dev);
-
- for (i = 0; i < iommu->nr_clocks; i++) {
- if (iommu->clocks[i])
- clk_disable(iommu->clocks[i]);
- }
}
static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
@@ -196,69 +171,50 @@ static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
}
static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
- struct sg_table *sgt, int prot)
+ struct sg_table *sgt, u32 flags, void *priv)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
struct iommu_domain *domain = iommu->domain;
- struct scatterlist *sg;
- uint64_t da = iova;
- unsigned int i, j;
int ret;
+ u32 prot = IOMMU_READ;
if (!domain || !sgt)
return -EINVAL;
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
- phys_addr_t pa = sg_phys(sg) - sg->offset;
- size_t bytes = sg->length + sg->offset;
+ if (!(flags & MSM_BO_GPU_READONLY))
+ prot |= IOMMU_WRITE;
- VERB("map[%d]: %016llx %pa(%zx)", i, iova, &pa, bytes);
+ if (flags & MSM_BO_PRIVILEGED)
+ prot |= IOMMU_PRIV;
- ret = iommu_map(domain, da, pa, bytes, prot);
- if (ret)
- goto fail;
+ if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(mmu))
+ prot |= IOMMU_CACHE;
- da += bytes;
- }
-
- return 0;
-
-fail:
- da = iova;
+ /* iommu_map_sg returns the number of bytes mapped */
+ ret = iommu_map_sg(domain, iova, sgt->sgl, sgt->nents, prot);
+ if (ret)
+ sgt->sgl->dma_address = iova;
- for_each_sg(sgt->sgl, sg, i, j) {
- size_t bytes = sg->length + sg->offset;
- iommu_unmap(domain, da, bytes);
- da += bytes;
- }
- return ret;
+ return ret ? 0 : -ENOMEM;
}
-static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova,
- struct sg_table *sgt)
+static void msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova,
+ struct sg_table *sgt, void *priv)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
struct iommu_domain *domain = iommu->domain;
struct scatterlist *sg;
- uint64_t da = iova;
- int i;
+ size_t len = 0;
+ int ret, i;
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
- size_t bytes = sg->length + sg->offset;
- size_t unmapped;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ len += sg->length;
- unmapped = iommu_unmap(domain, da, bytes);
- if (unmapped < bytes)
- return unmapped;
+ ret = iommu_unmap(domain, iova, len);
+ if (ret != len)
+ dev_warn(mmu->dev, "could not unmap iova %llx\n", iova);
- VERB("unmap[%d]: %016llx(%zx)", i, iova, bytes);
-
- BUG_ON(!PAGE_ALIGNED(bytes));
-
- da += bytes;
- }
-
- return 0;
+ sgt->sgl->dma_address = 0;
}
static void msm_iommu_destroy(struct msm_mmu *mmu)
@@ -268,7 +224,30 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
kfree(iommu);
}
-static const struct msm_mmu_funcs funcs = {
+static struct device *find_context_bank(const char *name)
+{
+ struct device_node *node = of_find_node_by_name(NULL, name);
+ struct platform_device *pdev, *parent;
+
+ if (!node)
+ return ERR_PTR(-ENODEV);
+
+ if (!of_find_property(node, "iommus", NULL))
+ return ERR_PTR(-ENODEV);
+
+ /* Get the parent device */
+ parent = of_find_device_by_node(node->parent);
+
+ /* Populate the sub nodes */
+ of_platform_populate(parent->dev.of_node, NULL, NULL, &parent->dev);
+
+ /* Get the context bank device */
+ pdev = of_find_device_by_node(node);
+
+ return pdev ? &pdev->dev : ERR_PTR(-ENODEV);
+}
+
+static const struct msm_mmu_funcs default_funcs = {
.attach = msm_iommu_attach,
.detach = msm_iommu_detach,
.map = msm_iommu_map,
@@ -276,6 +255,24 @@ static const struct msm_mmu_funcs funcs = {
.destroy = msm_iommu_destroy,
};
+static const struct msm_mmu_funcs user_funcs = {
+ .attach = msm_iommu_attach_user,
+ .detach = msm_iommu_detach,
+ .map = msm_iommu_map,
+ .unmap = msm_iommu_unmap,
+ .destroy = msm_iommu_destroy,
+ .enable = msm_iommu_clocks_enable,
+ .disable = msm_iommu_clocks_disable,
+};
+
+static const struct msm_mmu_funcs secure_funcs = {
+ .attach = msm_iommu_attach_secure,
+ .detach = msm_iommu_detach,
+ .map = msm_iommu_map,
+ .unmap = msm_iommu_unmap,
+ .destroy = msm_iommu_destroy,
+};
+
static const struct msm_mmu_funcs dynamic_funcs = {
.attach = msm_iommu_attach_dynamic,
.detach = msm_iommu_detach_dynamic,
@@ -284,8 +281,26 @@ static const struct msm_mmu_funcs dynamic_funcs = {
.destroy = msm_iommu_destroy,
};
-struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
- const struct msm_mmu_funcs *funcs)
+static const struct {
+ const char *cbname;
+ const struct msm_mmu_funcs *funcs;
+} msm_iommu_domains[] = {
+ [MSM_IOMMU_DOMAIN_DEFAULT] = {
+ .cbname = NULL,
+ .funcs = &default_funcs,
+ },
+ [MSM_IOMMU_DOMAIN_USER] = {
+ .cbname = "gfx3d_user",
+ .funcs = &user_funcs,
+ },
+ [MSM_IOMMU_DOMAIN_SECURE] = {
+ .cbname = "gfx3d_secure",
+ .funcs = &secure_funcs
+ },
+};
+
+static struct msm_mmu *iommu_create(struct device *dev,
+ struct iommu_domain *domain, const struct msm_mmu_funcs *funcs)
{
struct msm_iommu *iommu;
@@ -299,9 +314,23 @@ struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
return &iommu->base;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
+
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain)
{
- return _msm_iommu_new(dev, domain, &funcs);
+ struct device *dev = parent;
+
+ if (type >= ARRAY_SIZE(msm_iommu_domains) ||
+ !msm_iommu_domains[type].funcs)
+ return ERR_PTR(-ENODEV);
+
+ if (msm_iommu_domains[type].cbname) {
+ dev = find_context_bank(msm_iommu_domains[type].cbname);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+ }
+
+ return iommu_create(dev, domain, msm_iommu_domains[type].funcs);
}
/*
@@ -326,7 +355,7 @@ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base)
if (!domain)
return ERR_PTR(-ENODEV);
- mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs);
+ mmu = iommu_create(base->dev, domain, &dynamic_funcs);
if (IS_ERR(mmu)) {
if (domain)
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index 501f12bef00d..033370ccbe24 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -30,21 +30,22 @@ enum msm_mmu_domain_type {
MSM_SMMU_DOMAIN_MAX,
};
+enum msm_iommu_domain_type {
+ MSM_IOMMU_DOMAIN_DEFAULT,
+ MSM_IOMMU_DOMAIN_USER,
+ MSM_IOMMU_DOMAIN_SECURE,
+};
+
struct msm_mmu_funcs {
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
void (*detach)(struct msm_mmu *mmu);
int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
- int prot);
- int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt);
- int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
- enum dma_data_direction dir);
- void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt,
- enum dma_data_direction dir);
- int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt,
- struct dma_buf *dma_buf, int dir);
- void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt,
- struct dma_buf *dma_buf, int dir);
+ u32 flags, void *priv);
+ void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
+ void *priv);
void (*destroy)(struct msm_mmu *mmu);
+ void (*enable)(struct msm_mmu *mmu);
+ void (*disable)(struct msm_mmu *mmu);
};
struct msm_mmu {
@@ -59,9 +60,27 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
mmu->funcs = funcs;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
+/* Create a new SDE mmu device */
struct msm_mmu *msm_smmu_new(struct device *dev,
enum msm_mmu_domain_type domain);
+
+/* Create a new legacy MDP4 or GPU mmu device */
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain);
+
+/* Create a new dynamic domain for GPU */
struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig);
+static inline void msm_mmu_enable(struct msm_mmu *mmu)
+{
+ if (mmu->funcs->enable)
+ mmu->funcs->enable(mmu);
+}
+
+static inline void msm_mmu_disable(struct msm_mmu *mmu)
+{
+ if (mmu->funcs->disable)
+ mmu->funcs->disable(mmu);
+}
+
#endif /* __MSM_MMU_H__ */
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index 5a9e472ea59b..5f3d1b6356aa 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -183,6 +183,55 @@ static void _msm_property_install_integer(struct msm_property_info *info,
}
}
+/**
+ * _msm_property_install_integer - install signed drm range property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
+ */
+static void _msm_property_install_signed_integer(struct msm_property_info *info,
+ const char *name, int flags, int64_t min, int64_t max,
+ int64_t init, uint32_t property_idx, bool force_dirty)
+{
+ struct drm_property **prop;
+
+ if (!info)
+ return;
+
+ ++info->install_request;
+
+ if (!name || (property_idx >= info->property_count)) {
+ DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
+ } else {
+ prop = &info->property_array[property_idx];
+ /*
+ * Properties need to be attached to each drm object that
+ * uses them, but only need to be created once
+ */
+ if (*prop == 0) {
+ *prop = drm_property_create_signed_range(info->dev,
+ flags, name, min, max);
+ if (*prop == 0)
+ DRM_ERROR("create %s property failed\n", name);
+ }
+
+ /* save init value for later */
+ info->property_data[property_idx].default_value = I642U64(init);
+ info->property_data[property_idx].force_dirty = force_dirty;
+
+ /* always attach property, if created */
+ if (*prop) {
+ drm_object_attach_property(info->base, *prop, init);
+ ++info->install_count;
+ }
+ }
+}
+
void msm_property_install_range(struct msm_property_info *info,
const char *name, int flags, uint64_t min, uint64_t max,
uint64_t init, uint32_t property_idx)
@@ -199,6 +248,22 @@ void msm_property_install_volatile_range(struct msm_property_info *info,
min, max, init, property_idx, true);
}
+void msm_property_install_signed_range(struct msm_property_info *info,
+ const char *name, int flags, int64_t min, int64_t max,
+ int64_t init, uint32_t property_idx)
+{
+ _msm_property_install_signed_integer(info, name, flags,
+ min, max, init, property_idx, false);
+}
+
+void msm_property_install_volatile_signed_range(struct msm_property_info *info,
+ const char *name, int flags, int64_t min, int64_t max,
+ int64_t init, uint32_t property_idx)
+{
+ _msm_property_install_signed_integer(info, name, flags,
+ min, max, init, property_idx, true);
+}
+
void msm_property_install_rotation(struct msm_property_info *info,
unsigned int supported_rotations, uint32_t property_idx)
{
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index dbe28bdf5638..1430551700c7 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -208,6 +208,45 @@ void msm_property_install_volatile_range(struct msm_property_info *info,
uint32_t property_idx);
/**
+ * msm_property_install_signed_range - install signed drm range property
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ */
+void msm_property_install_signed_range(struct msm_property_info *info,
+ const char *name,
+ int flags,
+ int64_t min,
+ int64_t max,
+ int64_t init,
+ uint32_t property_idx);
+
+/**
+ * msm_property_install_volatile_signed_range - install signed range property
+ * This function is similar to msm_property_install_range, but assumes
+ * that the property is meant for holding user pointers or descriptors
+ * that may reference volatile data without having an updated value.
+ * @info: Pointer to property info container struct
+ * @name: Property name
+ * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
+ * @min: Min property value
+ * @max: Max property value
+ * @init: Default Property value
+ * @property_idx: Property index
+ */
+void msm_property_install_volatile_signed_range(struct msm_property_info *info,
+ const char *name,
+ int flags,
+ int64_t min,
+ int64_t max,
+ int64_t init,
+ uint32_t property_idx);
+
+/**
* msm_property_install_rotation - install standard drm rotation property
* @info: Pointer to property info container struct
* @supported_rotations: Bitmask of supported rotation values (see
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index c99f51e09700..f5c6e0cd8048 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -105,106 +105,34 @@ static void msm_smmu_detach(struct msm_mmu *mmu)
}
static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova,
- struct sg_table *sgt, int prot)
+ struct sg_table *sgt, u32 flags, void *priv)
{
struct msm_smmu *smmu = to_msm_smmu(mmu);
struct msm_smmu_client *client = msm_smmu_to_client(smmu);
- struct iommu_domain *domain;
- struct scatterlist *sg;
- uint64_t da = iova;
- unsigned int i, j;
int ret;
- if (!client)
- return -ENODEV;
-
- domain = client->mmu_mapping->domain;
- if (!domain || !sgt)
- return -EINVAL;
-
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
- u32 pa = sg_phys(sg) - sg->offset;
- size_t bytes = sg->length + sg->offset;
-
- VERB("map[%d]: %16llx %08x(%zx)", i, iova, pa, bytes);
-
- ret = iommu_map(domain, da, pa, bytes, prot);
- if (ret)
- goto fail;
-
- da += bytes;
- }
-
- return 0;
-
-fail:
- da = iova;
-
- for_each_sg(sgt->sgl, sg, i, j) {
- size_t bytes = sg->length + sg->offset;
-
- iommu_unmap(domain, da, bytes);
- da += bytes;
- }
- return ret;
-}
-
-static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt,
- enum dma_data_direction dir)
-{
- struct msm_smmu *smmu = to_msm_smmu(mmu);
- struct msm_smmu_client *client = msm_smmu_to_client(smmu);
- int ret;
-
- ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir);
- if (ret != sgt->nents)
- return -ENOMEM;
-
- return 0;
-}
-
-static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt,
- enum dma_data_direction dir)
-{
- struct msm_smmu *smmu = to_msm_smmu(mmu);
- struct msm_smmu_client *client = msm_smmu_to_client(smmu);
+ if (priv)
+ ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL, priv);
+ else
+ ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL);
- dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir);
+ return (ret != sgt->nents) ? -ENOMEM : 0;
}
-static int msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
- struct sg_table *sgt)
+static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
+ struct sg_table *sgt, void *priv)
{
struct msm_smmu *smmu = to_msm_smmu(mmu);
struct msm_smmu_client *client = msm_smmu_to_client(smmu);
- struct iommu_domain *domain;
- struct scatterlist *sg;
- uint64_t da = iova;
- int i;
-
- if (!client)
- return -ENODEV;
-
- domain = client->mmu_mapping->domain;
- if (!domain || !sgt)
- return -EINVAL;
-
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
- size_t bytes = sg->length + sg->offset;
- size_t unmapped;
-
- unmapped = iommu_unmap(domain, da, bytes);
- if (unmapped < bytes)
- return unmapped;
-
- VERB("unmap[%d]: %16llx(%zx)", i, iova, bytes);
- WARN_ON(!PAGE_ALIGNED(bytes));
-
- da += bytes;
- }
-
- return 0;
+ if (priv)
+ msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL, priv);
+ else
+ dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL);
}
static void msm_smmu_destroy(struct msm_mmu *mmu)
@@ -217,42 +145,11 @@ static void msm_smmu_destroy(struct msm_mmu *mmu)
kfree(smmu);
}
-static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
- struct dma_buf *dma_buf, int dir)
-{
- struct msm_smmu *smmu = to_msm_smmu(mmu);
- struct msm_smmu_client *client = msm_smmu_to_client(smmu);
- int ret;
-
- ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, dir,
- dma_buf);
- if (ret != sgt->nents) {
- DRM_ERROR("dma map sg failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-
-static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
- struct dma_buf *dma_buf, int dir)
-{
- struct msm_smmu *smmu = to_msm_smmu(mmu);
- struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-
- msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
-}
-
static const struct msm_mmu_funcs funcs = {
.attach = msm_smmu_attach,
.detach = msm_smmu_detach,
.map = msm_smmu_map,
- .map_sg = msm_smmu_map_sg,
- .unmap_sg = msm_smmu_unmap_sg,
.unmap = msm_smmu_unmap,
- .map_dma_buf = msm_smmu_map_dma_buf,
- .unmap_dma_buf = msm_smmu_unmap_dma_buf,
.destroy = msm_smmu_destroy,
};
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 31cf25ab5691..98eb50a04cb1 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -586,6 +586,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
+ msm_property_install_volatile_signed_range(&c_conn->property_info,
+ "PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0,
+ CONNECTOR_PROP_PLL_DELTA);
+
/* enum/bitmask properties */
msm_property_install_enum(&c_conn->property_info, "topology_name",
DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 581918da183f..f8c236f21e22 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -41,10 +41,6 @@
#define CREATE_TRACE_POINTS
#include "sde_trace.h"
-static const char * const iommu_ports[] = {
- "mdp_0",
-};
-
/**
* Controls size of event log buffer. Specified as a power of 2.
*/
@@ -598,6 +594,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.get_modes = sde_hdmi_connector_get_modes,
.mode_valid = sde_hdmi_mode_valid,
.get_info = sde_hdmi_get_info,
+ .set_property = sde_hdmi_set_property,
};
struct msm_display_info info = {0};
struct drm_encoder *encoder;
@@ -1076,8 +1073,7 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
sde_kms->aspace[i] = aspace;
- ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
- ARRAY_SIZE(iommu_ports));
+ ret = mmu->funcs->attach(mmu, NULL, 0);
if (ret) {
SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
msm_gem_address_space_put(aspace);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c
index fef4a8585eaa..74f362839ccc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -133,7 +133,7 @@ struct sde_mdp_mixer *sde_mdp_mixer_get(struct sde_mdp_ctl *ctl, int mux)
int sde_mdp_get_pipe_flush_bits(struct sde_mdp_pipe *pipe)
{
- u32 flush_bits;
+ u32 flush_bits = 0;
if (pipe->type == SDE_MDP_PIPE_TYPE_DMA)
flush_bits |= BIT(pipe->num) << 5;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index f5dbb67ba929..ccf22eb5bdc0 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -128,14 +128,11 @@ static int mmc_cmdq_thread(void *d)
ret = mq->cmdq_issue_fn(mq, mq->cmdq_req_peeked);
/*
- * Don't requeue if issue_fn fails, just bug on.
- * We don't expect failure here and there is no recovery other
- * than fixing the actual issue if there is any.
+ * Don't requeue if issue_fn fails.
+ * Recovery will be come by completion softirq
* Also we end the request if there is a partition switch error,
* so we should not requeue the request here.
*/
- if (ret)
- BUG_ON(1);
} /* loop */
return 0;
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index a83960fd474f..3f741f83a436 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -1102,12 +1102,17 @@ skip_cqterri:
* before setting doorbell, hence one is not needed here.
*/
for_each_set_bit(tag, &comp_status, cq_host->num_slots) {
- /* complete the corresponding mrq */
- pr_debug("%s: completing tag -> %lu\n",
- mmc_hostname(mmc), tag);
- MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
- __func__, tag);
+ mrq = get_req_by_tag(cq_host, tag);
+ if (!((mrq->cmd && mrq->cmd->error) ||
+ mrq->cmdq_req->resp_err ||
+ (mrq->data && mrq->data->error))) {
+ /* complete the corresponding mrq */
+ pr_debug("%s: completing tag -> %lu\n",
+ mmc_hostname(mmc), tag);
+ MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
+ __func__, tag);
cmdq_finish_data(mmc, tag);
+ }
}
}
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index f364882943e1..243afbe44df3 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -6754,12 +6754,12 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev,
PCIE_DBG(pcie_dev, "RC%d: PM_Enter_L23 is NOT received\n",
pcie_dev->rc_idx);
- msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
-
if (pcie_dev->use_pinctrl && pcie_dev->pins_sleep)
pinctrl_select_state(pcie_dev->pinctrl,
pcie_dev->pins_sleep);
+ msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
+
PCIE_DBG(pcie_dev, "RC%d: exit\n", pcie_dev->rc_idx);
return ret;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index c5b56f16788a..f23062702f28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1515,6 +1515,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
struct ipa3_ep_context *ep;
int empty;
int result;
+ int i;
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1551,7 +1552,17 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
flush_workqueue(ep->sys->wq);
if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
- result = ipa3_stop_gsi_channel(clnt_hdl);
+ /* channel stop might fail on timeout if IPA is busy */
+ for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+ result = ipa3_stop_gsi_channel(clnt_hdl);
+ if (result == GSI_STATUS_SUCCESS)
+ break;
+
+ if (result != -GSI_STATUS_AGAIN &&
+ result != -GSI_STATUS_TIMED_OUT)
+ break;
+ }
+
if (result != GSI_STATUS_SUCCESS) {
IPAERR("GSI stop chan err: %d.\n", result);
BUG();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index f4a7319ca290..5ffc1f23f47c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3582,21 +3582,30 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
memset(&mem, 0, sizeof(mem));
+ if (IPA_CLIENT_IS_PROD(ep->client)) {
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
+ res = gsi_stop_channel(ep->gsi_chan_hdl);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
+ goto end_sequence;
+ }
+
for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
- IPADBG("Calling gsi_stop_channel\n");
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
res = gsi_stop_channel(ep->gsi_chan_hdl);
- IPADBG("gsi_stop_channel returned %d\n", res);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
goto end_sequence;
- if (IPA_CLIENT_IS_CONS(ep->client)) {
- IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
- /* Send a 1B packet DMA_TASK to IPA and try again */
- res = ipa3_inject_dma_task_for_gsi();
- if (res) {
- IPAERR("Failed to inject DMA TASk for GSI\n");
- goto end_sequence;
- }
+ IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
+ /* Send a 1B packet DMA_TASK to IPA and try again */
+ res = ipa3_inject_dma_task_for_gsi();
+ if (res) {
+ IPAERR("Failed to inject DMA TASk for GSI\n");
+ goto end_sequence;
}
/* sleep for short period to flush IPA */
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 723b9eaf658a..8d7322a325de 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -114,7 +114,8 @@ static ssize_t power_supply_show_property(struct device *dev,
return sprintf(buf, "%s\n", technology_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
- else if (off == POWER_SUPPLY_PROP_TYPE)
+ else if (off == POWER_SUPPLY_PROP_TYPE ||
+ off == POWER_SUPPLY_PROP_REAL_TYPE)
return sprintf(buf, "%s\n", type_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_SCOPE)
return sprintf(buf, "%s\n", scope_text[value.intval]);
@@ -294,6 +295,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(connector_health),
POWER_SUPPLY_ATTR(ctm_current_max),
POWER_SUPPLY_ATTR(hw_current_max),
+ POWER_SUPPLY_ATTR(real_type),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 539e757d3e99..98d75f586b67 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -410,19 +410,6 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
if (!chip->main_psy)
return 0;
- if (chip->batt_psy) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CURRENT_QNOVO,
- &pval);
- if (rc < 0) {
- pr_err("Couldn't get qnovo fcc, rc=%d\n", rc);
- return rc;
- }
-
- if (pval.intval != -EINVAL)
- total_fcc_ua = pval.intval;
- }
-
if (chip->pl_mode == POWER_SUPPLY_PL_NONE
|| get_effective_result_locked(chip->pl_disable_votable)) {
pval.intval = total_fcc_ua;
@@ -473,7 +460,6 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
int rc = 0;
- int effective_fv_uv = fv_uv;
if (fv_uv < 0)
return 0;
@@ -481,20 +467,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
if (!chip->main_psy)
return 0;
- if (chip->batt_psy) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
- &pval);
- if (rc < 0) {
- pr_err("Couldn't get qnovo fv, rc=%d\n", rc);
- return rc;
- }
-
- if (pval.intval != -EINVAL)
- effective_fv_uv = pval.intval;
- }
-
- pval.intval = effective_fv_uv;
+ pval.intval = fv_uv;
rc = power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
@@ -930,11 +903,17 @@ static int pl_determine_initial_status(struct pl_data *chip)
}
#define DEFAULT_RESTRICTED_CURRENT_UA 1000000
-static int pl_init(void)
+int qcom_batt_init(void)
{
struct pl_data *chip;
int rc = 0;
+ /* initialize just once */
+ if (the_chip) {
+ pr_err("was initialized earlier Failing now\n");
+ return -EINVAL;
+ }
+
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -1014,7 +993,9 @@ static int pl_init(void)
goto unreg_notifier;
}
- return rc;
+ the_chip = chip;
+
+ return 0;
unreg_notifier:
power_supply_unreg_notifier(&chip->nb);
@@ -1031,21 +1012,23 @@ cleanup:
return rc;
}
-static void pl_deinit(void)
+void qcom_batt_deinit(void)
{
struct pl_data *chip = the_chip;
+ if (chip == NULL)
+ return;
+
+ cancel_work_sync(&chip->status_change_work);
+ cancel_delayed_work_sync(&chip->pl_taper_work);
+ cancel_work_sync(&chip->pl_disable_forever_work);
+
power_supply_unreg_notifier(&chip->nb);
destroy_votable(chip->pl_awake_votable);
destroy_votable(chip->pl_disable_votable);
destroy_votable(chip->fv_votable);
destroy_votable(chip->fcc_votable);
wakeup_source_unregister(chip->pl_ws);
+ the_chip = NULL;
kfree(chip);
}
-
-module_init(pl_init);
-module_exit(pl_deinit)
-
-MODULE_DESCRIPTION("");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h
new file mode 100644
index 000000000000..38626e733a09
--- /dev/null
+++ b/drivers/power/supply/qcom/battery.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __BATTERY_H
+#define __BATTERY_H
+int qcom_batt_init(void);
+void qcom_batt_deinit(void);
+#endif /* __BATTERY_H */
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 8855a1c74e0b..024c968e484a 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -238,11 +238,9 @@ static struct smb_params pm660_params = {
#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
- int fcc_ua;
int usb_icl_ua;
int dc_icl_ua;
int boost_threshold_ua;
- int fv_uv;
int wipower_max_uw;
int min_freq_khz;
int max_freq_khz;
@@ -310,14 +308,14 @@ static int smb2_parse_dt(struct smb2 *chip)
"qcom,external-vconn");
rc = of_property_read_u32(node,
- "qcom,fcc-max-ua", &chip->dt.fcc_ua);
+ "qcom,fcc-max-ua", &chg->batt_profile_fcc_ua);
if (rc < 0)
- chip->dt.fcc_ua = -EINVAL;
+ chg->batt_profile_fcc_ua = -EINVAL;
rc = of_property_read_u32(node,
- "qcom,fv-max-uv", &chip->dt.fv_uv);
+ "qcom,fv-max-uv", &chg->batt_profile_fv_uv);
if (rc < 0)
- chip->dt.fv_uv = -EINVAL;
+ chg->batt_profile_fv_uv = -EINVAL;
rc = of_property_read_u32(node,
"qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
@@ -619,7 +617,7 @@ static int smb2_init_usb_psy(struct smb2 *chip)
usb_cfg.drv_data = chip;
usb_cfg.of_node = chg->dev->of_node;
- chg->usb_psy = devm_power_supply_register(chg->dev,
+ chg->usb_psy = power_supply_register(chg->dev,
&chg->usb_psy_desc,
&usb_cfg);
if (IS_ERR(chg->usb_psy)) {
@@ -677,7 +675,7 @@ static int smb2_usb_main_get_prop(struct power_supply *psy,
rc = smblib_get_prop_fcc_delta(chg, val);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = get_effective_result(chg->usb_icl_votable);
+ rc = smblib_get_icl_current(chg, &val->intval);
break;
default:
pr_debug("get prop %d is not supported in usb-main\n", psp);
@@ -734,7 +732,7 @@ static int smb2_init_usb_main_psy(struct smb2 *chip)
usb_main_cfg.drv_data = chip;
usb_main_cfg.of_node = chg->dev->of_node;
- chg->usb_main_psy = devm_power_supply_register(chg->dev,
+ chg->usb_main_psy = power_supply_register(chg->dev,
&usb_main_psy_desc,
&usb_main_cfg);
if (IS_ERR(chg->usb_main_psy)) {
@@ -836,7 +834,7 @@ static int smb2_init_dc_psy(struct smb2 *chip)
dc_cfg.drv_data = chip;
dc_cfg.of_node = chg->dev->of_node;
- chg->dc_psy = devm_power_supply_register(chg->dev,
+ chg->dc_psy = power_supply_register(chg->dev,
&dc_psy_desc,
&dc_cfg);
if (IS_ERR(chg->dc_psy)) {
@@ -942,13 +940,15 @@ static int smb2_batt_get_prop(struct power_supply *psy,
rc = smblib_get_prop_charge_qnovo_enable(chg, val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
- val->intval = chg->qnovo_fv_uv;
+ val->intval = get_client_vote_locked(chg->fv_votable,
+ QNOVO_VOTER);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
rc = smblib_get_prop_batt_current_now(chg, val);
break;
case POWER_SUPPLY_PROP_CURRENT_QNOVO:
- val->intval = chg->qnovo_fcc_ua;
+ val->intval = get_client_vote_locked(chg->fcc_votable,
+ QNOVO_VOTER);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = get_client_vote(chg->fcc_votable,
@@ -1014,23 +1014,37 @@ static int smb2_batt_set_prop(struct power_supply *psy,
vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
+ chg->batt_profile_fv_uv = val->intval;
+ vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
break;
case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
rc = smblib_set_prop_charge_qnovo_enable(chg, val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
- chg->qnovo_fv_uv = val->intval;
- rc = rerun_election(chg->fv_votable);
+ if (val->intval == -EINVAL) {
+ vote(chg->fv_votable, BATT_PROFILE_VOTER,
+ true, chg->batt_profile_fv_uv);
+ vote(chg->fv_votable, QNOVO_VOTER, false, 0);
+ } else {
+ vote(chg->fv_votable, QNOVO_VOTER, true, val->intval);
+ vote(chg->fv_votable, BATT_PROFILE_VOTER, false, 0);
+ }
break;
case POWER_SUPPLY_PROP_CURRENT_QNOVO:
- chg->qnovo_fcc_ua = val->intval;
vote(chg->pl_disable_votable, PL_QNOVO_VOTER,
val->intval != -EINVAL && val->intval < 2000000, 0);
- rc = rerun_election(chg->fcc_votable);
+ if (val->intval == -EINVAL) {
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER,
+ true, chg->batt_profile_fcc_ua);
+ vote(chg->fcc_votable, QNOVO_VOTER, false, 0);
+ } else {
+ vote(chg->fcc_votable, QNOVO_VOTER, true, val->intval);
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0);
+ }
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- vote(chg->fcc_votable, DEFAULT_VOTER, true, val->intval);
+ chg->batt_profile_fcc_ua = val->intval;
+ vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as the device is active */
@@ -1090,7 +1104,7 @@ static int smb2_init_batt_psy(struct smb2 *chip)
batt_cfg.drv_data = chg;
batt_cfg.of_node = chg->dev->of_node;
- chg->batt_psy = devm_power_supply_register(chg->dev,
+ chg->batt_psy = power_supply_register(chg->dev,
&batt_psy_desc,
&batt_cfg);
if (IS_ERR(chg->batt_psy)) {
@@ -1447,11 +1461,13 @@ static int smb2_init_hw(struct smb2 *chip)
if (chip->dt.no_battery)
chg->fake_capacity = 50;
- if (chip->dt.fcc_ua < 0)
- smblib_get_charge_param(chg, &chg->param.fcc, &chip->dt.fcc_ua);
+ if (chg->batt_profile_fcc_ua < 0)
+ smblib_get_charge_param(chg, &chg->param.fcc,
+ &chg->batt_profile_fcc_ua);
- if (chip->dt.fv_uv < 0)
- smblib_get_charge_param(chg, &chg->param.fv, &chip->dt.fv_uv);
+ if (chg->batt_profile_fv_uv < 0)
+ smblib_get_charge_param(chg, &chg->param.fv,
+ &chg->batt_profile_fv_uv);
smblib_get_charge_param(chg, &chg->param.usb_icl,
&chg->default_icl_ua);
@@ -1512,9 +1528,9 @@ static int smb2_init_hw(struct smb2 *chip)
vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->fcc_votable,
- DEFAULT_VOTER, true, chip->dt.fcc_ua);
+ BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua);
vote(chg->fv_votable,
- DEFAULT_VOTER, true, chip->dt.fv_uv);
+ BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv);
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
@@ -2058,6 +2074,21 @@ static int smb2_request_interrupts(struct smb2 *chip)
return rc;
}
+static void smb2_free_interrupts(struct smb_charger *chg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+ if (smb2_irqs[i].irq > 0) {
+ if (smb2_irqs[i].wake)
+ disable_irq_wake(smb2_irqs[i].irq);
+
+ devm_free_irq(chg->dev, smb2_irqs[i].irq,
+ smb2_irqs[i].irq_data);
+ }
+ }
+}
+
static void smb2_disable_interrupts(struct smb_charger *chg)
{
int i;
@@ -2298,15 +2329,22 @@ static int smb2_probe(struct platform_device *pdev)
return rc;
cleanup:
- smblib_deinit(chg);
- if (chg->usb_psy)
- power_supply_unregister(chg->usb_psy);
+ smb2_free_interrupts(chg);
if (chg->batt_psy)
power_supply_unregister(chg->batt_psy);
+ if (chg->usb_main_psy)
+ power_supply_unregister(chg->usb_main_psy);
+ if (chg->usb_psy)
+ power_supply_unregister(chg->usb_psy);
+ if (chg->dc_psy)
+ power_supply_unregister(chg->dc_psy);
if (chg->vconn_vreg && chg->vconn_vreg->rdev)
- regulator_unregister(chg->vconn_vreg->rdev);
+ devm_regulator_unregister(chg->dev, chg->vconn_vreg->rdev);
if (chg->vbus_vreg && chg->vbus_vreg->rdev)
- regulator_unregister(chg->vbus_vreg->rdev);
+ devm_regulator_unregister(chg->dev, chg->vbus_vreg->rdev);
+
+ smblib_deinit(chg);
+
platform_set_drvdata(pdev, NULL);
return rc;
}
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 2d33ab502365..ecfb532e5b3c 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -19,10 +19,11 @@
#include <linux/qpnp/qpnp-revid.h>
#include <linux/input/qpnp-power-on.h>
#include <linux/irq.h>
+#include <linux/pmic-voter.h>
#include "smb-lib.h"
#include "smb-reg.h"
+#include "battery.h"
#include "storm-watch.h"
-#include <linux/pmic-voter.h>
#define smblib_err(chg, fmt, ...) \
pr_err("%s: %s: " fmt, chg->name, \
@@ -813,6 +814,28 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua)
return rc;
}
+static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
+{
+ int rc;
+ u8 icl_options;
+ bool usb3 = false;
+
+ rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
+ return rc;
+ }
+
+ usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
+
+ if (icl_options & USB51_MODE_BIT)
+ *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
+ else
+ *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
+
+ return rc;
+}
+
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{
int rc = 0;
@@ -890,6 +913,48 @@ enable_icl_changed_interrupt:
return rc;
}
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
+{
+ int rc = 0;
+ u8 load_cfg;
+ bool override;
+ union power_supply_propval pval;
+
+ rc = smblib_get_prop_typec_mode(chg, &pval);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
+ return rc;
+ }
+
+ if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ || chg->micro_usb_mode)
+ && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+ rc = get_sdp_current(chg, icl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
+ return rc;
+ }
+ override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
+ if (!override)
+ return INT_MAX;
+
+ /* override is set */
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
/*********************
* VOTABLE CALLBACKS *
*********************/
@@ -3088,12 +3153,28 @@ static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
}
}
-static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
{
+ int rc;
+ u8 stat;
+ bool vbus_rising;
+
+ rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ return;
+ }
+
+ vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+
if (vbus_rising)
smblib_cc2_sink_removal_exit(chg);
else
smblib_cc2_sink_removal_enter(chg);
+
+ power_supply_changed(chg->usb_psy);
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+ vbus_rising ? "attached" : "detached");
}
#define PL_DELAY_MS 30000
@@ -3152,8 +3233,6 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
if (chg->micro_usb_mode)
smblib_micro_usb_plugin(chg, vbus_rising);
- else
- smblib_typec_usb_plugin(chg, vbus_rising);
power_supply_changed(chg->usb_psy);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
@@ -3166,7 +3245,10 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
struct smb_charger *chg = irq_data->parent_data;
mutex_lock(&chg->lock);
- smblib_usb_plugin_locked(chg);
+ if (chg->pd_hard_reset)
+ smblib_usb_plugin_hard_reset_locked(chg);
+ else
+ smblib_usb_plugin_locked(chg);
mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -4187,26 +4269,30 @@ static int smblib_create_votables(struct smb_charger *chg)
int rc = 0;
chg->fcc_votable = find_votable("FCC");
- if (!chg->fcc_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->fcc_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
return rc;
}
chg->fv_votable = find_votable("FV");
- if (!chg->fv_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->fv_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
return rc;
}
chg->usb_icl_votable = find_votable("USB_ICL");
if (!chg->usb_icl_votable) {
- rc = -EPROBE_DEFER;
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
return rc;
}
chg->pl_disable_votable = find_votable("PL_DISABLE");
- if (!chg->pl_disable_votable) {
- rc = -EPROBE_DEFER;
+ if (chg->pl_disable_votable == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
return rc;
}
vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
@@ -4388,8 +4474,13 @@ int smblib_init(struct smb_charger *chg)
switch (chg->mode) {
case PARALLEL_MASTER:
- chg->qnovo_fcc_ua = -EINVAL;
- chg->qnovo_fv_uv = -EINVAL;
+ rc = qcom_batt_init();
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
+ rc);
+ return rc;
+ }
+
rc = smblib_create_votables(chg);
if (rc < 0) {
smblib_err(chg, "Couldn't create votables rc=%d\n",
@@ -4421,8 +4512,20 @@ int smblib_deinit(struct smb_charger *chg)
{
switch (chg->mode) {
case PARALLEL_MASTER:
+ cancel_work_sync(&chg->bms_update_work);
+ cancel_work_sync(&chg->rdstd_cc2_detach_work);
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+ cancel_delayed_work_sync(&chg->step_soc_req_work);
+ cancel_delayed_work_sync(&chg->clear_hdc_work);
+ cancel_work_sync(&chg->otg_oc_work);
+ cancel_work_sync(&chg->vconn_oc_work);
+ cancel_delayed_work_sync(&chg->otg_ss_done_work);
+ cancel_delayed_work_sync(&chg->icl_change_work);
+ cancel_delayed_work_sync(&chg->pl_enable_work);
+ cancel_work_sync(&chg->legacy_detection_work);
power_supply_unreg_notifier(&chg->nb);
smblib_destroy_votables(chg);
+ qcom_batt_deinit();
break;
case PARALLEL_SLAVE:
break;
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index b0d84f014b0d..d14ea86bf0c6 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -62,6 +62,8 @@ enum print_reason {
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER"
#define CC2_WA_VOTER "CC2_WA_VOTER"
+#define QNOVO_VOTER "QNOVO_VOTER"
+#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -325,9 +327,11 @@ struct smb_charger {
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
+ /* battery profile */
+ int batt_profile_fcc_ua;
+ int batt_profile_fv_uv;
+
/* qnovo */
- int qnovo_fcc_ua;
- int qnovo_fv_uv;
int usb_icl_delta_ua;
int pulse_cnt;
};
@@ -493,6 +497,7 @@ int smblib_icl_override(struct smb_charger *chg, bool override);
int smblib_dp_dm(struct smb_charger *chg, int val);
int smblib_rerun_aicl(struct smb_charger *chg);
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
int smblib_init(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 4e710cae6b78..e4a876126444 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -598,6 +598,26 @@ static enum power_supply_property smb1355_parallel_props[] = {
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
};
+static int smb138x_get_parallel_charging(struct smb138x *chip, int *disabled)
+{
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+ u8 cfg2;
+
+ rc = smblib_read(chg, CHGR_CFG2_REG, &cfg2);
+ if (rc < 0) {
+ pr_err("Couldn't read en_cmg_reg rc=%d\n", rc);
+ return rc;
+ }
+
+ if (cfg2 & CHG_EN_SRC_BIT)
+ *disabled = 0;
+ else
+ *disabled = 1;
+
+ return 0;
+}
+
static int smb138x_parallel_get_prop(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
@@ -624,7 +644,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
val->intval = !(temp & DISABLE_CHARGING_BIT);
break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smblib_get_usb_suspend(chg, &val->intval);
+ rc = smb138x_get_parallel_charging(chip, &val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -694,28 +714,33 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
return rc;
}
-static int smb138x_set_parallel_suspend(struct smb138x *chip, bool suspend)
+static int smb138x_set_parallel_charging(struct smb138x *chip, bool disable)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT,
- suspend ? 0 : WDOG_TIMER_EN_BIT);
+ disable ? 0 : WDOG_TIMER_EN_BIT);
if (rc < 0) {
pr_err("Couldn't %s watchdog rc=%d\n",
- suspend ? "disable" : "enable", rc);
- suspend = true;
+ disable ? "disable" : "enable", rc);
+ disable = true;
}
- rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
- suspend ? USBIN_SUSPEND_BIT : 0);
+ /*
+ * Configure charge enable for high polarity and
+ * When disabling charging set it to cmd register control(cmd bit=0)
+ * When enabling charging set it to pin control
+ */
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+ CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT,
+ disable ? 0 : CHG_EN_SRC_BIT);
if (rc < 0) {
- pr_err("Couldn't %s parallel charger rc=%d\n",
- suspend ? "suspend" : "resume", rc);
+ pr_err("Couldn't configure charge enable source rc=%d\n", rc);
return rc;
}
- return rc;
+ return 0;
}
static int smb138x_parallel_set_prop(struct power_supply *psy,
@@ -728,7 +753,7 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
switch (prop) {
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smb138x_set_parallel_suspend(chip, (bool)val->intval);
+ rc = smb138x_set_parallel_charging(chip, (bool)val->intval);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -946,35 +971,32 @@ static int smb138x_init_slave_hw(struct smb138x *chip)
return rc;
}
- /* suspend parallel charging */
- rc = smb138x_set_parallel_suspend(chip, true);
+ /* disable the charging path when under s/w control */
+ rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT, 0);
if (rc < 0) {
- pr_err("Couldn't suspend parallel charging rc=%d\n", rc);
+ pr_err("Couldn't disable charging rc=%d\n", rc);
return rc;
}
- /* initialize FCC to 0 */
- rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
+ /* disable parallel charging path */
+ rc = smb138x_set_parallel_charging(chip, true);
if (rc < 0) {
- pr_err("Couldn't set 0 FCC rc=%d\n", rc);
+ pr_err("Couldn't disable parallel path rc=%d\n", rc);
return rc;
}
- /* enable the charging path */
- rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
- CHARGING_ENABLE_CMD_BIT,
- CHARGING_ENABLE_CMD_BIT);
+ /* unsuspend parallel charging */
+ rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, 0);
if (rc < 0) {
- pr_err("Couldn't enable charging rc=%d\n", rc);
+ pr_err("Couldn't unsuspend parallel charging rc=%d\n", rc);
return rc;
}
- /* configure charge enable for software control; active high */
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
+ /* initialize FCC to 0 */
+ rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
if (rc < 0) {
- pr_err("Couldn't configure charge enable source rc=%d\n",
- rc);
+ pr_err("Couldn't set 0 FCC rc=%d\n", rc);
return rc;
}
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index 128ea434dcc8..a275537d4e08 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -514,19 +514,19 @@ struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
mutex_unlock(&svc->m_lock);
return NULL;
}
- if (!svc->port_cnt && !svc->svc_cnt)
+ if (!svc->svc_cnt)
clnt->svc_cnt++;
svc->port_cnt++;
svc->port_fn[temp_port] = svc_fn;
svc->port_priv[temp_port] = priv;
+ svc->svc_cnt++;
} else {
if (!svc->fn) {
- if (!svc->port_cnt && !svc->svc_cnt)
+ if (!svc->svc_cnt)
clnt->svc_cnt++;
svc->fn = svc_fn;
- if (svc->port_cnt)
- svc->svc_cnt++;
svc->priv = priv;
+ svc->svc_cnt++;
}
}
@@ -745,29 +745,28 @@ int apr_deregister(void *handle)
if (!handle)
return -EINVAL;
+ if (!svc->svc_cnt) {
+ pr_err("%s: svc already deregistered. svc = %pK\n",
+ __func__, svc);
+ return -EINVAL;
+ }
+
mutex_lock(&svc->m_lock);
dest_id = svc->dest_id;
client_id = svc->client_id;
clnt = &client[dest_id][client_id];
- if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+ if (svc->svc_cnt > 0) {
if (svc->port_cnt)
svc->port_cnt--;
- else if (svc->svc_cnt)
- svc->svc_cnt--;
- if (!svc->port_cnt && !svc->svc_cnt) {
+ svc->svc_cnt--;
+ if (!svc->svc_cnt) {
client[dest_id][client_id].svc_cnt--;
- svc->need_reset = 0x0;
- }
- } else if (client[dest_id][client_id].svc_cnt > 0) {
- client[dest_id][client_id].svc_cnt--;
- if (!client[dest_id][client_id].svc_cnt) {
- svc->need_reset = 0x0;
pr_debug("%s: service is reset %pK\n", __func__, svc);
}
}
- if (!svc->port_cnt && !svc->svc_cnt) {
+ if (!svc->svc_cnt) {
svc->priv = NULL;
svc->id = 0;
svc->fn = NULL;
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index d3d0b8594c9f..51f4ec79db10 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.c
@@ -480,15 +480,19 @@ static void send_sysmon_notif(struct subsys_device *dev)
mutex_unlock(&subsys_list_lock);
}
-static void for_each_subsys_device(struct subsys_device **list, unsigned count,
- void *data, void (*fn)(struct subsys_device *, void *))
+static int for_each_subsys_device(struct subsys_device **list, unsigned count,
+ void *data, int (*fn)(struct subsys_device *, void *))
{
+ int ret;
while (count--) {
struct subsys_device *dev = *list++;
if (!dev)
continue;
- fn(dev, data);
+ ret = fn(dev, data);
+ if (ret)
+ return ret;
}
+ return 0;
}
static void notify_each_subsys_device(struct subsys_device **list,
@@ -590,21 +594,31 @@ static int wait_for_err_ready(struct subsys_device *subsys)
return 0;
}
-static void subsystem_shutdown(struct subsys_device *dev, void *data)
+static int subsystem_shutdown(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
+ int ret;
pr_info("[%s:%d]: Shutting down %s\n",
current->comm, current->pid, name);
- if (dev->desc->shutdown(dev->desc, true) < 0)
- panic("subsys-restart: [%s:%d]: Failed to shutdown %s!",
- current->comm, current->pid, name);
+ ret = dev->desc->shutdown(dev->desc, true);
+ if (ret < 0) {
+ if (!dev->desc->ignore_ssr_failure) {
+ panic("subsys-restart: [%s:%d]: Failed to shutdown %s!",
+ current->comm, current->pid, name);
+ } else {
+ pr_err("Shutdown failure on %s\n", name);
+ return ret;
+ }
+ }
dev->crash_count++;
subsys_set_state(dev, SUBSYS_OFFLINE);
disable_all_irqs(dev);
+
+ return 0;
}
-static void subsystem_ramdump(struct subsys_device *dev, void *data)
+static int subsystem_ramdump(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
@@ -613,15 +627,17 @@ static void subsystem_ramdump(struct subsys_device *dev, void *data)
pr_warn("%s[%s:%d]: Ramdump failed.\n",
name, current->comm, current->pid);
dev->do_ramdump_on_put = false;
+ return 0;
}
-static void subsystem_free_memory(struct subsys_device *dev, void *data)
+static int subsystem_free_memory(struct subsys_device *dev, void *data)
{
if (dev->desc->free_memory)
dev->desc->free_memory(dev->desc);
+ return 0;
}
-static void subsystem_powerup(struct subsys_device *dev, void *data)
+static int subsystem_powerup(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
int ret;
@@ -629,11 +645,17 @@ static void subsystem_powerup(struct subsys_device *dev, void *data)
pr_info("[%s:%d]: Powering up %s\n", current->comm, current->pid, name);
init_completion(&dev->err_ready);
- if (dev->desc->powerup(dev->desc) < 0) {
+ ret = dev->desc->powerup(dev->desc);
+ if (ret < 0) {
notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
NULL);
- panic("[%s:%d]: Powerup error: %s!",
- current->comm, current->pid, name);
+ if (!dev->desc->ignore_ssr_failure) {
+ panic("[%s:%d]: Powerup error: %s!",
+ current->comm, current->pid, name);
+ } else {
+ pr_err("Powerup failure on %s\n", name);
+ return ret;
+ }
}
enable_all_irqs(dev);
@@ -641,11 +663,16 @@ static void subsystem_powerup(struct subsys_device *dev, void *data)
if (ret) {
notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
NULL);
- panic("[%s:%d]: Timed out waiting for error ready: %s!",
- current->comm, current->pid, name);
+ if (!dev->desc->ignore_ssr_failure)
+ panic("[%s:%d]: Timed out waiting for error ready: %s!",
+ current->comm, current->pid, name);
+ else
+ return ret;
}
subsys_set_state(dev, SUBSYS_ONLINE);
subsys_set_crash_status(dev, CRASH_STATUS_NO_CRASH);
+
+ return 0;
}
static int __find_subsys(struct device *dev, void *data)
@@ -907,6 +934,7 @@ static void subsystem_restart_wq_func(struct work_struct *work)
struct subsys_tracking *track;
unsigned count;
unsigned long flags;
+ int ret;
/*
* It's OK to not take the registration lock at this point.
@@ -954,7 +982,9 @@ static void subsystem_restart_wq_func(struct work_struct *work)
pr_debug("[%s:%d]: Starting restart sequence for %s\n",
current->comm, current->pid, desc->name);
notify_each_subsys_device(list, count, SUBSYS_BEFORE_SHUTDOWN, NULL);
- for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+ ret = for_each_subsys_device(list, count, NULL, subsystem_shutdown);
+ if (ret)
+ goto err;
notify_each_subsys_device(list, count, SUBSYS_AFTER_SHUTDOWN, NULL);
notify_each_subsys_device(list, count, SUBSYS_RAMDUMP_NOTIFICATION,
@@ -970,12 +1000,19 @@ static void subsystem_restart_wq_func(struct work_struct *work)
for_each_subsys_device(list, count, NULL, subsystem_free_memory);
notify_each_subsys_device(list, count, SUBSYS_BEFORE_POWERUP, NULL);
- for_each_subsys_device(list, count, NULL, subsystem_powerup);
+ ret = for_each_subsys_device(list, count, NULL, subsystem_powerup);
+ if (ret)
+ goto err;
notify_each_subsys_device(list, count, SUBSYS_AFTER_POWERUP, NULL);
pr_info("[%s:%d]: Restart sequence for %s completed.\n",
current->comm, current->pid, desc->name);
+err:
+ /* Reset subsys count */
+ if (ret)
+ dev->count = 0;
+
mutex_unlock(&soc_order_reg_lock);
mutex_unlock(&track->lock);
@@ -1466,6 +1503,9 @@ static int subsys_parse_devicetree(struct subsys_desc *desc)
desc->generic_irq = ret;
}
+ desc->ignore_ssr_failure = of_property_read_bool(pdev->dev.of_node,
+ "qcom,ignore-ssr-failure");
+
order = ssr_parse_restart_orders(desc);
if (IS_ERR(order)) {
pr_err("Could not initialize SSR restart order, err = %ld\n",
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 5bcff5d2cd8d..4ebd744434c6 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -167,6 +167,15 @@ static struct usb_endpoint_descriptor bulk_in_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+ .bLength = sizeof(ss_bulk_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /* the following 2 values can be tweaked if necessary */
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+};
+
/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
/* .bLength = DYNAMIC */
@@ -720,6 +729,7 @@ fail:
static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_descriptor_header **midi_function;
+ struct usb_descriptor_header **midi_ss_function;
struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS];
struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
@@ -727,7 +737,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct f_midi *midi = func_to_midi(f);
struct usb_string *us;
- int status, n, jack = 1, i = 0;
+ int status, n, jack = 1, i = 0, j = 0;
midi->gadget = cdev->gadget;
tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
@@ -767,11 +777,20 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
if (!midi->out_ep)
goto fail;
+ /* allocate temporary function list for ss */
+ midi_ss_function = kcalloc((MAX_PORTS * 4) + 11,
+ sizeof(*midi_ss_function), GFP_KERNEL);
+ if (!midi_ss_function) {
+ status = -ENOMEM;
+ goto fail;
+ }
+
/* allocate temporary function list */
midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
GFP_KERNEL);
if (!midi_function) {
status = -ENOMEM;
+ kfree(midi_ss_function);
goto fail;
}
@@ -785,6 +804,12 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ac_interface_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ac_header_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ms_interface_desc;
/* calculate the header's wTotalLength */
n = USB_DT_MS_HEADER_SIZE
@@ -793,6 +818,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
ms_header_desc.wTotalLength = cpu_to_le16(n);
midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ms_header_desc;
/* configure the external IN jacks, each linked to an embedded OUT jack */
for (n = 0; n < midi->in_ports; n++) {
@@ -806,6 +833,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
in_ext->bJackID = jack++;
in_ext->iJack = 0;
midi_function[i++] = (struct usb_descriptor_header *) in_ext;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) in_ext;
out_emb->bLength = USB_DT_MIDI_OUT_SIZE(1);
out_emb->bDescriptorType = USB_DT_CS_INTERFACE;
@@ -817,6 +845,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
out_emb->pins[0].baSourceID = in_ext->bJackID;
out_emb->iJack = 0;
midi_function[i++] = (struct usb_descriptor_header *) out_emb;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) out_emb;
/* link it to the endpoint */
ms_in_desc.baAssocJackID[n] = out_emb->bJackID;
@@ -834,6 +864,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
in_emb->bJackID = jack++;
in_emb->iJack = 0;
midi_function[i++] = (struct usb_descriptor_header *) in_emb;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) in_emb;
out_ext->bLength = USB_DT_MIDI_OUT_SIZE(1);
out_ext->bDescriptorType = USB_DT_CS_INTERFACE;
@@ -845,6 +876,8 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
out_ext->pins[0].baSourceID = in_emb->bJackID;
out_ext->pins[0].baSourcePin = 1;
midi_function[i++] = (struct usb_descriptor_header *) out_ext;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) out_ext;
/* link it to the endpoint */
ms_out_desc.baAssocJackID[n] = in_emb->bJackID;
@@ -864,6 +897,16 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
midi_function[i++] = NULL;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) &bulk_out_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ss_bulk_comp_desc;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) &ms_out_desc;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) &bulk_in_desc;
+ midi_ss_function[j++] =
+ (struct usb_descriptor_header *) &ss_bulk_comp_desc;
+ midi_ss_function[j++] = (struct usb_descriptor_header *) &ms_in_desc;
+ midi_ss_function[j++] = NULL;
+
/*
* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
@@ -882,13 +925,23 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
goto fail_f_midi;
}
+ if (gadget_is_superspeed(c->cdev->gadget)) {
+ bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024);
+ bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024);
+ f->ss_descriptors = usb_copy_descriptors(midi_ss_function);
+ if (!f->ss_descriptors)
+ goto fail_f_midi;
+ }
+
kfree(midi_function);
+ kfree(midi_ss_function);
return 0;
fail_f_midi:
kfree(midi_function);
usb_free_descriptors(f->hs_descriptors);
+ kfree(midi_ss_function);
fail:
f_midi_unregister_card(midi);
fail_register:
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ddba92d46eba..6cfef2760e09 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1677,6 +1677,9 @@ enum ieee80211_statuscode {
WLAN_STATUS_REJECT_DSE_BAND = 96,
WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
+ /* 802.11ai */
+ WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108,
+ WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109,
};
@@ -2038,6 +2041,12 @@ enum ieee80211_key_len {
#define FILS_NONCE_LEN 16
#define FILS_MAX_KEK_LEN 64
+#define FILS_ERP_MAX_USERNAME_LEN 16
+#define FILS_ERP_MAX_REALM_LEN 253
+#define FILS_ERP_MAX_RRK_LEN 64
+
+#define PMK_MAX_LEN 48
+
/* Public action codes */
enum ieee80211_pub_actioncode {
WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
@@ -2251,31 +2260,37 @@ enum ieee80211_sa_query_action {
};
+#define SUITE(oui, id) (((oui) << 8) | (id))
+
/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
-/* reserved: 0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
-#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
-#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09
-#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A
-#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
-#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
-#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
-
-#define WLAN_CIPHER_SUITE_SMS4 0x00147201
+#define WLAN_CIPHER_SUITE_USE_GROUP SUITE(0x000FAC, 0)
+#define WLAN_CIPHER_SUITE_WEP40 SUITE(0x000FAC, 1)
+#define WLAN_CIPHER_SUITE_TKIP SUITE(0x000FAC, 2)
+/* reserved: SUITE(0x000FAC, 3) */
+#define WLAN_CIPHER_SUITE_CCMP SUITE(0x000FAC, 4)
+#define WLAN_CIPHER_SUITE_WEP104 SUITE(0x000FAC, 5)
+#define WLAN_CIPHER_SUITE_AES_CMAC SUITE(0x000FAC, 6)
+#define WLAN_CIPHER_SUITE_GCMP SUITE(0x000FAC, 8)
+#define WLAN_CIPHER_SUITE_GCMP_256 SUITE(0x000FAC, 9)
+#define WLAN_CIPHER_SUITE_CCMP_256 SUITE(0x000FAC, 10)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_128 SUITE(0x000FAC, 11)
+#define WLAN_CIPHER_SUITE_BIP_GMAC_256 SUITE(0x000FAC, 12)
+#define WLAN_CIPHER_SUITE_BIP_CMAC_256 SUITE(0x000FAC, 13)
+
+#define WLAN_CIPHER_SUITE_SMS4 SUITE(0x001472, 1)
/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X 0x000FAC01
-#define WLAN_AKM_SUITE_PSK 0x000FAC02
-#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
-#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
-#define WLAN_AKM_SUITE_TDLS 0x000FAC07
-#define WLAN_AKM_SUITE_SAE 0x000FAC08
-#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09
+#define WLAN_AKM_SUITE_8021X SUITE(0x000FAC, 1)
+#define WLAN_AKM_SUITE_PSK SUITE(0x000FAC, 2)
+#define WLAN_AKM_SUITE_8021X_SHA256 SUITE(0x000FAC, 5)
+#define WLAN_AKM_SUITE_PSK_SHA256 SUITE(0x000FAC, 6)
+#define WLAN_AKM_SUITE_TDLS SUITE(0x000FAC, 7)
+#define WLAN_AKM_SUITE_SAE SUITE(0x000FAC, 8)
+#define WLAN_AKM_SUITE_FT_OVER_SAE SUITE(0x000FAC, 9)
+#define WLAN_AKM_SUITE_FILS_SHA256 SUITE(0x000FAC, 14)
+#define WLAN_AKM_SUITE_FILS_SHA384 SUITE(0x000FAC, 15)
+#define WLAN_AKM_SUITE_FT_FILS_SHA256 SUITE(0x000FAC, 16)
+#define WLAN_AKM_SUITE_FT_FILS_SHA384 SUITE(0x000FAC, 17)
#define WLAN_MAX_KEY_LEN 32
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 7488bb993d7a..aa8edf9928eb 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -247,6 +247,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+ POWER_SUPPLY_PROP_REAL_TYPE,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 216a4d281f14..3d11c7d26686 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -74,6 +74,11 @@ struct wiphy;
#define CFG80211_CONNECT_TIMEOUT 1
#define CFG80211_CONNECT_TIMEOUT_REASON_CODE 1
+/* Indicate backport support for the new connect done api */
+#define CFG80211_CONNECT_DONE 1
+/* Indicate backport support for FILS SK offload in cfg80211 */
+#define CFG80211_FILS_SK_OFFLOAD_SUPPORT 1
+
/*
* wireless hardware capability structures
*/
@@ -2000,7 +2005,20 @@ struct cfg80211_bss_selection {
* networks.
* @bss_select: criteria to be used for BSS selection.
* @prev_bssid: previous BSSID, if not %NULL use reassociate frame
- */
+ * @fils_erp_username: EAP re-authentication protocol (ERP) username part of the
+ * NAI or %NULL if not specified. This is used to construct FILS wrapped
+ * data IE.
+ * @fils_erp_username_len: Length of @fils_erp_username in octets.
+ * @fils_erp_realm: EAP re-authentication protocol (ERP) realm part of NAI or
+ * %NULL if not specified. This specifies the domain name of ER server and
+ * is used to construct FILS wrapped data IE.
+ * @fils_erp_realm_len: Length of @fils_erp_realm in octets.
+ * @fils_erp_next_seq_num: The next sequence number to use in the FILS ERP
+ * messages. This is also used to construct FILS wrapped data IE.
+ * @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
+ * keys in FILS or %NULL if not specified.
+ * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
+*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
struct ieee80211_channel *channel_hint;
@@ -2025,6 +2043,13 @@ struct cfg80211_connect_params {
bool pbss;
struct cfg80211_bss_selection bss_select;
const u8 *prev_bssid;
+ const u8 *fils_erp_username;
+ size_t fils_erp_username_len;
+ const u8 *fils_erp_realm;
+ size_t fils_erp_realm_len;
+ u16 fils_erp_next_seq_num;
+ const u8 *fils_erp_rrk;
+ size_t fils_erp_rrk_len;
};
/**
@@ -2063,12 +2088,27 @@ enum wiphy_params_flags {
* This structure is passed to the set/del_pmksa() method for PMKSA
* caching.
*
- * @bssid: The AP's BSSID.
- * @pmkid: The PMK material itself.
+ * @bssid: The AP's BSSID (may be %NULL).
+ * @pmkid: The identifier to refer a PMKSA.
+ * @pmk: The PMK for the PMKSA identified by @pmkid. This is used for key
+ * derivation by a FILS STA. Otherwise, %NULL.
+ * @pmk_len: Length of the @pmk. The length of @pmk can differ depending on
+ * the hash algorithm used to generate this.
+ * @ssid: SSID to specify the ESS within which a PMKSA is valid when using FILS
+ * cache identifier (may be %NULL).
+ * @ssid_len: Length of the @ssid in octets.
+ * @cache_id: 2-octet cache identifier advertized by a FILS AP identifying the
+ * scope of PMKSA. This is valid only if @ssid_len is non-zero (may be
+ * %NULL).
*/
struct cfg80211_pmksa {
const u8 *bssid;
const u8 *pmkid;
+ const u8 *pmk;
+ size_t pmk_len;
+ const u8 *ssid;
+ size_t ssid_len;
+ const u8 *cache_id;
};
/**
@@ -4828,6 +4868,78 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
#endif
/**
+ * struct cfg80211_connect_resp_params - Connection response params
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful connection, use
+ * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ * the real status code for failures. If this call is used to report a
+ * failure due to a timeout (e.g., not receiving an Authentication frame
+ * from the AP) instead of an explicit rejection by the AP, -1 is used to
+ * indicate that this is a failure, but without a status code.
+ * @timeout_reason is used to report the reason for the timeout in that
+ * case.
+ * @bssid: The BSSID of the AP (may be %NULL)
+ * @bss: Entry of bss to which STA got connected to, can be obtained through
+ * cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and
+ * @bss needs to be specified.
+ * @req_ie: Association request IEs (may be %NULL)
+ * @req_ie_len: Association request IEs length
+ * @resp_ie: Association response IEs (may be %NULL)
+ * @resp_ie_len: Association response IEs length
+ * @fils_kek: KEK derived from a successful FILS connection (may be %NULL)
+ * @fils_kek_len: Length of @fils_kek in octets
+ * @update_erp_next_seq_num: Boolean value to specify whether the value in
+ * @fils_erp_next_seq_num is valid.
+ * @fils_erp_next_seq_num: The next sequence number to use in ERP message in
+ * FILS Authentication. This value should be specified irrespective of the
+ * status for a FILS connection.
+ * @pmk: A new PMK if derived from a successful FILS connection (may be %NULL).
+ * @pmk_len: Length of @pmk in octets
+ * @pmkid: A new PMKID if derived from a successful FILS connection or the PMKID
+ * used for this FILS connection (may be %NULL).
+ * @timeout_reason: Reason for connection timeout. This is used when the
+ * connection fails due to a timeout instead of an explicit rejection from
+ * the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
+ * not known. This value is used only if @status < 0 to indicate that the
+ * failure is due to a timeout and not due to explicit rejection by the AP.
+ * This value is ignored in other cases (@status >= 0).
+ */
+struct cfg80211_connect_resp_params {
+ int status;
+ const u8 *bssid;
+ struct cfg80211_bss *bss;
+ const u8 *req_ie;
+ size_t req_ie_len;
+ const u8 *resp_ie;
+ size_t resp_ie_len;
+ const u8 *fils_kek;
+ size_t fils_kek_len;
+ bool update_erp_next_seq_num;
+ u16 fils_erp_next_seq_num;
+ const u8 *pmk;
+ size_t pmk_len;
+ const u8 *pmkid;
+ enum nl80211_timeout_reason timeout_reason;
+};
+
+/**
+ * cfg80211_connect_done - notify cfg80211 of connection result
+ *
+ * @dev: network device
+ * @params: connection response parameters
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver once execution of the connection
+ * request from connect() has been completed. This is similar to
+ * cfg80211_connect_bss(), but takes a structure pointer for connection response
+ * parameters. Only one of the functions among cfg80211_connect_bss(),
+ * cfg80211_connect_result(), cfg80211_connect_timeout(),
+ * and cfg80211_connect_done() should be called.
+ */
+void cfg80211_connect_done(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ gfp_t gfp);
+
+/**
* cfg80211_connect_bss - notify cfg80211 of connection result
*
* @dev: network device
@@ -4857,13 +4969,31 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
* It should be called by the underlying driver once execution of the connection
* request from connect() has been completed. This is similar to
* cfg80211_connect_result(), but with the option of identifying the exact bss
- * entry for the connection. Only one of these functions should be called.
+ * entry for the connection. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, int status, gfp_t gfp,
- enum nl80211_timeout_reason timeout_reason);
+static inline void
+cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
+ struct cfg80211_bss *bss, const u8 *req_ie,
+ size_t req_ie_len, const u8 *resp_ie,
+ size_t resp_ie_len, int status, gfp_t gfp,
+ enum nl80211_timeout_reason timeout_reason)
+{
+ struct cfg80211_connect_resp_params params;
+
+ memset(&params, 0, sizeof(params));
+ params.status = status;
+ params.bssid = bssid;
+ params.bss = bss;
+ params.req_ie = req_ie;
+ params.req_ie_len = req_ie_len;
+ params.resp_ie = resp_ie;
+ params.resp_ie_len = resp_ie_len;
+ params.timeout_reason = timeout_reason;
+
+ cfg80211_connect_done(dev, &params, gfp);
+}
/**
* cfg80211_connect_result - notify cfg80211 of connection result
@@ -4882,7 +5012,8 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
* It should be called by the underlying driver once execution of the connection
* request from connect() has been completed. This is similar to
* cfg80211_connect_bss() which allows the exact bss entry to be specified. Only
- * one of these functions should be called.
+ * one of the functions among cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
static inline void
cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -4909,7 +5040,9 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
* in a sequence where no explicit authentication/association rejection was
* received from the AP. This could happen, e.g., due to not being able to send
* out the Authentication or Association Request frame or timing out while
- * waiting for the response.
+ * waiting for the response. Only one of the functions among
+ * cfg80211_connect_bss(), cfg80211_connect_result(),
+ * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
*/
static inline void
cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h
index 59749210001a..b08cc7ded26e 100644
--- a/include/soc/qcom/subsystem_restart.h
+++ b/include/soc/qcom/subsystem_restart.h
@@ -56,6 +56,8 @@ struct module;
* @sysmon_shutdown_ret: Return value for the call to sysmon_send_shutdown
* @system_debug: If "set", triggers a device restart when the
* subsystem's wdog bite handler is invoked.
+ * @ignore_ssr_failure: SSR failures are usually fatal and results in panic. If
+ * set will ignore failure.
* @edge: GLINK logical name of the subsystem
*/
struct subsys_desc {
@@ -91,6 +93,7 @@ struct subsys_desc {
u32 sysmon_pid;
int sysmon_shutdown_ret;
bool system_debug;
+ bool ignore_ssr_failure;
const char *edge;
};
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h
index 758607226bfd..ad19e73ecb5d 100644
--- a/include/trace/events/clk.h
+++ b/include/trace/events/clk.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete,
TP_ARGS(core, phase)
);
+DECLARE_EVENT_CLASS(clk_state_dump,
+
+ TP_PROTO(const char *name, unsigned int prepare_count,
+ unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+ TP_ARGS(name, prepare_count, enable_count, rate, vdd_level),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(unsigned int, prepare_count)
+ __field(unsigned int, enable_count)
+ __field(unsigned long, rate)
+ __field(unsigned int, vdd_level)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->prepare_count = prepare_count;
+ __entry->enable_count = enable_count;
+ __entry->rate = rate;
+ __entry->vdd_level = vdd_level;
+ ),
+
+ TP_printk("%s\tprepare:enable cnt [%u:%u]\trate: vdd_level [%lu:%u]",
+ __get_str(name), __entry->prepare_count, __entry->enable_count,
+ __entry->rate, __entry->vdd_level)
+);
+
+DEFINE_EVENT(clk_state_dump, clk_state,
+
+ TP_PROTO(const char *name, unsigned int prepare_count,
+ unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+ TP_ARGS(name, prepare_count, enable_count, rate, vdd_level)
+);
+
#endif /* _TRACE_CLK_H */
/* This part must be outside protection */
diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h
index 57266ed29fb3..c0680f327073 100644
--- a/include/uapi/linux/esoc_ctrl.h
+++ b/include/uapi/linux/esoc_ctrl.h
@@ -7,6 +7,7 @@
#define ESOC_WAIT_FOR_REQ _IOR(ESOC_CODE, 2, unsigned int)
#define ESOC_NOTIFY _IOW(ESOC_CODE, 3, unsigned int)
#define ESOC_GET_STATUS _IOR(ESOC_CODE, 4, unsigned int)
+#define ESOC_GET_ERR_FATAL _IOR(ESOC_CODE, 5, unsigned int)
#define ESOC_WAIT_FOR_CRASH _IOR(ESOC_CODE, 6, unsigned int)
#define ESOC_REG_REQ_ENG _IO(ESOC_CODE, 7)
#define ESOC_REG_CMD_ENG _IO(ESOC_CODE, 8)
@@ -15,6 +16,7 @@
#define HSIC "HSIC"
#define HSICPCIe "HSIC+PCIe"
#define PCIe "PCIe"
+#define ESOC_REQ_SEND_SHUTDOWN ESOC_REQ_SEND_SHUTDOWN
enum esoc_evt {
ESOC_RUN_STATE = 0x1,
@@ -55,6 +57,7 @@ enum esoc_req {
ESOC_REQ_IMG = 1,
ESOC_REQ_DEBUG,
ESOC_REQ_SHUTDOWN,
+ ESOC_REQ_SEND_SHUTDOWN,
};
#ifdef __KERNEL__
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 960aa84e3b61..3dd0091f4af3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -172,6 +172,42 @@
*/
/**
+ * DOC: FILS shared key authentication offload
+ *
+ * FILS shared key authentication offload can be advertized by drivers by
+ * setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support
+ * FILS shared key authentication offload should be able to construct the
+ * authentication and association frames for FILS shared key authentication and
+ * eventually do a key derivation as per IEEE 802.11ai. The below additional
+ * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ * %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
+ * %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
+ * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
+ * %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK
+ * rIK should be used to generate an authentication tag on the ERP message and
+ * rMSK should be used to derive a PMKSA.
+ * rIK, rMSK should be generated and keyname_nai, sequence number should be used
+ * as specified in IETF RFC 6696.
+ *
+ * When FILS shared key authentication is completed, driver needs to provide the
+ * below additional parameters to userspace.
+ * %NL80211_ATTR_FILS_KEK - used for key renewal
+ * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
+ * %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
+ * %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace
+ * The PMKSA can be maintained in userspace persistently so that it can be used
+ * later after reboots or wifi turn off/on also.
+ *
+ * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS
+ * capable AP supporting PMK caching. It specifies the scope within which the
+ * PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and
+ * %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based
+ * on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with
+ * %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to
+ * use in a FILS shared key connection with PMKSA caching.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -369,10 +405,18 @@
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
* NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
*
- * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
- * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC
+ * (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK
+ * (PMK is used for PTKSA derivation in case of FILS shared key offload) or
+ * using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID,
+ * %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS
+ * authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier
+ * advertized by a FILS capable AP identifying the scope of PMKSA in an
+ * ESS.
* @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
- * (for the BSSID) and %NL80211_ATTR_PMKID.
+ * (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID,
+ * %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS
+ * authentication.
* @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
*
* @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
@@ -1965,6 +2009,31 @@ enum nl80211_commands {
* u32 attribute with an &enum nl80211_timeout_reason value. This is used,
* e.g., with %NL80211_CMD_CONNECT event.
*
+ * @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP)
+ * username part of NAI used to refer keys rRK and rIK. This is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part
+ * of NAI specifying the domain name of the ER server. This is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number
+ * to use in ERP messages. This is used in generating the FILS wrapped data
+ * for FILS authentication and is used with %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the
+ * NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and
+ * %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK
+ * from successful FILS authentication and is used with
+ * %NL80211_CMD_CONNECT.
+ *
+ * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP
+ * identifying the scope of PMKSAs. This is used with
+ * @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
+ *
+ * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
+ * This is used with @NL80211_CMD_SET_PMKSA.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2376,6 +2445,14 @@ enum nl80211_attrs {
NL80211_ATTR_TIMEOUT_REASON,
+ NL80211_ATTR_FILS_ERP_USERNAME,
+ NL80211_ATTR_FILS_ERP_REALM,
+ NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ NL80211_ATTR_FILS_ERP_RRK,
+ NL80211_ATTR_FILS_CACHE_ID,
+
+ NL80211_ATTR_PMK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3856,7 +3933,10 @@ enum nl80211_ps_state {
* @__NL80211_ATTR_CQM_INVALID: invalid
* @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
* the threshold for the RSSI level at which an event will be sent. Zero
- * to disable.
+ * to disable. Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is
+ * set, multiple values can be supplied as a low-to-high sorted array of
+ * threshold values in dBm. Events will be sent when the RSSI value
+ * crosses any of the thresholds.
* @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
* the minimum amount the RSSI level must change after an event before a
* new event may be issued (to reduce effects of RSSI oscillation).
@@ -4664,6 +4744,11 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
* for reporting BSSs with better RSSI than the current connected BSS
* (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
+ * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the
+ * %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more
+ * RSSI threshold values to monitor rather than exactly one threshold.
+ * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
+ * authentication with %NL80211_CMD_CONNECT.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4682,6 +4767,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
+ NL80211_EXT_FEATURE_CQM_RSSI_LIST,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5cfe6fd72d52..be5ab8c13a39 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -208,16 +208,7 @@ struct cfg80211_event {
enum cfg80211_event_type type;
union {
- struct {
- u8 bssid[ETH_ALEN];
- const u8 *req_ie;
- const u8 *resp_ie;
- size_t req_ie_len;
- size_t resp_ie_len;
- struct cfg80211_bss *bss;
- int status; /* -1 = failed; 0..65535 = status code */
- enum nl80211_timeout_reason timeout_reason;
- } cr;
+ struct cfg80211_connect_resp_params cr;
struct {
const u8 *req_ie;
const u8 *resp_ie;
@@ -373,12 +364,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
struct cfg80211_connect_params *connect,
struct cfg80211_cached_keys *connkeys,
const u8 *prev_bssid);
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, bool wextev,
- struct cfg80211_bss *bss,
- enum nl80211_timeout_reason timeout_reason);
+void __cfg80211_connect_result(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ bool wextev);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index e2b1333cc4e4..2bc6eaa766c7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -26,9 +26,16 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
- u8 *ie = mgmt->u.assoc_resp.variable;
- int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
- u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ cr.bssid = mgmt->bssid;
+ cr.bss = bss;
+ cr.resp_ie = mgmt->u.assoc_resp.variable;
+ cr.resp_ie_len =
+ len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+ cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
trace_cfg80211_send_rx_assoc(dev, bss);
@@ -38,7 +45,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
* and got a reject -- we only try again with an assoc
* frame instead of reassoc.
*/
- if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
+ if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
cfg80211_unhold_bss(bss_from_pub(bss));
cfg80211_put_bss(wiphy, bss);
return;
@@ -46,10 +53,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
/* update current_bss etc., consumes the bss reference */
- __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
- status_code,
- status_code == WLAN_STATUS_SUCCESS, bss,
- NL80211_TIMEOUT_UNSPECIFIED);
+ __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
}
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a03abbb1c9..d0d09c290ff8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -412,6 +412,15 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.len = FILS_MAX_KEK_LEN },
[NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
[NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
+ [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_USERNAME_LEN },
+ [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_REALM_LEN },
+ [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
+ [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
+ .len = FILS_ERP_MAX_RRK_LEN },
+ [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
+ [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
};
/* policy for the key attributes */
@@ -3656,6 +3665,19 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
return false;
return true;
case NL80211_CMD_CONNECT:
+ /* SAE not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_SAE)
+ return false;
+ /* FILS with SK PFS or PK not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
+ return false;
+ if (!wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ auth_type == NL80211_AUTHTYPE_FILS_SK)
+ return false;
+ return true;
case NL80211_CMD_START_AP:
/* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE)
@@ -8511,6 +8533,35 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
}
}
+ if (wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
+ info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ connect.fils_erp_username =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_username_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
+ connect.fils_erp_realm =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_realm_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
+ connect.fils_erp_next_seq_num =
+ nla_get_u16(
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
+ connect.fils_erp_rrk =
+ nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ connect.fils_erp_rrk_len =
+ nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
+ } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
+ info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
+ kzfree(connkeys);
+ return -EINVAL;
+ }
+
wdev_lock(dev->ieee80211_ptr);
err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
wdev_unlock(dev->ieee80211_ptr);
@@ -8616,14 +8667,28 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
- if (!info->attrs[NL80211_ATTR_MAC])
- return -EINVAL;
-
if (!info->attrs[NL80211_ATTR_PMKID])
return -EINVAL;
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
- pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_MAC]) {
+ pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ } else if (info->attrs[NL80211_ATTR_SSID] &&
+ info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
+ (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
+ info->attrs[NL80211_ATTR_PMK])) {
+ pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ pmksa.cache_id =
+ nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
+ } else {
+ return -EINVAL;
+ }
+ if (info->attrs[NL80211_ATTR_PMK]) {
+ pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+ pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
+ }
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
@@ -12276,17 +12341,16 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
}
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status,
- enum nl80211_timeout_reason timeout_reason,
+ struct net_device *netdev,
+ struct cfg80211_connect_resp_params *cr,
gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
- msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
+ msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
+ cr->fils_kek_len + cr->pmk_len +
+ (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
if (!msg)
return;
@@ -12298,17 +12362,31 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
+ (cr->bssid &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
- status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
- status) ||
- (status < 0 &&
+ cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
+ cr->status) ||
+ (cr->status < 0 &&
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
- nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
- (req_ie &&
- nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
- (resp_ie &&
- nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
+ nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
+ cr->timeout_reason))) ||
+ (cr->req_ie &&
+ nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
+ (cr->resp_ie &&
+ nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
+ cr->resp_ie)) ||
+ (cr->update_erp_next_seq_num &&
+ nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ cr->fils_erp_next_seq_num)) ||
+ (cr->status == WLAN_STATUS_SUCCESS &&
+ ((cr->fils_kek &&
+ nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
+ cr->fils_kek)) ||
+ (cr->pmk &&
+ nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
+ (cr->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
goto nla_put_failure;
genlmsg_end(msg, hdr);
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index a749c9be2836..79e9270d5067 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -52,11 +52,8 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *addr, gfp_t gfp);
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status,
- enum nl80211_timeout_reason timeout_reason,
+ struct net_device *netdev,
+ struct cfg80211_connect_resp_params *params,
gfp_t gfp);
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index fe8a9062de98..85c12c7d0ed1 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -276,10 +276,13 @@ void cfg80211_conn_work(struct work_struct *work)
}
treason = NL80211_TIMEOUT_UNSPECIFIED;
if (cfg80211_conn_do_work(wdev, &treason)) {
- __cfg80211_connect_result(
- wdev->netdev, bssid,
- NULL, 0, NULL, 0, -1, false, NULL,
- treason);
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = -1;
+ cr.bssid = bssid;
+ cr.timeout_reason = treason;
+ __cfg80211_connect_result(wdev->netdev, &cr, false);
}
wdev_unlock(wdev);
}
@@ -382,10 +385,13 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
schedule_work(&rdev->conn_work);
} else if (status_code != WLAN_STATUS_SUCCESS) {
- __cfg80211_connect_result(wdev->netdev, mgmt->bssid,
- NULL, 0, NULL, 0,
- status_code, false, NULL,
- NL80211_TIMEOUT_UNSPECIFIED);
+ struct cfg80211_connect_resp_params cr;
+
+ memset(&cr, 0, sizeof(cr));
+ cr.status = status_code;
+ cr.bssid = mgmt->bssid;
+ cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
+ __cfg80211_connect_result(wdev->netdev, &cr, false);
} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
schedule_work(&rdev->conn_work);
@@ -683,12 +689,9 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
*/
/* This method must consume bss one way or another */
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
- const u8 *req_ie, size_t req_ie_len,
- const u8 *resp_ie, size_t resp_ie_len,
- int status, bool wextev,
- struct cfg80211_bss *bss,
- enum nl80211_timeout_reason timeout_reason)
+void __cfg80211_connect_result(struct net_device *dev,
+ struct cfg80211_connect_resp_params *cr,
+ bool wextev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const u8 *country_ie;
@@ -700,48 +703,48 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, cr->bss);
return;
}
- nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
- bssid, req_ie, req_ie_len,
- resp_ie, resp_ie_len,
- status, timeout_reason, GFP_KERNEL);
+ nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
+ GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
if (wextev) {
- if (req_ie && status == WLAN_STATUS_SUCCESS) {
+ if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = req_ie_len;
- wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
+ wrqu.data.length = cr->req_ie_len;
+ wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
+ cr->req_ie);
}
- if (resp_ie && status == WLAN_STATUS_SUCCESS) {
+ if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = resp_ie_len;
- wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
+ wrqu.data.length = cr->resp_ie_len;
+ wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
+ cr->resp_ie);
}
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (bssid && status == WLAN_STATUS_SUCCESS) {
- memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
- memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
+ if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
+ memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
+ memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
wdev->wext.prev_bssid_valid = true;
}
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
#endif
- if (!bss && (status == WLAN_STATUS_SUCCESS)) {
+ if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
- bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
- wdev->ssid, wdev->ssid_len,
- wdev->conn_bss_type,
- IEEE80211_PRIVACY_ANY);
- if (bss)
- cfg80211_hold_bss(bss_from_pub(bss));
+ cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
+ wdev->ssid, wdev->ssid_len,
+ wdev->conn_bss_type,
+ IEEE80211_PRIVACY_ANY);
+ if (cr->bss)
+ cfg80211_hold_bss(bss_from_pub(cr->bss));
}
if (wdev->current_bss) {
@@ -750,27 +753,27 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
wdev->current_bss = NULL;
}
- if (status != WLAN_STATUS_SUCCESS) {
+ if (cr->status != WLAN_STATUS_SUCCESS) {
kzfree(wdev->connect_keys);
wdev->connect_keys = NULL;
wdev->ssid_len = 0;
- if (bss) {
- cfg80211_unhold_bss(bss_from_pub(bss));
- cfg80211_put_bss(wdev->wiphy, bss);
+ if (cr->bss) {
+ cfg80211_unhold_bss(bss_from_pub(cr->bss));
+ cfg80211_put_bss(wdev->wiphy, cr->bss);
}
cfg80211_sme_free(wdev);
return;
}
- if (WARN_ON(!bss))
+ if (WARN_ON(!cr->bss))
return;
- wdev->current_bss = bss_from_pub(bss);
+ wdev->current_bss = bss_from_pub(cr->bss);
cfg80211_upload_connect_keys(wdev);
rcu_read_lock();
- country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+ country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
if (!country_ie) {
rcu_read_unlock();
return;
@@ -787,64 +790,95 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
* - country_ie + 2, the start of the country ie data, and
* - and country_ie[1] which is the IE length
*/
- regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
+ regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
country_ie + 2, country_ie[1]);
kfree(country_ie);
}
/* Consumes bss object one way or another */
-void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
- struct cfg80211_bss *bss, const u8 *req_ie,
- size_t req_ie_len, const u8 *resp_ie,
- size_t resp_ie_len, int status, gfp_t gfp,
- enum nl80211_timeout_reason timeout_reason)
+void cfg80211_connect_done(struct net_device *dev,
+ struct cfg80211_connect_resp_params *params,
+ gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
unsigned long flags;
+ u8 *next;
- if (bss) {
+ if (params->bss) {
/* Make sure the bss entry provided by the driver is valid. */
- struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
+ struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
if (WARN_ON(list_empty(&ibss->list))) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, params->bss);
return;
}
}
- ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+ ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
+ params->req_ie_len + params->resp_ie_len +
+ params->fils_kek_len + params->pmk_len +
+ (params->pmkid ? WLAN_PMKID_LEN : 0), gfp);
if (!ev) {
- cfg80211_put_bss(wdev->wiphy, bss);
+ cfg80211_put_bss(wdev->wiphy, params->bss);
return;
}
ev->type = EVENT_CONNECT_RESULT;
- if (bssid)
- memcpy(ev->cr.bssid, bssid, ETH_ALEN);
- if (req_ie_len) {
- ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
- ev->cr.req_ie_len = req_ie_len;
- memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+ next = ((u8 *)ev) + sizeof(*ev);
+ if (params->bssid) {
+ ev->cr.bssid = next;
+ memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
+ next += ETH_ALEN;
}
- if (resp_ie_len) {
- ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
- ev->cr.resp_ie_len = resp_ie_len;
- memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+ if (params->req_ie_len) {
+ ev->cr.req_ie = next;
+ ev->cr.req_ie_len = params->req_ie_len;
+ memcpy((void *)ev->cr.req_ie, params->req_ie,
+ params->req_ie_len);
+ next += params->req_ie_len;
}
- if (bss)
- cfg80211_hold_bss(bss_from_pub(bss));
- ev->cr.bss = bss;
- ev->cr.status = status;
- ev->cr.timeout_reason = timeout_reason;
+ if (params->resp_ie_len) {
+ ev->cr.resp_ie = next;
+ ev->cr.resp_ie_len = params->resp_ie_len;
+ memcpy((void *)ev->cr.resp_ie, params->resp_ie,
+ params->resp_ie_len);
+ next += params->resp_ie_len;
+ }
+ if (params->fils_kek_len) {
+ ev->cr.fils_kek = next;
+ ev->cr.fils_kek_len = params->fils_kek_len;
+ memcpy((void *)ev->cr.fils_kek, params->fils_kek,
+ params->fils_kek_len);
+ next += params->fils_kek_len;
+ }
+ if (params->pmk_len) {
+ ev->cr.pmk = next;
+ ev->cr.pmk_len = params->pmk_len;
+ memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len);
+ next += params->pmk_len;
+ }
+ if (params->pmkid) {
+ ev->cr.pmkid = next;
+ memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN);
+ next += WLAN_PMKID_LEN;
+ }
+ ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num;
+ if (params->update_erp_next_seq_num)
+ ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num;
+ if (params->bss)
+ cfg80211_hold_bss(bss_from_pub(params->bss));
+ ev->cr.bss = params->bss;
+ ev->cr.status = params->status;
+ ev->cr.timeout_reason = params->timeout_reason;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
queue_work(cfg80211_wq, &rdev->event_work);
}
-EXPORT_SYMBOL(cfg80211_connect_bss);
+EXPORT_SYMBOL(cfg80211_connect_done);
/* Consumes bss object one way or another */
void __cfg80211_roamed(struct wireless_dev *wdev,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 305370cfd1e0..afdbc1200a1b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -858,7 +858,6 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
{
struct cfg80211_event *ev;
unsigned long flags;
- const u8 *bssid = NULL;
spin_lock_irqsave(&wdev->event_lock, flags);
while (!list_empty(&wdev->event_list)) {
@@ -870,15 +869,10 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
wdev_lock(wdev);
switch (ev->type) {
case EVENT_CONNECT_RESULT:
- if (!is_zero_ether_addr(ev->cr.bssid))
- bssid = ev->cr.bssid;
__cfg80211_connect_result(
- wdev->netdev, bssid,
- ev->cr.req_ie, ev->cr.req_ie_len,
- ev->cr.resp_ie, ev->cr.resp_ie_len,
- ev->cr.status,
- ev->cr.status == WLAN_STATUS_SUCCESS,
- ev->cr.bss, ev->cr.timeout_reason);
+ wdev->netdev,
+ &ev->cr,
+ ev->cr.status == WLAN_STATUS_SUCCESS);
break;
case EVENT_ROAMED:
__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index b969e842a7f9..0cf386a3c2fc 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1031,12 +1031,14 @@ void q6asm_audio_client_free(struct audio_client *ac)
}
rtac_set_asm_handle(ac->session, NULL);
- apr_deregister(ac->apr2);
- apr_deregister(ac->apr);
- q6asm_mmap_apr_dereg();
- ac->apr2 = NULL;
- ac->apr = NULL;
- ac->mmap_apr = NULL;
+ if (!atomic_read(&ac->reset)) {
+ apr_deregister(ac->apr2);
+ apr_deregister(ac->apr);
+ q6asm_mmap_apr_dereg();
+ ac->apr2 = NULL;
+ ac->apr = NULL;
+ ac->mmap_apr = NULL;
+ }
q6asm_session_free(ac);
pr_debug("%s: APR De-Register\n", __func__);
@@ -1507,7 +1509,6 @@ static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
}
pr_debug("%s: Clearing custom topology\n", __func__);
}
- this_mmap.apr = NULL;
cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
common_client.mmap_apr = NULL;
@@ -1708,8 +1709,10 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
if (data->opcode == RESET_EVENTS) {
mutex_lock(&ac->cmd_lock);
atomic_set(&ac->reset, 1);
- if (ac->apr == NULL)
+ if (ac->apr == NULL) {
ac->apr = ac->apr2;
+ ac->apr2 = NULL;
+ }
pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
__func__,
data->reset_event, data->reset_proc, ac->apr);
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 25691389f337..4340d31c218c 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -398,21 +398,23 @@ bool q6core_is_adsp_ready(void)
mutex_lock(&(q6core_lcl.cmd_lock));
ocm_core_open();
- q6core_lcl.bus_bw_resp_received = 0;
- rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
- if (rc < 0) {
- pr_err("%s: Get ADSP state APR packet send event %d\n",
- __func__, rc);
- goto bail;
- }
+ if (q6core_lcl.core_handle_q) {
+ q6core_lcl.bus_bw_resp_received = 0;
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+ if (rc < 0) {
+ pr_err("%s: Get ADSP state APR packet send event %d\n",
+ __func__, rc);
+ goto bail;
+ }
- rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
- (q6core_lcl.bus_bw_resp_received == 1),
- msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
- if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
- /* ensure to read updated param by callback thread */
- rmb();
- ret = !!q6core_lcl.param;
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+ if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+ /* ensure to read updated param by callback thread */
+ rmb();
+ ret = !!q6core_lcl.param;
+ }
}
bail:
pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);