Преглед на файлове

Merge "msm: ipa: add support for data warning limit"

qctecmdr преди 4 години
родител
ревизия
b8c2d297fc

+ 14 - 7
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c

@@ -1447,6 +1447,7 @@ static void ipa3_q6_clnt_quota_reached_ind_cb(struct qmi_handle *handle,
 	const void *data)
 {
 	struct ipa_data_usage_quota_reached_ind_msg_v01 *qmi_ind;
+	bool data_warning = false;
 
 	if (handle != ipa_q6_clnt) {
 		IPAWANERR("Wrong client\n");
@@ -1455,10 +1456,18 @@ static void ipa3_q6_clnt_quota_reached_ind_cb(struct qmi_handle *handle,
 
 	qmi_ind = (struct ipa_data_usage_quota_reached_ind_msg_v01 *) data;
 
-	IPAWANDBG("Quota reached indication on qmux(%d) Mbytes(%lu)\n",
-		qmi_ind->apn.mux_id, (unsigned long) qmi_ind->apn.num_Mbytes);
+#ifdef IPA_DATA_WARNING_QUOTA
+	data_warning = (qmi_ind->is_warning_limit_valid &&
+		qmi_ind->is_warning_limit);
+	if (qmi_ind->is_warning_limit_valid && qmi_ind->is_warning_limit)
+		IPAWANDBG("Warning reached indication on qmux(%d) Mbytes(%lu)\n",
+			qmi_ind->apn.mux_id, (unsigned long) qmi_ind->apn.num_Mbytes);
+	else
+#endif
+		IPAWANDBG("Quota reached indication on qmux(%d) Mbytes(%lu)\n",
+			qmi_ind->apn.mux_id, (unsigned long) qmi_ind->apn.num_Mbytes);
 	ipa3_broadcast_quota_reach_ind(qmi_ind->apn.mux_id,
-		IPA_UPSTEAM_MODEM);
+		IPA_UPSTEAM_MODEM, data_warning);
 }
 
 static void ipa3_q6_clnt_install_firewall_rules_ind_cb(
@@ -2099,14 +2108,12 @@ int ipa3_qmi_set_aggr_info(enum ipa_aggr_enum_type_v01 aggr_enum_type)
 		resp.resp.error, "ipa_mhi_prime_aggr_info_req_msg_v01");
 }
 
-int ipa3_qmi_stop_data_qouta(void)
+int ipa3_qmi_stop_data_quota(struct ipa_stop_data_usage_quota_req_msg_v01 *req)
 {
-	struct ipa_stop_data_usage_quota_req_msg_v01 req;
 	struct ipa_stop_data_usage_quota_resp_msg_v01 resp;
 	struct ipa_msg_desc req_desc, resp_desc;
 	int rc;
 
-	memset(&req, 0, sizeof(struct ipa_stop_data_usage_quota_req_msg_v01));
 	memset(&resp, 0, sizeof(struct ipa_stop_data_usage_quota_resp_msg_v01));
 
 	req_desc.max_msg_len =
@@ -2123,7 +2130,7 @@ int ipa3_qmi_stop_data_qouta(void)
 	if (unlikely(!ipa_q6_clnt))
 		return -ETIMEDOUT;
 	rc = ipa3_qmi_send_req_wait(ipa_q6_clnt,
-		&req_desc, &req,
+		&req_desc, req,
 		&resp_desc, &resp,
 		QMI_SEND_STATS_REQ_TIMEOUT_MS);
 

+ 18 - 4
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h

@@ -287,8 +287,13 @@ int rmnet_ipa3_poll_tethering_stats(struct wan_ioctl_poll_tethering_stats
 
 int rmnet_ipa3_set_data_quota(struct wan_ioctl_set_data_quota *data);
 
+#ifdef IPA_DATA_WARNING_QUOTA
+int rmnet_ipa3_set_data_quota_warning(struct wan_ioctl_set_data_quota_warning
+		*data);
+#endif
+
 void ipa3_broadcast_quota_reach_ind(uint32_t mux_id,
-	enum ipa_upstream_type upstream_type);
+	enum ipa_upstream_type upstream_type, bool is_warning_limit);
 
 int rmnet_ipa3_set_tether_client_pipe(struct wan_ioctl_set_tether_client_pipe
 	*data);
@@ -328,7 +333,7 @@ int ipa3_qmi_set_data_quota(struct ipa_set_data_usage_quota_req_msg_v01 *req);
 int ipa3_qmi_set_aggr_info(
 	enum ipa_aggr_enum_type_v01 aggr_enum_type);
 
-int ipa3_qmi_stop_data_qouta(void);
+int ipa3_qmi_stop_data_quota(struct ipa_stop_data_usage_quota_req_msg_v01 *req);
 
 void ipa3_q6_handshake_complete(bool ssr_bootup);
 
@@ -456,8 +461,16 @@ static inline int rmnet_ipa3_set_data_quota(
 	return -EPERM;
 }
 
+#ifdef IPA_DATA_WARNING_QUOTA
+static inline int rmnet_ipa3_set_data_quota_warning(
+	struct wan_ioctl_set_data_quota_warning *data)
+{
+	return -EPERM;
+}
+#endif
+
 static inline void ipa3_broadcast_quota_reach_ind(uint32_t mux_id,
-	enum ipa_upstream_type upstream_type) { }
+	enum ipa_upstream_type upstream_type, bool is_warning_limit) { }
 
 static inline int ipa3_qmi_get_data_stats(
 	struct ipa_get_data_stats_req_msg_v01 *req,
@@ -479,7 +492,8 @@ static inline int ipa3_qmi_set_data_quota(
 	return -EPERM;
 }
 
-static inline int ipa3_qmi_stop_data_qouta(void)
+static inline int ipa3_qmi_stop_data_quota(
+struct ipa_stop_data_usage_quota_req_msg_v01 *req)
 {
 	return -EPERM;
 }

+ 98 - 1
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c

@@ -3250,6 +3250,40 @@ struct qmi_elem_info ipa3_set_data_usage_quota_req_msg_data_v01_ei[] = {
 			apn_quota_list),
 		.ei_array	= ipa3_data_usage_quota_info_type_data_v01_ei,
 	},
