cmd.c revision 61f845f4f441a90e5328a78c6c4e0646d99fc2f0
1f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/*
2f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This file is part of wl1271
3f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
42f826f55404ca43efced94d548356182820e764fLuciano Coelho * Copyright (C) 2009-2010 Nokia Corporation
5f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
6f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
8f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is free software; you can redistribute it and/or
9f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * modify it under the terms of the GNU General Public License
10f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * version 2 as published by the Free Software Foundation.
11f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
12f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is distributed in the hope that it will be useful, but
13f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * WITHOUT ANY WARRANTY; without even the implied warranty of
14f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * General Public License for more details.
16f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
17f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * You should have received a copy of the GNU General Public License
18f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * along with this program; if not, write to the Free Software
19f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 02110-1301 USA
21f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
22f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
23f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
24f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/module.h>
25f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/platform_device.h>
26f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/spi/spi.h>
27f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/etherdevice.h>
28023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo#include <linux/ieee80211.h>
295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
30f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "wl12xx.h"
3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "reg.h"
3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h"
3400d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "acx.h"
35f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl12xx_80211.h"
3600d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "cmd.h"
3700d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "event.h"
3898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov#include "tx.h"
39f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
4016092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen#define WL1271_CMD_FAST_POLL_COUNT       50
41f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
42f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/*
43f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send command to firmware
44f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
45f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
46f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: command id
47f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, must work with dma
48f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
49f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
50fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinenint wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
51fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		    size_t res_len)
52f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
53f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_header *cmd;
54f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	unsigned long timeout;
55f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 intr;
56f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
57ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	u16 status;
58bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal	u16 poll_count = 0;
59f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
60f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = buf;
61d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->id = cpu_to_le16(id);
62f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->status = 0;
63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
64f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(len % 4 != 0);
6524225b37bd78d3e2edaa1a39316c54786adaa465Arik Nemtsov	WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
66f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
677b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
68f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
697b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
70f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
737b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
74f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		if (time_after(jiffies, timeout)) {
76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			wl1271_error("command complete timeout");
77f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			ret = -ETIMEDOUT;
78f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov			goto fail;
79f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		}
80f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
81bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal		poll_count++;
8216092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		if (poll_count < WL1271_CMD_FAST_POLL_COUNT)
8316092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			udelay(10);
8416092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		else
8516092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			msleep(1);
86f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
877b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
88f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
89f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
903b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	/* read back the status code of the command */
91fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (res_len == 0)
92fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = sizeof(struct wl1271_cmd_header);
937b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
943b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
95ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	status = le16_to_cpu(cmd->status);
96ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	if (status != CMD_STATUS_SUCCESS) {
97ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen		wl1271_error("command execute failure %d", status);
983b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen		ret = -EIO;
99f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov		goto fail;
1003b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	}
1013b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
1027b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
1037b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		       WL1271_ACX_INTR_CMD_COMPLETE);
104f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov	return 0;
105f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
106f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsovfail:
107f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov	WARN_ON(1);
108baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv	wl12xx_queue_recovery_work(wl);
109f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
110f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
111f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
11298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_general_parms(struct wl1271 *wl)
11398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
11498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_general_parms_cmd *gen_parms;
11549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl1271_ini_general_params *gp =
11649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
11749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	bool answer = false;
11849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
11949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
12149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
12249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
12449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!gen_parms)
12549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
12649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
12849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
13049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
13149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (gp->tx_bip_fem_auto_detect)
13249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		answer = true;
13349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
134b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	/* Override the REF CLK from the NVS with the one from platform data */
135b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.ref_clock = wl->ref_clock;
136b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi
13749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
13849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (ret < 0) {
13949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
14049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		goto out;
14149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	}
14249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gp->tx_bip_fem_manufacturer =
14449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		gen_parms->general_params.tx_bip_fem_manufacturer;
14549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
14749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
14849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviout:
15049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	kfree(gen_parms);
15149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	return ret;
15249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi}
15349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
15449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_general_parms(struct wl1271 *wl)
15549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
15649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_general_parms_cmd *gen_parms;
15749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp =
15849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
1594b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	bool answer = false;
16098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	int ret;
16198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
162152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
163152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
164152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
16598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
16698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!gen_parms)
16798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
16898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
16998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
17098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1714b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
1724b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1734b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (gp->tx_bip_fem_auto_detect)
1744b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		answer = true;
17576c0f8d396bd306111d349cfe770e1c4fcf70248Luciano Coelho
176b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	/* Replace REF and TCXO CLKs with the ones from platform data */
177b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.ref_clock = wl->ref_clock;
178b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
179b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi
1804b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
1814b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (ret < 0) {
18298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
1834b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		goto out;
1844b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	}
18598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1864b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	gp->tx_bip_fem_manufacturer =
1874b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		gen_parms->general_params.tx_bip_fem_manufacturer;
1884b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1894b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
1904b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
1914b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1924b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinenout:
19398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(gen_parms);
19498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
19598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
19698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
19798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_radio_parms(struct wl1271 *wl)
19898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
199bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
20098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_radio_parms_cmd *radio_parms;
201bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_ini_general_params *gp = &nvs->general_params;
202152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	int ret;
203152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
204152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
205152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
20698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
20798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
20898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!radio_parms)
20998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
21098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
21198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
21298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
213a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 2.4GHz parameters */
214bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
215eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_2));
216eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	memcpy(&radio_parms->dyn_params_2,
217bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
218eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_2));
219152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
220a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 5GHz parameters */
221a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->static_params_5,
222bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->stat_radio_params_5,
223a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_5));
224a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->dyn_params_5,
225bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
226a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_5));
22798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
22898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
22998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		    radio_parms, sizeof(*radio_parms));
23098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
23198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
23298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
23398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
23498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
23598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
23698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
23798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
23898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
23949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_radio_parms(struct wl1271 *wl)
24049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
24149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
24249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_radio_parms_cmd *radio_parms;
24349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp = &nvs->general_params;
24449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
24549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
24649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
24749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
24849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
24949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
25049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!radio_parms)
25149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
25249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
25449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 2.4GHz parameters */
25649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
25749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_2));
25849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_2,
25949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
26049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_2));
26149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 5GHz parameters */
26349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_5,
26449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->stat_radio_params_5,
26549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_5));
26649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_5,
26749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
26849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_5));
26949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
27049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
27149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
27249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
27349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		    radio_parms, sizeof(*radio_parms));
27449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
27549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
27698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
27798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
27898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
27998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
28098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
28198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
28298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
283644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinenint wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
284644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen{
285644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
286644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct conf_rf_settings *rf = &wl->conf.rf;
287644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	int ret;
288644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
289644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!wl->nvs)
290644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENODEV;
291644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
292644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
293644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!ext_radio_parms)
294644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENOMEM;
295644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
296644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
297644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
298644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
299644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_2,
300644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_2);
301644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
302644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_5,
303644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_5);
304644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
305644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
306644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		    ext_radio_parms, sizeof(*ext_radio_parms));
307644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
308644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
309644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (ret < 0)
310644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
311644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
312644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	kfree(ext_radio_parms);
313644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	return ret;
314644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen}
315644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
31699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho/*
31799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * Poll the mailbox event field until any of the bits in the mask is set or a
31899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
31999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho */
32005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
32199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho{
32299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	u32 events_vector, event;
32399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	unsigned long timeout;
32499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
32599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
32699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
32799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	do {
32852b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		if (time_after(jiffies, timeout)) {
32905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov			wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
33005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov				     (int)mask);
33199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			return -ETIMEDOUT;
33252b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		}
33399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		msleep(1);
33599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		/* read from both event fields */
33799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
33899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
33999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event = events_vector & mask;
34099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
34199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
34299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event |= events_vector & mask;
34399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	} while (!event);
34499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
34599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	return 0;
34699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho}
34799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
34805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
34905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov{
35005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	int ret;
35105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
35205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
35305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	if (ret != 0) {
354baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv		wl12xx_queue_recovery_work(wl);
35505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		return ret;
35605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	}
35705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
35805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	return 0;
35905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov}
36005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
361784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Pellerint wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
362784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller			   u8 *role_id)
363f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
364c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_enable *cmd;
365c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
366c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
367c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd role enable");
368c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
369c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID))
370c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		return -EBUSY;
371c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
372c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
373c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
374c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -ENOMEM;
375c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
376c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
377c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
378c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	/* get role id */
379c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES);
380c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (cmd->role_id >= WL12XX_MAX_ROLES) {
381c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -EBUSY;
382c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out_free;
383c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
384c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
385784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller	memcpy(cmd->mac_address, addr, ETH_ALEN);
386c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->role_type = role_type;
387c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
388c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
389c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
390c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role enable");
391c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out_free;
392c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
393c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
394c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	__set_bit(cmd->role_id, wl->roles_map);
395c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	*role_id = cmd->role_id;
396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
397c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free:
398c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
399c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
400c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout:
401c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return ret;
402c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
403c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
404c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
405c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
406c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_disable *cmd;
407c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
408c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
409c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd role disable");
410c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
411c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID))
412c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		return -ENOENT;
413c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
414c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
415c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
417f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
419c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->role_id = *role_id;
420c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
421c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0);
422c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
423c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role disable");
424c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out_free;
425c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
427c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	__clear_bit(*role_id, wl->roles_map);
428c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	*role_id = WL12XX_INVALID_ROLE_ID;
429f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
430c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free:
431c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
432c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
433c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout:
434c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return ret;
435c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
436c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
437c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerint wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
438c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
439c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
440c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (link >= WL12XX_MAX_LINKS)
441c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		return -EBUSY;
442c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
443c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	__set_bit(link, wl->links_map);
444c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	__set_bit(link, wlvif->links_map);
445c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	*hlid = link;
446c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return 0;
447c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
448c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
449c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellervoid wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
450c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
451c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (*hlid == WL12XX_INVALID_LINK_ID)
452c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		return;
453c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
454c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	__clear_bit(*hlid, wl->links_map);
455c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	__clear_bit(*hlid, wlvif->links_map);
456c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	*hlid = WL12XX_INVALID_LINK_ID;
457c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
458c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
45998b8625301e55bd3e4340f704edc378e4707e577Eliad Pellerstatic int wl12xx_get_new_session_id(struct wl1271 *wl,
46098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller				     struct wl12xx_vif *wlvif)
461712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov{
46298b8625301e55bd3e4340f704edc378e4707e577Eliad Peller	if (wlvif->session_counter >= SESSION_COUNTER_MAX)
46398b8625301e55bd3e4340f704edc378e4707e577Eliad Peller		wlvif->session_counter = 0;
464712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov
46598b8625301e55bd3e4340f704edc378e4707e577Eliad Peller	wlvif->session_counter++;
466712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov
46798b8625301e55bd3e4340f704edc378e4707e577Eliad Peller	return wlvif->session_counter;
468712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov}
469712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov
4707edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Pellerint wl12xx_cmd_role_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
47104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller{
47204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	struct wl12xx_cmd_role_start *cmd;
47304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	int ret;
47404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
47504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
47604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	if (!cmd) {
47704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		ret = -ENOMEM;
47804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		goto out;
47904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
48004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
4817edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id);
48204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
4837edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller	cmd->role_id = wlvif->dev_role_id;
4841b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	if (wlvif->band == IEEE80211_BAND_5GHZ)
48504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		cmd->band = WL12XX_BAND_5GHZ;
48661f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	cmd->channel = wlvif->channel;
48704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
488afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller	if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
489c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller		ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid);
49004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		if (ret)
49104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller			goto out_free;
49204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
493afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller	cmd->device.hlid = wlvif->dev_hlid;
49498b8625301e55bd3e4340f704edc378e4707e577Eliad Peller	cmd->device.session = wlvif->session_counter;
49504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
49604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
49704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		     cmd->role_id, cmd->device.hlid, cmd->device.session);
49804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
49904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
50004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	if (ret < 0) {
50104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		wl1271_error("failed to initiate cmd role enable");
50204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		goto err_hlid;
50304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
50404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
50504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	goto out_free;
50604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
50704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellererr_hlid:
50804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	/* clear links on error */
509c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
51004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
51104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout_free:
51204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	kfree(cmd);
51304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
51404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout:
51504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	return ret;
51604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller}
51704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
5187edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Pellerint wl12xx_cmd_role_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
51904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller{
52004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	struct wl12xx_cmd_role_stop *cmd;
52104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	int ret;
52204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
523afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller	if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID))
52404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		return -EINVAL;
52504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
52604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
52704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	if (!cmd) {
52804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		ret = -ENOMEM;
52904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		goto out;
53004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
53104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
53204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role stop dev");
53304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
5347edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller	cmd->role_id = wlvif->dev_role_id;
53504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	cmd->disc_type = DISCONNECT_IMMEDIATE;
53604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
53704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
53804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
53904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	if (ret < 0) {
54004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		wl1271_error("failed to initiate cmd role stop");
54104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		goto out_free;
54204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
54304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
54404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
54504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	if (ret < 0) {
54604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		wl1271_error("cmd role stop dev event completion error");
54704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller		goto out_free;
54804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	}
54904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
550c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
55104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
55204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout_free:
55304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	kfree(cmd);
55404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
55504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout:
55604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller	return ret;
55704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller}
55804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller
55987fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
560c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
561cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
562c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_start *cmd;
563c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
564f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
565c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
566c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
567c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -ENOMEM;
568c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
569c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
570f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
5710603d891c5b5153f667a79357d4652824c22b54eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id);
572c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
5730603d891c5b5153f667a79357d4652824c22b54eEliad Peller	cmd->role_id = wlvif->role_id;
5741b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	if (wlvif->band == IEEE80211_BAND_5GHZ)
575c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->band = WL12XX_BAND_5GHZ;
57661f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	cmd->channel = wlvif->channel;
57787fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller	cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
5786a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller	cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int);
579c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY;
5801fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller	cmd->sta.ssid_len = wlvif->ssid_len;
5811fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller	memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
582cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
58330d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller	cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
584c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
585154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
586c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller		ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
587c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		if (ret)
588c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller			goto out_free;
589c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
590154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	cmd->sta.hlid = wlvif->sta.hlid;
59198b8625301e55bd3e4340f704edc378e4707e577Eliad Peller	cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif);
59230d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller	cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
593c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
594c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
595c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		     "basic_rate_set: 0x%x, remote_rates: 0x%x",
5960603d891c5b5153f667a79357d4652824c22b54eEliad Peller		     wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
59730d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller		     wlvif->basic_rate_set, wlvif->rate_set);
598c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
599c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
600c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
601c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role start sta");
602c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto err_hlid;
603c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
604c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
605c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	goto out_free;
606c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
607c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellererr_hlid:
608c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	/* clear links on error. */
609c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
610c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
611c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free:
612c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
613c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
614c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout:
615c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return ret;
616c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
617f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
61831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller/* use this function to stop ibss as well */
6190603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
620c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
621c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_stop *cmd;
622c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
623c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
624154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID))
625c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		return -EINVAL;
626c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
627c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
628c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
629c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -ENOMEM;
630c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
631c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
632a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi
6330603d891c5b5153f667a79357d4652824c22b54eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id);
634f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
6350603d891c5b5153f667a79357d4652824c22b54eEliad Peller	cmd->role_id = wlvif->role_id;
636c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->disc_type = DISCONNECT_IMMEDIATE;
637c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
638f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
639c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
640c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
641c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role stop sta");
642c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out_free;
643c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
64472c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller
645c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
646c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
647c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free:
648c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
649c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
650c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout:
651c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return ret;
652c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
653c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
65487fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
655c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
656c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_start *cmd;
657c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
658c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
659c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
6600603d891c5b5153f667a79357d4652824c22b54eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
661c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
66268eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov	/* trying to use hidden SSID with an old hostapd version */
6631fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller	if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
66468eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		wl1271_error("got a null SSID from beacon/bss");
665c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -EINVAL;
666c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
667c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
668c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
669c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
670c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
671c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -ENOMEM;
672c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
673c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
674c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
675c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid);
676e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov	if (ret < 0)
677e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov		goto out_free;
678e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
679c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid);
680e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov	if (ret < 0)
681e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov		goto out_free_global;
682e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
6830603d891c5b5153f667a79357d4652824c22b54eEliad Peller	cmd->role_id = wlvif->role_id;
684c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
685c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
686a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller	cmd->ap.global_hlid = wlvif->ap.global_hlid;
687a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller	cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid;
68887fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller	cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
6896a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller	cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
690c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->ap.dtim_interval = bss_conf->dtim_period;
691c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
69261f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	cmd->channel = wlvif->channel;
69368eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov
69468eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov	if (!bss_conf->hidden_ssid) {
69568eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		/* take the SSID from the beacon for backward compatibility */
69668eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
6971fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller		cmd->ap.ssid_len = wlvif->ssid_len;
6981fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller		memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len);
69968eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov	} else {
70068eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
70168eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		cmd->ap.ssid_len = bss_conf->ssid_len;
70268eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov		memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
70368eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov	}
70468eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov
705c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->ap.local_rates = cpu_to_le32(0xffffffff);
706c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
7071b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	switch (wlvif->band) {
708c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	case IEEE80211_BAND_2GHZ:
709c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->band = RADIO_BAND_2_4GHZ;
710c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		break;
711c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	case IEEE80211_BAND_5GHZ:
712c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->band = RADIO_BAND_5GHZ;
713c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		break;
714c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	default:
7151b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller		wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
716c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->band = RADIO_BAND_2_4GHZ;
717c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		break;
718c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
719c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
720c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
721c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
722c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role start ap");
723e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov		goto out_free_bcast;
724c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
725f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
726e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov	goto out_free;
727e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
728e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsovout_free_bcast:
729c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
730e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
731e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsovout_free_global:
732c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
733e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
734f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
735c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
736f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
737f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
738f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
739f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
740f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
7410603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
742c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{
743c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_role_stop *cmd;
744c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	int ret;
745c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
746c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
747c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (!cmd) {
748c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = -ENOMEM;
749c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out;
750c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
751c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
7520603d891c5b5153f667a79357d4652824c22b54eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id);
753c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
7540603d891c5b5153f667a79357d4652824c22b54eEliad Peller	cmd->role_id = wlvif->role_id;
755c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
756c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
757c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (ret < 0) {
758c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd role stop ap");
759c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		goto out_free;
760c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	}
761c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
762c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
763c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
764e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov
765c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free:
766c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	kfree(cmd);
767c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
768c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout:
769c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	return ret;
770c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller}
771c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
77287fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
77331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller{
774cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
77531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	struct wl12xx_cmd_role_start *cmd;
77631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
77731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	int ret;
77831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
77931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
78031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	if (!cmd) {
78131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		ret = -ENOMEM;
78231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		goto out;
78331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	}
78431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
7850603d891c5b5153f667a79357d4652824c22b54eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id);
78631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
7870603d891c5b5153f667a79357d4652824c22b54eEliad Peller	cmd->role_id = wlvif->role_id;
7881b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	if (wlvif->band == IEEE80211_BAND_5GHZ)
78931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		cmd->band = WL12XX_BAND_5GHZ;
79061f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	cmd->channel = wlvif->channel;
79187fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller	cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
7926a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller	cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int);
79331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	cmd->ibss.dtim_interval = bss_conf->dtim_period;
79431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY;
7951fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller	cmd->ibss.ssid_len = wlvif->ssid_len;
7961fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller	memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len);
797cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN);
79830d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller	cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
79931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
800154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
801c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller		ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
80231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		if (ret)
80331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller			goto out_free;
80431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	}
805154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	cmd->ibss.hlid = wlvif->sta.hlid;
80630d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller	cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set);
80731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
80831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
80931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		     "basic_rate_set: 0x%x, remote_rates: 0x%x",
8100603d891c5b5153f667a79357d4652824c22b54eEliad Peller		     wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
81130d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller		     wlvif->basic_rate_set, wlvif->rate_set);
81231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
813cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM",
814cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller		     vif->bss_conf.bssid);
81531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
81631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
81731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	if (ret < 0) {
81831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		wl1271_error("failed to initiate cmd role enable");
81931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller		goto err_hlid;
82031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	}
82131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
82231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	goto out_free;
82331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
82431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellererr_hlid:
82531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	/* clear links on error. */
826c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
82731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
82831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellerout_free:
82931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	kfree(cmd);
83031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
83131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellerout:
83231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller	return ret;
83331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller}
83431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller
835c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
837f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware
838f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
839f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
840f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma
841f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
842f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed
843f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
844f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
845f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
846f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
847fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	size_t res_len = 0;
848f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
849f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd test");
850f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
851fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (answer)
852fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = buf_len;
853fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen
854fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len);
855f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
856f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
857f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TEST command failed");
858f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
859f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
860f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
861fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	return ret;
862f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
863f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
864f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
865f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware
866f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
867f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
868f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
869f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma
87025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @len: length of buf
871f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
872f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
873f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
874f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
875f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
877f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd interrogate");
878f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
879d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
880f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
881f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
882d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
884fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len);
885fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (ret < 0)
886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("INTERROGATE command failed");
887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware
893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
894f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
895f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
896f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma
897f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf
898f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
899f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
900f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
901f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
902f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
904c91d06006dd327153d163e5299b8c92f82da86b3Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id);
905f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
906d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
908f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
909d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
911fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("CONFIGURE command NOK");
914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return 0;
918f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
92094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct cmd_enabledisable_path *cmd;
923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u16 cmd_rx, cmd_tx;
925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd data path");
927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
931f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
932f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
933f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
93494210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	/* the channel here is only used for calibration, so hardcoded to 1 */
93594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	cmd->channel = 1;
936f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
937f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (enable) {
938f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_ENABLE_RX;
939f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_ENABLE_TX;
940f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
941f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_DISABLE_RX;
942f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_DISABLE_TX;
943f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
944f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
945fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
946f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
947f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("rx %s cmd for channel %d failed",
94894210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
949f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
950f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
951f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
952f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
95394210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
954f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
955fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
956f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
957f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("tx %s cmd for channel %d failed",
95894210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
9591b00f2b560028a68cdbc57a0352163afd79822ddJuuso Oikarinen		goto out;
960f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
961f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
962f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
96394210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
964f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
965f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
966f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
967f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
968f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
969f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
9700603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
9710603d891c5b5153f667a79357d4652824c22b54eEliad Peller		       u8 ps_mode)
972f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
973f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_ps_params *ps_params = NULL;
974f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
975f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
976f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set ps mode");
977f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
978f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
979f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!ps_params) {
980f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
981f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
982f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
983f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
9840603d891c5b5153f667a79357d4652824c22b54eEliad Peller	ps_params->role_id = wlvif->role_id;
985f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params->ps_mode = ps_mode;
986f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
987f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
988fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen			      sizeof(*ps_params), 0);
989f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
990f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("cmd set_ps_mode failed");
991f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
992f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
993f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
994f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
995f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(ps_params);
996f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
997f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
998f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
999f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
1000606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen			    void *buf, size_t buf_len, int index, u32 rates)
1001f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1002f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_template_set *cmd;
1003f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
1004f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1005f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
1006f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1007f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
1008f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
1009f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1010f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1011f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
1012f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
1013f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
1014f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1015f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1016f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->len = cpu_to_le16(buf_len);
1017f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->template_type = template_id;
1018606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	cmd->enabled_rates = cpu_to_le32(rates);
10191e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
10201e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
1021bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	cmd->index = index;
1022f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1023f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (buf)
1024f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->template_data, buf, buf_len);
1025f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1026fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0);
1027f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
1028f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_template failed: %d", ret);
1029f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
1030f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1031f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1032f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
1033f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
1034f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1035f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
1036f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
1037f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1038f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1039d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
1040f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1041a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	struct sk_buff *skb = NULL;
1042a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int size;
1043a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	void *ptr;
1044a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int ret = -ENOMEM;
1045f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1046f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1047536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	if (wlvif->bss_type == BSS_TYPE_IBSS) {
1048a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = sizeof(struct wl12xx_null_data_template);
1049a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = NULL;
1050a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	} else {
1051d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller		skb = ieee80211_nullfunc_get(wl->hw,
1052d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller					     wl12xx_wlvif_to_vif(wlvif));
1053a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		if (!skb)
1054a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen			goto out;
1055a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = skb->len;
1056a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = skb->data;
1057a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	}
1058a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
1059606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
1060d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller				      wlvif->basic_rate);
1061f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1062899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
1063899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
1064a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (ret)
1065a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		wl1271_warning("cmd buld null data failed %d", ret);
1066a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
1067899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
1068f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1069f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1070f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1071d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
1072d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller				   struct wl12xx_vif *wlvif)
1073bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen{
1074d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
1075bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	struct sk_buff *skb = NULL;
1076bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	int ret = -ENOMEM;
1077bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
1078d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller	skb = ieee80211_nullfunc_get(wl->hw, vif);
1079bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (!skb)
1080bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		goto out;
1081bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
1082bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
1083bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen				      skb->data, skb->len,
1084606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				      CMD_TEMPL_KLV_IDX_NULL_DATA,
1085d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller				      wlvif->basic_rate);
1086bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
1087bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenout:
1088bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	dev_kfree_skb(skb);
1089bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (ret)
1090bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		wl1271_warning("cmd build klv null data failed %d", ret);
1091bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
1092bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	return ret;
1093bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
1094bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen}
1095bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
109687fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
109787fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller			     u16 aid)
1098f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1099899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	struct sk_buff *skb;
1100899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	int ret = 0;
1101c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen
1102899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	skb = ieee80211_pspoll_get(wl->hw, wl->vif);
1103899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	if (!skb)
1104899e6e65c39990a76c17940625dbe6001f618734Kalle Valo		goto out;
1105f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1106899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
110787fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller				      skb->len, 0, wlvif->basic_rate_set);
1108f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1109899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
1110899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
1111899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
1112f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1113f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
111483587505a2b63bb434f76b26a22f48283b86a467Eliad Pellerint wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1115818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ssid, size_t ssid_len,
1116818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ie, size_t ie_len, u8 band)
1117f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
111883587505a2b63bb434f76b26a22f48283b86a467Eliad Peller	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
1119818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	struct sk_buff *skb;
1120abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	int ret;
1121af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller	u32 rate;
1122f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
112383587505a2b63bb434f76b26a22f48283b86a467Eliad Peller	skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
1124818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo				     ie, ie_len);
1125818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	if (!skb) {
1126818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		ret = -ENOMEM;
1127818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		goto out;
1128818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	}
1129818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
1130818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
1131f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
113283587505a2b63bb434f76b26a22f48283b86a467Eliad Peller	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
1133abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	if (band == IEEE80211_BAND_2GHZ)
1134abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
1135af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller					      skb->data, skb->len, 0, rate);
1136abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	else
1137abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
1138af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller					      skb->data, skb->len, 0, rate);
1139818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
1140818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoout:
1141818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	dev_kfree_skb(skb);
1142abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	return ret;
1143f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1144f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
11452f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenstruct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
114683587505a2b63bb434f76b26a22f48283b86a467Eliad Peller					      struct wl12xx_vif *wlvif,
11472f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      struct sk_buff *skb)
11482f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen{
114983587505a2b63bb434f76b26a22f48283b86a467Eliad Peller	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
11502f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	int ret;
1151af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller	u32 rate;
11522f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
11532f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
115483587505a2b63bb434f76b26a22f48283b86a467Eliad Peller		skb = ieee80211_ap_probereq_get(wl->hw, vif);
11552f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
11562f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		goto out;
11572f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
11582f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
11592f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
11601b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
11611b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	if (wlvif->band == IEEE80211_BAND_2GHZ)
11622f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
1163af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller					      skb->data, skb->len, 0, rate);
11642f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	else
11652f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
1166af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller					      skb->data, skb->len, 0, rate);
11672f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
11682f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (ret < 0)
11692f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		wl1271_error("Unable to set ap probe request template.");
11702f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
11712f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenout:
11722f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	return skb;
11732f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen}
11742f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
1175d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1176d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller			     __be32 ip_addr)
1177c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller{
1178c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	int ret;
1179c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct wl12xx_arp_rsp_template tmpl;
1180c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct ieee80211_hdr_3addr *hdr;
1181c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct arphdr *arp_hdr;
1182c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1183c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(&tmpl, 0, sizeof(tmpl));
1184c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1185c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* mac80211 header */
1186c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr = &tmpl.hdr;
1187c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1188c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_STYPE_DATA |
1189c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_FCTL_TODS);
1190c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
1191c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
1192c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(hdr->addr3, 0xff, ETH_ALEN);
1193c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1194c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* llc layer */
1195c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
11966177eaea277527e48753d050723cd138494c98a8Eliad Peller	tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
1197c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1198c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp header */
1199c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr = &tmpl.arp_hdr;
12006177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
12016177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
1202c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_hln = ETH_ALEN;
1203c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_pln = 4;
12046177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
1205c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1206c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp payload */
1207c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
1208c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	tmpl.sender_ip = ip_addr;
1209c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1210c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
1211c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      &tmpl, sizeof(tmpl), 0,
1212d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller				      wlvif->basic_rate);
1213c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1214c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	return ret;
1215c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller}
1216c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
1217784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Pellerint wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
1218023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo{
1219d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1220023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	struct ieee80211_qos_hdr template;
1221023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1222023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memset(&template, 0, sizeof(template));
1223023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1224cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN);
1225784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller	memcpy(template.addr2, vif->addr, ETH_ALEN);
1226cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller	memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN);
1227023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1228023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1229023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_STYPE_QOS_NULLFUNC |
1230023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_FCTL_TODS);
1231023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1232023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	/* FIXME: not sure what priority to use here */
1233023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.qos_ctrl = cpu_to_le16(0);
1234023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1235023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
1236606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				       sizeof(template), 0,
1237d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller				       wlvif->basic_rate);
1238023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo}
1239023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
1240c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
1241f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1242c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl1271_cmd_set_keys *cmd;
1243f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
1244f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1245f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
1246f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1247f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1248f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
1249f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
1250f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
1251f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1252f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1253c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->hlid = hlid;
125498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
125598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
125698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(KEY_SET_ID);
125798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = KEY_WEP;
125898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
125998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
126098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
1261c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_warning("cmd set_default_wep_key failed: %d", ret);
126298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
126398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
126498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
126598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
126698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
126798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
126898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
126998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
127098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1271a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Pellerint wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1272154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller		       u16 action, u8 id, u8 key_type,
1273ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u8 key_size, const u8 *key, const u8 *addr,
1274ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u32 tx_seq_32, u16 tx_seq_16)
1275f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1276c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl1271_cmd_set_keys *cmd;
1277f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
1278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1279b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller	/* hlid might have already been deleted */
1280154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
1281b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller		return 0;
1282b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller
1283f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1284f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
1285f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
1286f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
1287f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1288f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1289154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller	cmd->hlid = wlvif->sta.hlid;
1290c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller
1291c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	if (key_type == KEY_WEP)
1292c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
1293c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	else if (is_broadcast_ether_addr(addr))
1294c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->lid_key_type = BROADCAST_LID_TYPE;
1295c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	else
1296c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		cmd->lid_key_type = UNICAST_LID_TYPE;
1297f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1298d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(action);
1299f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_size = key_size;
1300f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = key_type;
1301f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1302d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
1303d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
1304ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen
1305c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	cmd->key_id = id;
1306f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1307f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type == KEY_TKIP) {
1308f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		/*
1309f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * We get the key in the following form:
1310f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
1311f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * but the target is expecting:
1312f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP - RX MIC - TX MIC
1313f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 */
1314f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, 16);
1315f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 16, key + 24, 8);
1316f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 24, key + 16, 8);
1317f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1318f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
1319f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, key_size);
1320f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1321f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1322f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
1323f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1324fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
1325f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
1326f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("could not set keys");
1327152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	goto out;
1328f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1329f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1330f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
1331f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
1332f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1333f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
1334f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
133525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
1336c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller/*
1337c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller * TODO: merge with sta/ibss into 1 set_key function.
1338c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller * note there are slight diffs
1339c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller */
1340a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Pellerint wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1341a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller			  u16 action, u8 id, u8 key_type,
1342a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller			  u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1343a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller			  u16 tx_seq_16)
134498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
1345c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl1271_cmd_set_keys *cmd;
134698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
134798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	u8 lid_type;
134898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
134998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
135098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd)
135198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		return -ENOMEM;
135298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1353a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller	if (hlid == wlvif->ap.bcast_hlid) {
135498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		if (key_type == KEY_WEP)
135598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = WEP_DEFAULT_LID_TYPE;
135698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		else
135798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = BROADCAST_LID_TYPE;
135898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
135998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		lid_type = UNICAST_LID_TYPE;
136098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
136198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
136298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
136398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     " hlid: %d", (int)action, (int)id, (int)lid_type,
136498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     (int)key_type, (int)hlid);
136598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
136698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = lid_type;
136798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
136898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(action);
136998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_size = key_size;
137098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = key_type;
137198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
137298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
137398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
137498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
137598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (key_type == KEY_TKIP) {
137698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		/*
137798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * We get the key in the following form:
137898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
137998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * but the target is expecting:
138098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP - RX MIC - TX MIC
138198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 */
138298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, 16);
138398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 16, key + 24, 8);
138498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 24, key + 16, 8);
138598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
138698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, key_size);
138798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
138898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
138998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
139098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
139198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
139298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
139398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("could not set ap keys");
139498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
139598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
139698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
139798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
139898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
139998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
140098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
140198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1402b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Pellerint wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
1403be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen{
1404c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_set_peer_state *cmd;
1405be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	int ret = 0;
1406be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1407b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Peller	wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid);
1408be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1409be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1410be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (!cmd) {
1411be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		ret = -ENOMEM;
1412be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out;
1413be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1414be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1415b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Peller	cmd->hlid = hlid;
1416be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
1417be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1418c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
1419be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (ret < 0) {
1420c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to send set peer state command");
1421be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out_free;
1422be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1423be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1424be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout_free:
1425be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	kfree(cmd);
1426be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1427be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout:
1428be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	return ret;
1429be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen}
143099d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov
14311b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerint wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
14321b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller			struct ieee80211_sta *sta, u8 hlid)
143398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
1434c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_add_peer *cmd;
14351ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller	int i, ret;
143699d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov	u32 sta_rates;
143798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1438c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid);
143998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
144098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
144198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
144298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
144398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
144498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
144598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
144698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->addr, sta->addr, ETH_ALEN);
144798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
144898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->aid = sta->aid;
144998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
14501ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller	cmd->sp_len = sta->max_sp;
1451b4d38db121c19fe94862357763b374e44fc23ebbArik Nemtsov	cmd->wmm = sta->wme ? 1 : 0;
145298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
14531ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller	for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
14541ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller		if (sta->wme && (sta->uapsd_queues & BIT(i)))
14551ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller			cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
14561ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller		else
14571ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller			cmd->psd_type[i] = WL1271_PSD_LEGACY;
14581ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller
14591b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	sta_rates = sta->supp_rates[wlvif->band];
146099d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov	if (sta->ht_cap.ht_supported)
146199d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov		sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
146299d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov
146399d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov	cmd->supported_rates =
1464af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller		cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
14651b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller							wlvif->band));
146698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
14671ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller	wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
14681ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller		     cmd->supported_rates, sta->uapsd_queues);
146998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1470c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
147198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
1472c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd add peer");
147398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
147498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
147598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
147698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
147798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
147898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
147998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
148098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
148198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
148298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1483c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
148498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
1485c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	struct wl12xx_cmd_remove_peer *cmd;
148698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
148798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1488c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
148998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
149098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
149198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
149298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
149398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
149498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
149598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
149698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
149798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* We never send a deauth, mac80211 is in charge of this */
149898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->reason_opcode = 0;
149998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->send_deauth_flag = 0;
150098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
1501c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
150298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
1503c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		wl1271_error("failed to initiate cmd remove peer");
150498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
150598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
150698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
150705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	/*
150805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * We are ok with a timeout here. The event is sometimes not sent
150905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * due to a firmware bug.
151005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 */
1511c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller	wl1271_cmd_wait_for_event_or_timeout(wl,
1512c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller					     PEER_REMOVE_COMPLETE_EVENT_ID);
151398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
151498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
151598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
151698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
151798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
151898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
151998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
152095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
152195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_config_fwlog(struct wl1271 *wl)
152295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
152395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_config_fwlog *cmd;
152495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
152595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
152695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
152795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
152895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
152995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
153095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
153195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
153295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
153395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
153495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->logger_mode = wl->conf.fwlog.mode;
153595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->log_severity = wl->conf.fwlog.severity;
153695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->timestamp = wl->conf.fwlog.timestamp;
153795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->output = wl->conf.fwlog.output;
153895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->threshold = wl->conf.fwlog.threshold;
153995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
154095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
154195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
154295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send config firmware logger command");
154395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
154495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
154595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
154695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
154795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
154895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
154995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
155095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
155195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
155295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
155395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_start_fwlog(struct wl1271 *wl)
155495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
155595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_start_fwlog *cmd;
155695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
155795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
155895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
155995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
156095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
156195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
156295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
156395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
156495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
156595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
156695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
156795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
156895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send start firmware logger command");
156995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
157095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
157195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
157295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
157395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
157495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
157595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
157695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
157795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
157895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
157995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
158095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
158195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_stop_fwlog *cmd;
158295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
158395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
158495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
158595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
158695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
158795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
158895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
158995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
159095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
159195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
159295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
159395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
159495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send stop firmware logger command");
159595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
159695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
159795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
159895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
159995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
160095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
160195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
160295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
160395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
1604a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
16051b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerstatic int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
16061b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller			  u8 role_id)
1607a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{
1608a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	struct wl12xx_cmd_roc *cmd;
1609a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	int ret = 0;
1610a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
161161f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id);
1612a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1613a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
1614a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		return -EINVAL;
1615a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1616a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1617a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	if (!cmd) {
1618a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		ret = -ENOMEM;
1619a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		goto out;
1620a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	}
1621a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1622a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	cmd->role_id = role_id;
162361f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller	cmd->channel = wlvif->channel;
16241b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	switch (wlvif->band) {
1625a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	case IEEE80211_BAND_2GHZ:
1626a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		cmd->band = RADIO_BAND_2_4GHZ;
1627a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		break;
1628a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	case IEEE80211_BAND_5GHZ:
1629a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		cmd->band = RADIO_BAND_5GHZ;
1630a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		break;
1631a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	default:
16321b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller		wl1271_error("roc - unknown band: %d", (int)wlvif->band);
1633a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		ret = -EINVAL;
1634a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		goto out_free;
1635a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	}
1636a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1637a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1638a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0);
1639a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	if (ret < 0) {
1640a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		wl1271_error("failed to send ROC command");
1641a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		goto out_free;
1642a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	}
1643a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1644a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free:
1645a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	kfree(cmd);
1646a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1647a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout:
1648a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	return ret;
1649a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller}
1650a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1651a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerstatic int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id)
1652a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{
1653a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	struct wl12xx_cmd_croc *cmd;
1654a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	int ret = 0;
1655a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1656a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id);
1657a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1658a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1659a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	if (!cmd) {
1660a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		ret = -ENOMEM;
1661a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		goto out;
1662a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	}
1663a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	cmd->role_id = role_id;
1664a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1665a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
1666a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller			      sizeof(*cmd), 0);
1667a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	if (ret < 0) {
1668a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		wl1271_error("failed to send ROC command");
1669a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller		goto out_free;
1670a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	}
1671a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1672a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free:
1673a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	kfree(cmd);
1674a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller
1675a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout:
1676a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller	return ret;
1677a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller}
1678251c177f886027fbce494202e44935762f103137Eliad Peller
16791b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerint wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
1680251c177f886027fbce494202e44935762f103137Eliad Peller{
1681251c177f886027fbce494202e44935762f103137Eliad Peller	int ret = 0;
1682251c177f886027fbce494202e44935762f103137Eliad Peller
1683251c177f886027fbce494202e44935762f103137Eliad Peller	if (WARN_ON(test_bit(role_id, wl->roc_map)))
1684251c177f886027fbce494202e44935762f103137Eliad Peller		return 0;
1685251c177f886027fbce494202e44935762f103137Eliad Peller
16861b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller	ret = wl12xx_cmd_roc(wl, wlvif, role_id);
1687251c177f886027fbce494202e44935762f103137Eliad Peller	if (ret < 0)
1688251c177f886027fbce494202e44935762f103137Eliad Peller		goto out;
1689251c177f886027fbce494202e44935762f103137Eliad Peller
1690251c177f886027fbce494202e44935762f103137Eliad Peller	ret = wl1271_cmd_wait_for_event(wl,
1691251c177f886027fbce494202e44935762f103137Eliad Peller					REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
1692251c177f886027fbce494202e44935762f103137Eliad Peller	if (ret < 0) {
1693251c177f886027fbce494202e44935762f103137Eliad Peller		wl1271_error("cmd roc event completion error");
1694251c177f886027fbce494202e44935762f103137Eliad Peller		goto out;
1695251c177f886027fbce494202e44935762f103137Eliad Peller	}
1696251c177f886027fbce494202e44935762f103137Eliad Peller
1697251c177f886027fbce494202e44935762f103137Eliad Peller	__set_bit(role_id, wl->roc_map);
1698251c177f886027fbce494202e44935762f103137Eliad Pellerout:
1699251c177f886027fbce494202e44935762f103137Eliad Peller	return ret;
1700251c177f886027fbce494202e44935762f103137Eliad Peller}
1701251c177f886027fbce494202e44935762f103137Eliad Peller
1702251c177f886027fbce494202e44935762f103137Eliad Pellerint wl12xx_croc(struct wl1271 *wl, u8 role_id)
1703251c177f886027fbce494202e44935762f103137Eliad Peller{
1704251c177f886027fbce494202e44935762f103137Eliad Peller	int ret = 0;
1705251c177f886027fbce494202e44935762f103137Eliad Peller
1706251c177f886027fbce494202e44935762f103137Eliad Peller	if (WARN_ON(!test_bit(role_id, wl->roc_map)))
1707251c177f886027fbce494202e44935762f103137Eliad Peller		return 0;
1708251c177f886027fbce494202e44935762f103137Eliad Peller
1709251c177f886027fbce494202e44935762f103137Eliad Peller	ret = wl12xx_cmd_croc(wl, role_id);
1710251c177f886027fbce494202e44935762f103137Eliad Peller	if (ret < 0)
1711251c177f886027fbce494202e44935762f103137Eliad Peller		goto out;
1712251c177f886027fbce494202e44935762f103137Eliad Peller
1713251c177f886027fbce494202e44935762f103137Eliad Peller	__clear_bit(role_id, wl->roc_map);
1714251c177f886027fbce494202e44935762f103137Eliad Pellerout:
1715251c177f886027fbce494202e44935762f103137Eliad Peller	return ret;
1716251c177f886027fbce494202e44935762f103137Eliad Peller}
17176d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17186d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_channel_switch(struct wl1271 *wl,
17196d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi			      struct ieee80211_channel_switch *ch_switch)
17206d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{
17216d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	struct wl12xx_cmd_channel_switch *cmd;
17226d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	int ret;
17236d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17246d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	wl1271_debug(DEBUG_ACX, "cmd channel switch");
17256d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17266d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
17276d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	if (!cmd) {
17286d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		ret = -ENOMEM;
17296d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		goto out;
17306d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	}
17316d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17326d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd->channel = ch_switch->channel->hw_value;
17336d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd->switch_time = ch_switch->count;
17346d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd->tx_suspend = ch_switch->block_tx;
17356d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd->flush = 0; /* this value is ignored by the FW */
17366d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17376d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
17386d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	if (ret < 0) {
17396d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		wl1271_error("failed to send channel switch command");
17406d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		goto out_free;
17416d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	}
17426d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17436d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free:
17446d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	kfree(cmd);
17456d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17466d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout:
17476d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	return ret;
17486d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi}
17496d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17506d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
17516d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{
17526d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	struct wl12xx_cmd_stop_channel_switch *cmd;
17536d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	int ret;
17546d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17556d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	wl1271_debug(DEBUG_ACX, "cmd stop channel switch");
17566d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17576d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
17586d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	if (!cmd) {
17596d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		ret = -ENOMEM;
17606d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		goto out;
17616d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	}
17626d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17636d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0);
17646d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	if (ret < 0) {
17656d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		wl1271_error("failed to stop channel switch command");
17666d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi		goto out_free;
17676d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	}
17686d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17696d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free:
17706d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	kfree(cmd);
17716d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi
17726d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout:
17736d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi	return ret;
17746d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi}
1775