1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * This file is part of wl18xx
4 *
5 * Copyright (C) 2011 Texas Instruments Inc.
6 */
7
8#include "../wlcore/cmd.h"
9#include "../wlcore/debug.h"
10#include "../wlcore/hw_ops.h"
11
12#include "cmd.h"
13
14int wl18xx_cmd_channel_switch(struct wl1271 *wl,
15			      struct wl12xx_vif *wlvif,
16			      struct ieee80211_channel_switch *ch_switch)
17{
18	struct wl18xx_cmd_channel_switch *cmd;
19	u32 supported_rates;
20	int ret;
21
22	wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)",
23		     ch_switch->count);
24
25	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
26	if (!cmd) {
27		ret = -ENOMEM;
28		goto out;
29	}
30
31	cmd->role_id = wlvif->role_id;
32	cmd->channel = ch_switch->chandef.chan->hw_value;
33	cmd->switch_time = ch_switch->count;
34	cmd->stop_tx = ch_switch->block_tx;
35
36	switch (ch_switch->chandef.chan->band) {
37	case NL80211_BAND_2GHZ:
38		cmd->band = WLCORE_BAND_2_4GHZ;
39		break;
40	case NL80211_BAND_5GHZ:
41		cmd->band = WLCORE_BAND_5GHZ;
42		break;
43	default:
44		wl1271_error("invalid channel switch band: %d",
45			     ch_switch->chandef.chan->band);
46		ret = -EINVAL;
47		goto out_free;
48	}
49
50	supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES;
51	if (wlvif->bss_type == BSS_TYPE_STA_BSS)
52		supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
53	else
54		supported_rates |=
55			wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
56	if (wlvif->p2p)
57		supported_rates &= ~CONF_TX_CCK_RATES;
58	cmd->local_supported_rates = cpu_to_le32(supported_rates);
59	cmd->channel_type = wlvif->channel_type;
60
61	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
62	if (ret < 0) {
63		wl1271_error("failed to send channel switch command");
64		goto out_free;
65	}
66
67out_free:
68	kfree(cmd);
69out:
70	return ret;
71}
72
73int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap)
74{
75	struct wl18xx_cmd_smart_config_start *cmd;
76	int ret = 0;
77
78	wl1271_debug(DEBUG_CMD, "cmd smart config start group_bitmap=0x%x",
79		     group_bitmap);
80
81	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
82	if (!cmd) {
83		ret = -ENOMEM;
84		goto out;
85	}
86
87	cmd->group_id_bitmask = cpu_to_le32(group_bitmap);
88
89	ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_START, cmd, sizeof(*cmd), 0);
90	if (ret < 0) {
91		wl1271_error("failed to send smart config start command");
92		goto out_free;
93	}
94
95out_free:
96	kfree(cmd);
97out:
98	return ret;
99}
100
101int wl18xx_cmd_smart_config_stop(struct wl1271 *wl)
102{
103	struct wl1271_cmd_header *cmd;
104	int ret = 0;
105
106	wl1271_debug(DEBUG_CMD, "cmd smart config stop");
107
108	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
109	if (!cmd) {
110		ret = -ENOMEM;
111		goto out;
112	}
113
114	ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_STOP, cmd, sizeof(*cmd), 0);
115	if (ret < 0) {
116		wl1271_error("failed to send smart config stop command");
117		goto out_free;
118	}
119
120out_free:
121	kfree(cmd);
122out:
123	return ret;
124}
125
126int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
127					  u8 key_len, u8 *key)
128{
129	struct wl18xx_cmd_smart_config_set_group_key *cmd;
130	int ret = 0;
131
132	wl1271_debug(DEBUG_CMD, "cmd smart config set group key id=0x%x",
133		     group_id);
134
135	if (key_len != sizeof(cmd->key)) {
136		wl1271_error("invalid group key size: %d", key_len);
137		return -E2BIG;
138	}
139
140	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
141	if (!cmd) {
142		ret = -ENOMEM;
143		goto out;
144	}
145
146	cmd->group_id = cpu_to_le32(group_id);
147	memcpy(cmd->key, key, key_len);
148
149	ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_SET_GROUP_KEY, cmd,
150			      sizeof(*cmd), 0);
151	if (ret < 0) {
152		wl1271_error("failed to send smart config set group key cmd");
153		goto out_free;
154	}
155
156out_free:
157	kfree(cmd);
158out:
159	return ret;
160}
161
162int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)
163{
164	struct wlcore_cmd_cac_start *cmd;
165	int ret = 0;
166
167	wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s",
168		     wlvif->channel, start ? "start" : "stop");
169
170	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
171	if (!cmd)
172		return -ENOMEM;
173
174	cmd->role_id = wlvif->role_id;
175	cmd->channel = wlvif->channel;
176	if (wlvif->band == NL80211_BAND_5GHZ)
177		cmd->band = WLCORE_BAND_5GHZ;
178	cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type);
179
180	ret = wl1271_cmd_send(wl,
181			      start ? CMD_CAC_START : CMD_CAC_STOP,
182			      cmd, sizeof(*cmd), 0);
183	if (ret < 0) {
184		wl1271_error("failed to send cac command");
185		goto out_free;
186	}
187
188out_free:
189	kfree(cmd);
190	return ret;
191}
192
193int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel)
194{
195	struct wl18xx_cmd_dfs_radar_debug *cmd;
196	int ret = 0;
197
198	wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)",
199		     channel);
200
201	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
202	if (!cmd)
203		return -ENOMEM;
204
205	cmd->channel = channel;
206
207	ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG,
208			      cmd, sizeof(*cmd), 0);
209	if (ret < 0) {
210		wl1271_error("failed to send radar detection debug command");
211		goto out_free;
212	}
213
214out_free:
215	kfree(cmd);
216	return ret;
217}
218
219int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif)
220{
221	struct wl18xx_cmd_dfs_master_restart *cmd;
222	int ret = 0;
223
224	wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)",
225		     wlvif->role_id);
226
227	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
228	if (!cmd)
229		return -ENOMEM;
230
231	cmd->role_id = wlvif->role_id;
232
233	ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART,
234			      cmd, sizeof(*cmd), 0);
235	if (ret < 0) {
236		wl1271_error("failed to send dfs master restart command");
237		goto out_free;
238	}
239out_free:
240	kfree(cmd);
241	return ret;
242}
243