Merge "ARM: dts: add device tree support for Hasting Genoa and Rome"
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
index 0d3c61a..c9cf528 100755
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -421,6 +421,7 @@
 CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_IPA=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index 2feaf40..b9df764 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -427,6 +427,7 @@
 CONFIG_UIO_MSM_SHAREDMEM=y
 CONFIG_STAGING=y
 CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_IPA=y
diff --git a/arch/arm64/boot/dts/qcom/msm-pm8909.dtsi b/arch/arm64/boot/dts/qcom/msm-pm8909.dtsi
index 87330d6..ab8435a 100644
--- a/arch/arm64/boot/dts/qcom/msm-pm8909.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-pm8909.dtsi
@@ -96,7 +96,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x0 0x31 0x0 0x0>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
@@ -142,9 +142,9 @@
 			reg = <0x3400 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts =	<0x0 0x34 0x0 0x0>,
-					<0x0 0x34 0x3 0x0>,
-					<0x0 0x34 0x4 0x0>;
+			interrupts =	<0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names =	"eoc-int-en-set",
 						"high-thr-en-set",
 						"low-thr-en-set";
@@ -198,6 +198,7 @@
 			qcom,tchg-mins = <232>;
 			qcom,chg-vadc = <&pm8909_vadc>;
 			qcom,chg-adc_tm = <&pm8909_adc_tm>;
+			#cooling-cells = <2>;
 
 			status = "okay";
 
@@ -244,6 +245,7 @@
 			qcom,channel-num = <8>;
 			qcom,threshold-set = <0>;
 			qcom,temp_alarm-vadc = <&pm8909_vadc>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		pm8909_bms: qcom,vmbms {
@@ -298,33 +300,6 @@
 		};
 	};
 
-
-	pm8909_temp_alarm: pm8909_tz {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "step_wise";
-		thermal-sensors = <&pm8909_tz>;
-		wake-capable-sensor;
-
-		trips {
-			pm8909_trip0: pm8909-trip0 {
-				temperature = <105000>;
-				hysteresis = <0>;
-				type = "passive";
-			};
-			pm8909_trip1: pm8909-trip1 {
-				temperature = <125000>;
-				hysteresis = <0>;
-				type = "passive";
-			};
-			pm8909_trip2: pm8909-trip2 {
-				temperature = <145000>;
-				hysteresis = <0>;
-				type = "critical";
-			};
-		};
-	};
-
 	pm8909_1: qcom,pm8909@1 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x1 0>;
@@ -576,3 +551,31 @@
 		};
 	};
 };
+
+&thermal_zones {
+	pm8909_temp_alarm: pm8909_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&pm8909_tz>;
+		wake-capable-sensor;
+
+		trips {
+			pm8909_trip0: pm8909-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8909_trip1: pm8909-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8909_trip2: pm8909-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8905-qrd-skub.dtsi b/arch/arm64/boot/dts/qcom/msm8905-qrd-skub.dtsi
index c053070..71007c8 100644
--- a/arch/arm64/boot/dts/qcom/msm8905-qrd-skub.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8905-qrd-skub.dtsi
@@ -133,11 +133,6 @@
 		};
 	};
 };
-&pm8909_vadc {
-	chan@30 {
-		qcom,scale-function = <6>;
-	};
-};
 
 &spmi_bus {
 	qcom,pm8909@0 {
@@ -213,6 +208,7 @@
 };
 
 &pm8909_vadc {
+	#thermal-sensor-cells = <1>;
 	chan@30 {
 		qcom,scale-function = <12>;
 	};
@@ -226,7 +222,7 @@
 		qcom,scale-function = <2>;
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
-		/*qcom,vadc-thermal-node;*/
+		qcom,vadc-thermal-node;
 	};
 };
 
@@ -367,6 +363,144 @@
 		};
 	};
 };