+#ifdef IPA_DATA_WARNING_QUOTA
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x11,
+		.offset		= offsetof(
+			struct ipa_set_data_usage_quota_req_msg_v01,
+			apn_warning_list_valid),
+	},
+	{
+		.data_type	= QMI_DATA_LEN,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x11,
+		.offset		= offsetof(
+			struct ipa_set_data_usage_quota_req_msg_v01,
+			apn_warning_list_len),
+	},
+	{
+		.data_type	= QMI_STRUCT,
+		.elem_len	= QMI_IPA_MAX_APN_V01,
+		.elem_size	= sizeof(struct
+					ipa_data_usage_quota_info_type_v01),
+		.array_type	= VAR_LEN_ARRAY,
+		.tlv_type	= 0x11,
+		.offset		= offsetof(
+			struct ipa_set_data_usage_quota_req_msg_v01,
+			apn_warning_list),
+		.ei_array	= ipa3_data_usage_quota_info_type_data_v01_ei,
+	},
+#endif
 	{
 		.data_type	= QMI_EOTI,
 		.array_type	= NO_ARRAY,
@@ -3289,6 +3323,28 @@ struct qmi_elem_info ipa3_data_usage_quota_reached_ind_msg_data_v01_ei[] = {
 			apn),
 		.ei_array	= ipa3_data_usage_quota_info_type_data_v01_ei,
 	},
