1 /*
2  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: wlan_hdd_sysfs_dp_traffic_end_indication.c
19  *
20  * implementation for creating sysfs files:
21  *
22  * dp_traffic_end_indication
23  */
24 #include <wlan_hdd_includes.h>
25 #include "osif_vdev_sync.h"
26 #include "wlan_hdd_object_manager.h"
27 #include <wlan_hdd_sysfs.h>
28 #include <wlan_hdd_sysfs_dp_traffic_end_indication.h>
29 #include <wlan_dp_ucfg_api.h>
30 
31 static ssize_t
__hdd_sysfs_dp_traffic_end_indication_show(struct net_device * net_dev,char * buf)32 __hdd_sysfs_dp_traffic_end_indication_show(struct net_device *net_dev,
33 					   char *buf)
34 {
35 	struct hdd_adapter *adapter = netdev_priv(net_dev);
36 	struct wlan_objmgr_vdev *vdev;
37 	struct dp_traffic_end_indication info = {0};
38 	QDF_STATUS status;
39 	int ret;
40 
41 	if (hdd_validate_adapter(adapter))
42 		return -EINVAL;
43 
44 	ret = wlan_hdd_validate_context(adapter->hdd_ctx);
45 	if (ret)
46 		return ret;
47 
48 	if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx))
49 		return -EINVAL;
50 
51 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID);
52 	if (!vdev)
53 		return -EINVAL;
54 
55 	status = ucfg_dp_traffic_end_indication_get(vdev, &info);
56 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
57 
58 	if (!QDF_IS_STATUS_SUCCESS(status))
59 		return -EINVAL;
60 
61 	hdd_debug("vdev_id:%u traffic end indication:%u defdscp:%u spldscp:%u",
62 		  adapter->deflink->vdev_id, info.enabled,
63 		  info.def_dscp, info.spl_dscp);
64 
65 	ret = scnprintf(buf, PAGE_SIZE, "%u %u %u\n",
66 			info.enabled, info.def_dscp, info.def_dscp);
67 	return ret;
68 }
69 
70 static ssize_t
hdd_sysfs_dp_traffic_end_indication_show(struct device * dev,struct device_attribute * attr,char * buf)71 hdd_sysfs_dp_traffic_end_indication_show(struct device *dev,
72 					 struct device_attribute *attr,
73 					 char *buf)
74 {
75 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
76 	struct osif_vdev_sync *vdev_sync;
77 	ssize_t err_size;
78 
79 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
80 	if (err_size)
81 		return err_size;
82 
83 	err_size = __hdd_sysfs_dp_traffic_end_indication_show(net_dev, buf);
84 
85 	osif_vdev_sync_op_stop(vdev_sync);
86 
87 	return err_size;
88 }
89 
90 static ssize_t
__hdd_sysfs_dp_traffic_end_indication_store(struct net_device * net_dev,const char * buf,size_t count)91 __hdd_sysfs_dp_traffic_end_indication_store(struct net_device *net_dev,
92 					    const char *buf,
93 					    size_t count)
94 {
95 	struct hdd_adapter *adapter = netdev_priv(net_dev);
96 	struct dp_traffic_end_indication info = {0};
97 	struct wlan_objmgr_vdev *vdev;
98 	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
99 	char *sptr, *token;
100 	uint8_t value, defdscp, spldscp;
101 	int ret;
102 
103 	if (hdd_validate_adapter(adapter))
104 		return -EINVAL;
105 
106 	ret = wlan_hdd_validate_context(adapter->hdd_ctx);
107 	if (ret)
108 		return ret;
109 
110 	if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx))
111 		return -EINVAL;
112 
113 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
114 					      buf, count);
115 	if (ret) {
116 		hdd_err("invalid input");
117 		return ret;
118 	}
119 
120 	sptr = buf_local;
121 	/* Enable/disable traffic end indication*/
122 	token = strsep(&sptr, " ");
123 	if (!token)
124 		return -EINVAL;
125 	if (kstrtou8(token, 0, &value))
126 		return -EINVAL;
127 
128 	/* Default DSCP Value */
129 	token = strsep(&sptr, " ");
130 	if (!token)
131 		return -EINVAL;
132 	if (kstrtou8(token, 0, &defdscp))
133 		return -EINVAL;
134 
135 	/* Special DSCP Value */
136 	token = strsep(&sptr, " ");
137 	if (!token)
138 		return -EINVAL;
139 	if (kstrtou8(token, 0, &spldscp))
140 		return -EINVAL;
141 
142 	if ((defdscp > 63) || (spldscp > 63)) {
143 		hdd_err("invalid dscp value");
144 		return -EINVAL;
145 	}
146 
147 	vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID);
148 	if (!vdev)
149 		return -EINVAL;
150 
151 	info.enabled = !!value;
152 	adapter->traffic_end_ind_en = info.enabled;
153 	if (info.enabled) {
154 		info.def_dscp = defdscp;
155 		info.spl_dscp = spldscp;
156 	} else {
157 		info.def_dscp = 0;
158 		info.spl_dscp = 0;
159 	}
160 
161 	hdd_debug("vdev_id:%u traffic end indication:%u defdscp:%u spldscp:%u",
162 		  adapter->deflink->vdev_id, value, defdscp, spldscp);
163 
164 	ucfg_dp_traffic_end_indication_set(vdev, info);
165 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID);
166 
167 	return count;
168 }
169 
170 static ssize_t
hdd_sysfs_dp_traffic_end_indication_store(struct device * dev,struct device_attribute * attr,char const * buf,size_t count)171 hdd_sysfs_dp_traffic_end_indication_store(struct device *dev,
172 					  struct device_attribute *attr,
173 					  char const *buf, size_t count)
174 {
175 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
176 	struct osif_vdev_sync *vdev_sync;
177 	ssize_t errno_size;
178 
179 	errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
180 	if (errno_size)
181 		return errno_size;
182 
183 	errno_size = __hdd_sysfs_dp_traffic_end_indication_store(net_dev,
184 								 buf, count);
185 
186 	osif_vdev_sync_op_stop(vdev_sync);
187 
188 	return errno_size;
189 }
190 
191 static DEVICE_ATTR(dp_traffic_end_indication, 0660,
192 		   hdd_sysfs_dp_traffic_end_indication_show,
193 		   hdd_sysfs_dp_traffic_end_indication_store);
194 
hdd_sysfs_dp_traffic_end_indication_create(struct hdd_adapter * adapter)195 int hdd_sysfs_dp_traffic_end_indication_create(struct hdd_adapter *adapter)
196 {
197 	int error;
198 
199 	error = device_create_file(&adapter->dev->dev,
200 				   &dev_attr_dp_traffic_end_indication);
201 	if (error)
202 		hdd_err("could not create traffic_end_indication sysfs file");
203 
204 	return error;
205 }
206 
207 void
hdd_sysfs_dp_traffic_end_indication_destroy(struct hdd_adapter * adapter)208 hdd_sysfs_dp_traffic_end_indication_destroy(struct hdd_adapter *adapter)
209 {
210 	device_remove_file(&adapter->dev->dev,
211 			   &dev_attr_dp_traffic_end_indication);
212 }
213