+&thermal_zones {
+	xo-therm-buf-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8909_vadc 0x3c>;
+		thermal-governor = "user_space";
+		wake-capable-sensor;
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8909_vadc 0x32>;
+		thermal-governor = "user_space";
+		wake-capable-sensor;
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm0-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8909_vadc 0x36>;
+		thermal-governor = "user_space";
+		wake-capable-sensor;
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	case-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8909_vadc 0x13>;
+		thermal-governor = "user_space";
+		wake-capable-sensor;
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	case-therm-adc-step {
+		polling-delay-passive = <1000>;
+		polling-delay = <10000>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&pm8909_vadc 0x13>;
+		wake-capable-sensor;
+		trips {
+			cpu_trip: cpu-trip {
+				temperature = <40000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			modem_trip0: modem-trip0 {
+				temperature = <42000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+			batt_trip0: batt-trip0 {
+				temperature = <44000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+			modem_trip1: modem-trip1 {
+				temperature = <46000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+			batt_trip1: batt-trip1 {
+				temperature = <47000>;
+				hysteresis = <3000>;
+				type = "passive";
+			};
+			cpu1_hotplug_trip: cpu1-hotplug-trip {
+				temperature = <55000>;
+				hysteresis = <4000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			skin_cpu0{
+				trip = <&cpu_trip>;
+				cooling-device =
+					<&CPU0 THERMAL_NO_LIMIT 2>;
+			};
+			skin_cpu1{
+				trip = <&cpu_trip>;
+				cooling-device =
+					<&CPU1 THERMAL_NO_LIMIT 2>;
+			};
+			modem_lvl1 {
+				trip = <&modem_trip0>;
+				cooling-device = <&modem_pa 1 1>;
+			};
+			modem_lvl2 {
+				trip = <&modem_trip1>;
+				cooling-device = <&modem_pa 2 2>;
+			};
+			hotplug_cpu1_cdev {
+				trip = <&cpu1_hotplug_trip>;
+				cooling-device = <&CPU1 THERMAL_MAX_LIMIT
+							THERMAL_MAX_LIMIT>;
+			};
+			battery_lvl1 {
+				trip = <&batt_trip0>;
+				cooling-device = <&pm8909_chg 1 1>;
+			};
+			battery_lvl2 {
+				trip = <&batt_trip1>;
+				cooling-device = <&pm8909_chg 2 2>;
+			};
+		};
+	};
+};
 
 &pm8909_1 {
 	pmic_analog_codec: analog-codec@f100 {
diff --git a/arch/arm64/boot/dts/qcom/msm8905.dtsi b/arch/arm64/boot/dts/qcom/msm8905.dtsi
index 2d2b502..6d5efb9 100644
--- a/arch/arm64/boot/dts/qcom/msm8905.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8905.dtsi
@@ -20,3 +20,25 @@
 	/* Disable GPU snapshot dumping */
 	qcom,snapshot-size = <0>;
 };
+
+&thermal_zones {
+	pop-mem-step {
+		status = "disabled";
+	};
+
+	cpu0-2-step {
+		trips {
+			cpu0-2-step-trip {
+				temperature = <80000>;
+			};
+		};
+	};
+
+	cpu1-3-step {
+		trips {
+			cpu1-3-step-trip {
+				temperature = <80000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-pm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909-pm8909.dtsi
index b7ae62b..4f59e2d 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-pm8909.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-pm8909.dtsi
@@ -20,6 +20,7 @@
 };
 
 &pm8909_vadc {
+	#thermal-sensor-cells = <1>;
 	chan@0 {
 		label = "usb_in";
 		reg = <0>;
@@ -117,7 +118,7 @@
 		qcom,scale-function = <2>;
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
-		/* qcom,vadc-thermal-node; */
+		qcom,vadc-thermal-node;
 	};
 
 	chan@32 {
@@ -129,7 +130,7 @@
 		qcom,scale-function = <4>;
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
-		/* qcom,vadc-thermal-node; */
+		qcom,vadc-thermal-node;
 	};
 
 	chan@3c {
@@ -141,7 +142,7 @@
 		qcom,scale-function = <4>;
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <0>;
-		/* qcom,vadc-thermal-node; */
+		qcom,vadc-thermal-node;
 	};
 };
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 107812f..2a88ae0 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -445,6 +445,9 @@
 	int ret = 0;
 	int retry_count = 0;
 
+	if (qseecom.support_bus_scaling)
+		return scm_call2(smc_id, desc);
+
 	do {
 		ret = scm_call2_noretry(smc_id, desc);
 		if (ret == -EBUSY) {
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 8f548691..9784f5f 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -42,6 +42,17 @@
 	  a 'cuttlefish' Android image inside QEmu. The driver interacts with
 	  a QEmu ivshmem device. If built as a module, it will be called vsoc.
 
+config ANDROID_LMK_NOTIFY_TRIGGER
+	bool "Android Low Memory Killer Notify Trigger"
+	depends on ANDROID_LOW_MEMORY_KILLER
+	default n
+	---help---
+	Create node "/sys/kernel/mm/lowmemkiller/notify_trigger_active",
+	on which an userspace application can poll for notification when
+	the number of free physical memory pages in the system falls below
+	a set threshold. The threshold is set by the new module parameter
+	"/sys/module/lowmemorykiller/parameters/notify_trigger".
+
 source "drivers/staging/android/ion/Kconfig"
 
 endif # if ANDROID
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 3973822..853601d 100755
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -92,6 +92,12 @@
 
 static unsigned long lowmem_deathpending_timeout;
 
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+static struct shrink_control lowmem_notif_sc = {GFP_KERNEL, 0};
+static int lowmem_minfree_notif_trigger;
+static struct kobject *lowmem_notify_kobj;
+#endif
+
 #define lowmem_print(level, x...)			\
 	do {						\
 		if (lowmem_debug_level >= (level))	\
@@ -582,6 +588,34 @@
 	}
 }
 
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+static void lowmem_notify_killzone_approach(void);
+
+static int get_free_ram(int *other_free, int *other_file,
+			struct shrink_control *sc)
+{
+	*other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
+
+	if (global_node_page_state(NR_SHMEM) + total_swapcache_pages() +
+			global_node_page_state(NR_UNEVICTABLE) <
+			global_node_page_state(NR_FILE_PAGES))
+		*other_file = global_node_page_state(NR_FILE_PAGES) -
+					global_node_page_state(NR_SHMEM) -
+					global_node_page_state(NR_UNEVICTABLE) -
+					total_swapcache_pages();
+	else
+		*other_file = 0;
+
+	tune_lmk_param(other_free, other_file, sc);
+
+	if (*other_free < lowmem_minfree_notif_trigger &&
+	    *other_file < lowmem_minfree_notif_trigger)
+		return 1;
+	else
+		return 0;
+}
+#endif
+
 static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
 {
 	struct task_struct *tsk;
@@ -601,6 +635,12 @@
 	if (!mutex_trylock(&scan_mutex))
 		return 0;
 
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+	lowmem_notif_sc.gfp_mask = sc->gfp_mask;
+
+	if (get_free_ram(&other_free, &other_file, sc))
+		lowmem_notify_killzone_approach();
+#else
 	other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
 
 	if (global_node_page_state(NR_SHMEM) + total_swapcache_pages() +
@@ -614,6 +654,7 @@
 		other_file = 0;
 
 	tune_lmk_param(&other_free, &other_file, sc);
+#endif
 
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
@@ -801,8 +842,74 @@
 	.seeks = DEFAULT_SEEKS * 16
 };
 
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+static void lowmem_notify_killzone_approach(void)
+{
+	lowmem_print(3, "notification trigger activated\n");
+	sysfs_notify(lowmem_notify_kobj, NULL,
+		     "notify_trigger_active");
+}
+
+static ssize_t lowmem_notify_trigger_active_show(struct kobject *k,
+						 struct kobj_attribute *attr,
+						 char *buf)
+{
+	int other_free, other_file;
+
+	if (get_free_ram(&other_free, &other_file, &lowmem_notif_sc))
+		return snprintf(buf, 3, "1\n");
+	else
+		return snprintf(buf, 3, "0\n");
+}
+
+static struct kobj_attribute lowmem_notify_trigger_active_attr =
+	__ATTR(notify_trigger_active, 0444,
+	       lowmem_notify_trigger_active_show, NULL);
+
+static struct attribute *lowmem_notify_default_attrs[] = {
+	&lowmem_notify_trigger_active_attr.attr, NULL,
+};
+
+static ssize_t lowmem_show(struct kobject *k, struct attribute *attr, char *buf)
+{
+	struct kobj_attribute *kobj_attr;
+
+	kobj_attr = container_of(attr, struct kobj_attribute, attr);
+	return kobj_attr->show(k, kobj_attr, buf);
+}
+
+static const struct sysfs_ops lowmem_notify_ops = {
+	.show = lowmem_show,
+};
+
+static void lowmem_notify_kobj_release(struct kobject *kobj)
+{
+	/* Nothing to be done here */
+}
+
+static struct kobj_type lowmem_notify_kobj_type = {
+	.release = lowmem_notify_kobj_release,
+	.sysfs_ops = &lowmem_notify_ops,
+	.default_attrs = lowmem_notify_default_attrs,
+};
+#endif
+
 static int __init lowmem_init(void)
 {
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+	int rc;
+
+	lowmem_notify_kobj = kzalloc(sizeof(*lowmem_notify_kobj), GFP_KERNEL);
+	if (!lowmem_notify_kobj)
+		return -ENOMEM;
+
+	rc = kobject_init_and_add(lowmem_notify_kobj, &lowmem_notify_kobj_type,
+				  mm_kobj, "lowmemkiller");
+	if (rc) {
+		kfree(lowmem_notify_kobj);
+		return rc;
+	}
+#endif
 	register_shrinker(&lowmem_shrinker);
 	vmpressure_notifier_register(&lmk_vmpr_nb);
 	lmk_event_init();
@@ -904,4 +1011,6 @@
 			 S_IRUGO | S_IWUSR);
 module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
 module_param_named(lmk_fast_run, lmk_fast_run, int, S_IRUGO | S_IWUSR);
-
+#ifdef CONFIG_ANDROID_LMK_NOTIFY_TRIGGER
+module_param_named(notify_trigger, lowmem_minfree_notif_trigger, uint, 0644);
+#endif
diff --git a/mm/memory.c b/mm/memory.c
index 6a939ae..cff4067 100755
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1146,6 +1146,9 @@
 			continue;
 		}
 
+		if (need_resched())
+			break;
+
 		if (pte_present(ptent)) {
 			struct page *page;
 
@@ -1227,8 +1230,11 @@
 			__tlb_remove_pte_page(tlb, pending_page);
 			pending_page = NULL;
 		}
-		if (addr != end)
-			goto again;
+	}
+
+	if (addr != end) {
+		cond_resched();
+		goto again;
 	}
 
 	return addr;