+#ifdef IPA_DATA_WARNING_QUOTA
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(
+			struct ipa_data_usage_quota_reached_ind_msg_v01,
+			is_warning_limit_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(
+			struct ipa_data_usage_quota_reached_ind_msg_v01,
+			is_warning_limit),
+	},
+#endif
 	{
 		.data_type	= QMI_EOTI,
 		.array_type	= NO_ARRAY,
@@ -3297,7 +3353,48 @@ struct qmi_elem_info ipa3_data_usage_quota_reached_ind_msg_data_v01_ei[] = {
 };
 
 struct qmi_elem_info ipa3_stop_data_usage_quota_req_msg_data_v01_ei[] = {
-	/* ipa_stop_data_usage_quota_req_msg is empty */
+#ifdef IPA_DATA_WARNING_QUOTA
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(
+			struct ipa_stop_data_usage_quota_req_msg_v01,
+			is_quota_limit_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x10,
+		.offset		= offsetof(
+			struct ipa_stop_data_usage_quota_req_msg_v01,
+			is_quota_limit),
+	},
+	{
+		.data_type	= QMI_OPT_FLAG,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x11,
+		.offset		= offsetof(
+			struct ipa_stop_data_usage_quota_req_msg_v01,
+			is_warning_limit_valid),
+	},
+	{
+		.data_type	= QMI_UNSIGNED_1_BYTE,
+		.elem_len	= 1,
+		.elem_size	= sizeof(uint8_t),
+		.array_type	= NO_ARRAY,
+		.tlv_type	= 0x11,
+		.offset		= offsetof(
+			struct ipa_stop_data_usage_quota_req_msg_v01,
+			is_warning_limit),
+	},
+#endif
 	{
 		.data_type	= QMI_EOTI,
 		.array_type	= NO_ARRAY,

+ 1 - 1
drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c

@@ -2890,7 +2890,7 @@ int ipa3_broadcast_wdi_quota_reach_ind(uint32_t fid,
 {
 	IPAERR_RL("Quota reached indication on fid(%d) Mbytes(%lu)\n",
 			  fid, (unsigned long)num_bytes);
-	ipa3_broadcast_quota_reach_ind(0, IPA_UPSTEAM_WLAN);
+	ipa3_broadcast_quota_reach_ind(0, IPA_UPSTEAM_WLAN, false);
 	return 0;
 }
 

+ 164 - 8
drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c

@@ -3959,13 +3959,18 @@ static void rmnet_ipa_get_network_stats_and_update(void)
  * This function sends the quota_reach indication from the IPA Modem driver
  * via QMI, to user-space module
  */
-static void rmnet_ipa_send_quota_reach_ind(void)
+static void rmnet_ipa_send_quota_reach_ind(bool is_warning_limit)
 {
 	struct ipa_msg_meta msg_meta;
 	int rc;
 
 	memset(&msg_meta, 0, sizeof(struct ipa_msg_meta));
-	msg_meta.msg_type = IPA_QUOTA_REACH;
+	if (!is_warning_limit)
+		msg_meta.msg_type = IPA_QUOTA_REACH;
+#ifdef IPA_DATA_WARNING_QUOTA
+	else
+		msg_meta.msg_type = IPA_WARNING_LIMIT_REACHED;
+#endif
 	rc = ipa_send_msg(&msg_meta, NULL, NULL);
 	if (rc) {
 		IPAWANERR("ipa_send_msg failed: %d\n", rc);
@@ -3987,12 +3992,22 @@ static void rmnet_ipa_send_quota_reach_ind(void)
  */
 int rmnet_ipa3_poll_tethering_stats(struct wan_ioctl_poll_tethering_stats *data)
 {
+	struct ipa_stop_data_usage_quota_req_msg_v01 stop_req;
+	memset(&stop_req, 0,
+		sizeof(struct ipa_stop_data_usage_quota_req_msg_v01));
+
 	ipa3_rmnet_ctx.polling_interval = data->polling_interval_secs;
 
 	cancel_delayed_work_sync(&ipa_tether_stats_poll_wakequeue_work);
 
 	if (ipa3_rmnet_ctx.polling_interval == 0) {
-		ipa3_qmi_stop_data_qouta();
+		/* stop quota */
+#ifdef IPA_DATA_WARNING_QUOTA
+		stop_req.is_quota_limit_valid = true;
+		stop_req.is_quota_limit = true;
+#endif
+		ipa3_qmi_stop_data_quota(&stop_req);
+
 		rmnet_ipa_get_network_stats_and_update();
 		rmnet_ipa_get_stats_and_update();
 		return 0;
@@ -4021,10 +4036,18 @@ static int rmnet_ipa3_set_data_quota_modem(
 	u32 mux_id;
 	int index;
 	struct ipa_set_data_usage_quota_req_msg_v01 req;
+	struct ipa_stop_data_usage_quota_req_msg_v01 stop_req;
 
 	/* stop quota */
-	if (!data->set_quota)
-		ipa3_qmi_stop_data_qouta();
+	memset(&stop_req, 0,
+		sizeof(struct ipa_stop_data_usage_quota_req_msg_v01));
+	if (!data->set_quota) {
+#ifdef IPA_DATA_WARNING_QUOTA
+		stop_req.is_quota_limit_valid = true;
+		stop_req.is_quota_limit = true;
+#endif
+		ipa3_qmi_stop_data_quota(&stop_req);
+	}
 
 	/* prevent string buffer overflows */
 	data->interface_name[IFNAMSIZ-1] = '\0';
@@ -4051,6 +4074,82 @@ static int rmnet_ipa3_set_data_quota_modem(
 	return ipa3_qmi_set_data_quota(&req);
 }
 
+#ifdef IPA_DATA_WARNING_QUOTA
+/**
+ * rmnet_ipa_set_data_quota_warning_modem() - Data quota and warning
+ * setting handler
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_SET_DATA_QUOTA_WARNING on modem interface.
+ * It translates the given interface name to the Modem MUX ID and
+ * sends the request of the quota to the IPA Modem driver via QMI.
+ *
+ * Return codes:
+ * 0: Success
+ * -EFAULT: Invalid interface name provided
+ * other: See ipa_qmi_set_data_quota_warning
+ */
+static int rmnet_ipa3_set_data_quota_warning_modem
+(
+	struct wan_ioctl_set_data_quota_warning *data
+)
+{
+	u32 mux_id;
+	int index;
+	struct ipa_set_data_usage_quota_req_msg_v01 req;
+	struct ipa_stop_data_usage_quota_req_msg_v01 stop_req;
+
+	/* prevent string buffer overflows */
+	data->interface_name[IFNAMSIZ-1] = '\0';
+
+	index = find_vchannel_name_index(data->interface_name);
+	IPAWANERR("iface name %s, quota %lu, warning %lu\n",
+		  data->interface_name, (unsigned long) data->quota_mbytes,
+		  (unsigned long) data->warning_mbytes);
+
+	if (index == MAX_NUM_OF_MUX_CHANNEL) {
+		IPAWANERR("%s is an invalid iface name\n",
+			  data->interface_name);
+		return -ENODEV;
+	}
+	/* stop quota or warning */
+	memset(&stop_req, 0,
+		sizeof(struct ipa_stop_data_usage_quota_req_msg_v01));
+	if (!data->set_quota || !data->set_warning) {
+
+		if (!data->set_quota) {
+			stop_req.is_quota_limit_valid = true;
+			stop_req.is_quota_limit = true;
+		}
+
+		if (!data->set_warning) {
+			stop_req.is_warning_limit_valid = true;
+			stop_req.is_warning_limit = true;
+		}
+		ipa3_qmi_stop_data_quota(&stop_req);
+	}
+
+	mux_id = rmnet_ipa3_ctx->mux_channel[index].mux_id;
+	ipa3_rmnet_ctx.metered_mux_id = mux_id;
+
+	memset(&req, 0, sizeof(struct ipa_set_data_usage_quota_req_msg_v01));
+	if (data->set_quota && (data->quota_mbytes != 0)) {
+		req.apn_quota_list_valid = true;
+		req.apn_quota_list_len = 1;
+		req.apn_quota_list[0].mux_id = mux_id;
+		req.apn_quota_list[0].num_Mbytes = data->quota_mbytes;
+	}
+
+	if (data->set_warning && (data->warning_mbytes != 0)) {
+		req.apn_warning_list_valid = true;
+		req.apn_warning_list_len = 1;
+		req.apn_warning_list[0].mux_id = mux_id;
+		req.apn_warning_list[0].num_Mbytes = data->warning_mbytes;
+	}
+	return ipa3_qmi_set_data_quota(&req);
+}
+#endif
+
 static int rmnet_ipa3_set_data_quota_wifi(struct wan_ioctl_set_data_quota *data)
 {
 	struct ipa_set_wifi_quota wifi_quota;
@@ -4117,6 +4216,59 @@ int rmnet_ipa3_set_data_quota(struct wan_ioctl_set_data_quota *data)
 	}
 	return rc;
 }
+
+#ifdef IPA_DATA_WARNING_QUOTA
+/**
+ * rmnet_ipa_set_data_quota_warning() - Data quota and warning setting handler
+ * @data - IOCTL data
+ *
+ * This function handles WAN_IOC_SET_DATA_QUOTA_WARNING.
+ * It translates the given interface name to the Modem MUX ID and
+ * sends the request of the quota and warning to the IPA Modem driver via QMI.
+ *
+ * Return codes:
+ * 0: Success
+ * -EFAULT: Invalid interface name provided
+ * other: See ipa_qmi_set_data_quota
+ */
+int rmnet_ipa3_set_data_quota_warning
+(
+	struct wan_ioctl_set_data_quota_warning *data
+)
+{
+	enum ipa_upstream_type upstream_type;
+	int rc = 0;
+
+	/* prevent string buffer overflows */
+	data->interface_name[IFNAMSIZ-1] = '\0';
+
+	/* get IPA backhaul type */
+	upstream_type = find_upstream_type(data->interface_name);
+
+	if (upstream_type == IPA_UPSTEAM_MAX) {
+		IPAWANERR("Wrong interface_name name %s\n",
+			data->interface_name);
+	} else if (upstream_type == IPA_UPSTEAM_WLAN) {
+		/* No support for Data Warning for WLAN backhaul.
+		 * Support only Data Quota.
+		 */
+		rc = rmnet_ipa3_set_data_quota_wifi(
+			(struct wan_ioctl_set_data_quota *)data);
+		if (rc) {
+			IPAWANERR("set quota and warning on wifi failed\n");
+			return rc;
+		}
+	} else {
+		rc = rmnet_ipa3_set_data_quota_warning_modem(data);
+		if (rc) {
+			IPAWANERR("set quota and warning on modem failed\n");
+			return rc;
+		}
+	}
+	return rc;
+}
+#endif
+
 /* rmnet_ipa_set_tether_client_pipe() -
  * @data - IOCTL data
  *
@@ -5034,7 +5186,7 @@ int rmnet_ipa3_reset_tethering_stats(struct wan_ioctl_reset_tether_stats *data)
  *
  */
 void ipa3_broadcast_quota_reach_ind(u32 mux_id,
-	enum ipa_upstream_type upstream_type)
+	enum ipa_upstream_type upstream_type, bool is_warning_limit)
 {
 	char alert_msg[IPA_QUOTA_REACH_ALERT_MAX_SIZE];
 	char iface_name_m[IPA_QUOTA_REACH_IF_NAME_MAX_SIZE];
@@ -5055,8 +5207,12 @@ void ipa3_broadcast_quota_reach_ind(u32 mux_id,
 			return;
 		}
 	}
-	res = snprintf(alert_msg, IPA_QUOTA_REACH_ALERT_MAX_SIZE,
+	if (!is_warning_limit)
+		res = snprintf(alert_msg, IPA_QUOTA_REACH_ALERT_MAX_SIZE,
 			"ALERT_NAME=%s", "quotaReachedAlert");
+	else
+		res = snprintf(alert_msg, IPA_QUOTA_REACH_ALERT_MAX_SIZE,
+			"ALERT_NAME=%s", "warningReachedAlert");
 	if (res >= IPA_QUOTA_REACH_ALERT_MAX_SIZE) {
 		IPAWANERR("message too long (%d)", res);
 		return;
@@ -5097,7 +5253,7 @@ void ipa3_broadcast_quota_reach_ind(u32 mux_id,
 	kobject_uevent_env(&(IPA_NETDEV()->dev.kobj),
 		KOBJ_CHANGE, envp);
 
-	rmnet_ipa_send_quota_reach_ind();
+	rmnet_ipa_send_quota_reach_ind(is_warning_limit);
 }
 
 /**

+ 32 - 0
drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c

@@ -287,6 +287,38 @@ static long ipa3_wan_ioctl(struct file *filp,
 		}
 		break;
 
+#ifdef IPA_DATA_WARNING_QUOTA
+	case WAN_IOC_SET_DATA_QUOTA_WARNING:
+		IPAWANDBG_LOW("device %s got WAN_IOC_SET_DATA_QUOTA_WARNING :>>>\n",
+			DRIVER_NAME);
+		pyld_sz = sizeof(struct wan_ioctl_set_data_quota_warning);
+		if (pyld_sz > _IOC_SIZE(cmd)) {
+			IPAWANERR("SET_DATA_QUOTA_WARNING failed, invalid params\n");
+			retval = -EINVAL;
+			break;
+		}
+		param = memdup_user((const void __user *)arg, pyld_sz);
+		if (IS_ERR(param)) {
+			retval = PTR_ERR(param);
+			break;
+		}
+		rc = rmnet_ipa3_set_data_quota_warning(
+			(struct wan_ioctl_set_data_quota_warning *)param);
+		if (rc != 0) {
+			IPAWANERR("SET_DATA_QUOTA_WARNING failed\n");
+			if (rc == -ENODEV)
+				retval = -ENODEV;
+			else
+				retval = -EFAULT;
+			break;
+		}
+		if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+			retval = -EFAULT;
+			break;
+		}
+		break;
+#endif
+
 	case WAN_IOC_SET_TETHER_CLIENT_PIPE:
 		IPAWANDBG_LOW("got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n");
 		pyld_sz = sizeof(struct wan_ioctl_set_tether_client_pipe);