cmd.c revision 83587505a2b63bb434f76b26a22f48283b86a467
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; 48404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (wl->band == IEEE80211_BAND_5GHZ) 48504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->band = WL12XX_BAND_5GHZ; 48604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->channel = wl->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; 574ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinen if (wl->band == IEEE80211_BAND_5GHZ) 575c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->band = WL12XX_BAND_5GHZ; 576c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->channel = wl->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; 692c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->channel = wl->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 707c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller switch (wl->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: 715c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_warning("ap start - unknown band: %d", (int)wl->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; 78831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller if (wl->band == IEEE80211_BAND_5GHZ) 78931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd->band = WL12XX_BAND_5GHZ; 79031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd->channel = wl->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 116083587505a2b63bb434f76b26a22f48283b86a467Eliad Peller rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wl->band]); 11612f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen if (wl->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 1431c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) 143298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{ 1433c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_add_peer *cmd; 14341ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller int i, ret; 143599d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov u32 sta_rates; 143698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1437c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); 143898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 143998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 144098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (!cmd) { 144198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = -ENOMEM; 144298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 144398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 144498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 144598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->addr, sta->addr, ETH_ALEN); 144698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->bss_index = WL1271_AP_BSS_INDEX; 144798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->aid = sta->aid; 144898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->hlid = hlid; 14491ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->sp_len = sta->max_sp; 1450b4d38db121c19fe94862357763b374e44fc23ebbArik Nemtsov cmd->wmm = sta->wme ? 1 : 0; 145198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 14521ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) 14531ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller if (sta->wme && (sta->uapsd_queues & BIT(i))) 14541ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; 14551ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller else 14561ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->psd_type[i] = WL1271_PSD_LEGACY; 14571ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller 145899d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov sta_rates = sta->supp_rates[wl->band]; 145999d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov if (sta->ht_cap.ht_supported) 146099d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; 146199d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov 146299d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov cmd->supported_rates = 1463af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, 1464af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller wl->band)); 146598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 14661ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", 14671ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->supported_rates, sta->uapsd_queues); 146898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1469c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); 147098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 1471c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd add peer"); 147298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out_free; 147398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 147498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 147598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free: 147698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 147798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 147898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 147998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 148098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 148198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1482c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) 148398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{ 1484c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_remove_peer *cmd; 148598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov int ret; 148698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1487c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); 148898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 148998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 149098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (!cmd) { 149198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = -ENOMEM; 149298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 149398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 149498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 149598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->hlid = hlid; 149698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov /* We never send a deauth, mac80211 is in charge of this */ 149798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->reason_opcode = 0; 149898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->send_deauth_flag = 0; 149998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1500c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); 150198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 1502c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd remove peer"); 150398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out_free; 150498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 150598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 150605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov /* 150705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov * We are ok with a timeout here. The event is sometimes not sent 150805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov * due to a firmware bug. 150905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov */ 1510c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_cmd_wait_for_event_or_timeout(wl, 1511c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller PEER_REMOVE_COMPLETE_EVENT_ID); 151298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 151398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free: 151498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 151598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 151698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 151798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 151898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 151995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 152095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_config_fwlog(struct wl1271 *wl) 152195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 152295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_config_fwlog *cmd; 152395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 152495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 152595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); 152695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 152795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 152895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 152995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 153095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 153195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 153295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 153395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->logger_mode = wl->conf.fwlog.mode; 153495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->log_severity = wl->conf.fwlog.severity; 153595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->timestamp = wl->conf.fwlog.timestamp; 153695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->output = wl->conf.fwlog.output; 153795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->threshold = wl->conf.fwlog.threshold; 153895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 153995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); 154095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 154195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send config firmware logger command"); 154295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 154395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 154495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 154595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 154695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 154795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 154895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 154995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 155095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 155195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 155295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_start_fwlog(struct wl1271 *wl) 155395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 155495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_start_fwlog *cmd; 155595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 155695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 155795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); 155895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 155995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 156095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 156195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 156295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 156395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 156495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 156595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); 156695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 156795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send start firmware logger command"); 156895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 156995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 157095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 157195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 157295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 157395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 157495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 157595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 157695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 157795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 157895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_stop_fwlog(struct wl1271 *wl) 157995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 158095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_stop_fwlog *cmd; 158195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 158295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 158395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); 158495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 158595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 158695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 158795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 158895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 158995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 159095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 159195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); 159295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 159395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send stop firmware logger command"); 159495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 159595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 159695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 159795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 159895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 159995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 160095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 160195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 160295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 1603a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1604a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerstatic int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) 1605a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{ 1606a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller struct wl12xx_cmd_roc *cmd; 1607a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller int ret = 0; 1608a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1609a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id); 1610a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1611a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) 1612a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return -EINVAL; 1613a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1614a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1615a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (!cmd) { 1616a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -ENOMEM; 1617a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out; 1618a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1619a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1620a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->role_id = role_id; 1621a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->channel = wl->channel; 1622a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller switch (wl->band) { 1623a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller case IEEE80211_BAND_2GHZ: 1624a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->band = RADIO_BAND_2_4GHZ; 1625a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller break; 1626a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller case IEEE80211_BAND_5GHZ: 1627a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->band = RADIO_BAND_5GHZ; 1628a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller break; 1629a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller default: 1630a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_error("roc - unknown band: %d", (int)wl->band); 1631a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -EINVAL; 1632a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1633a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1634a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1635a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1636a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); 1637a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (ret < 0) { 1638a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_error("failed to send ROC command"); 1639a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1640a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1641a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1642a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free: 1643a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller kfree(cmd); 1644a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1645a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout: 1646a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return ret; 1647a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller} 1648a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1649a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerstatic int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) 1650a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{ 1651a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller struct wl12xx_cmd_croc *cmd; 1652a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller int ret = 0; 1653a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1654a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); 1655a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1656a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1657a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (!cmd) { 1658a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -ENOMEM; 1659a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out; 1660a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1661a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->role_id = role_id; 1662a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1663a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, 1664a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller sizeof(*cmd), 0); 1665a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (ret < 0) { 1666a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_error("failed to send ROC command"); 1667a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1668a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1669a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1670a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free: 1671a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller kfree(cmd); 1672a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1673a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout: 1674a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return ret; 1675a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller} 1676251c177f886027fbce494202e44935762f103137Eliad Peller 1677251c177f886027fbce494202e44935762f103137Eliad Pellerint wl12xx_roc(struct wl1271 *wl, u8 role_id) 1678251c177f886027fbce494202e44935762f103137Eliad Peller{ 1679251c177f886027fbce494202e44935762f103137Eliad Peller int ret = 0; 1680251c177f886027fbce494202e44935762f103137Eliad Peller 1681251c177f886027fbce494202e44935762f103137Eliad Peller if (WARN_ON(test_bit(role_id, wl->roc_map))) 1682251c177f886027fbce494202e44935762f103137Eliad Peller return 0; 1683251c177f886027fbce494202e44935762f103137Eliad Peller 1684251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl12xx_cmd_roc(wl, role_id); 1685251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 1686251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1687251c177f886027fbce494202e44935762f103137Eliad Peller 1688251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl1271_cmd_wait_for_event(wl, 1689251c177f886027fbce494202e44935762f103137Eliad Peller REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); 1690251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) { 1691251c177f886027fbce494202e44935762f103137Eliad Peller wl1271_error("cmd roc event completion error"); 1692251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1693251c177f886027fbce494202e44935762f103137Eliad Peller } 1694251c177f886027fbce494202e44935762f103137Eliad Peller 1695251c177f886027fbce494202e44935762f103137Eliad Peller __set_bit(role_id, wl->roc_map); 1696251c177f886027fbce494202e44935762f103137Eliad Pellerout: 1697251c177f886027fbce494202e44935762f103137Eliad Peller return ret; 1698251c177f886027fbce494202e44935762f103137Eliad Peller} 1699251c177f886027fbce494202e44935762f103137Eliad Peller 1700251c177f886027fbce494202e44935762f103137Eliad Pellerint wl12xx_croc(struct wl1271 *wl, u8 role_id) 1701251c177f886027fbce494202e44935762f103137Eliad Peller{ 1702251c177f886027fbce494202e44935762f103137Eliad Peller int ret = 0; 1703251c177f886027fbce494202e44935762f103137Eliad Peller 1704251c177f886027fbce494202e44935762f103137Eliad Peller if (WARN_ON(!test_bit(role_id, wl->roc_map))) 1705251c177f886027fbce494202e44935762f103137Eliad Peller return 0; 1706251c177f886027fbce494202e44935762f103137Eliad Peller 1707251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl12xx_cmd_croc(wl, role_id); 1708251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 1709251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1710251c177f886027fbce494202e44935762f103137Eliad Peller 1711251c177f886027fbce494202e44935762f103137Eliad Peller __clear_bit(role_id, wl->roc_map); 1712251c177f886027fbce494202e44935762f103137Eliad Pellerout: 1713251c177f886027fbce494202e44935762f103137Eliad Peller return ret; 1714251c177f886027fbce494202e44935762f103137Eliad Peller} 17156d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17166d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_channel_switch(struct wl1271 *wl, 17176d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct ieee80211_channel_switch *ch_switch) 17186d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{ 17196d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct wl12xx_cmd_channel_switch *cmd; 17206d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi int ret; 17216d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17226d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_debug(DEBUG_ACX, "cmd channel switch"); 17236d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17246d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 17256d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (!cmd) { 17266d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = -ENOMEM; 17276d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out; 17286d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17296d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17306d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->channel = ch_switch->channel->hw_value; 17316d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->switch_time = ch_switch->count; 17326d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->tx_suspend = ch_switch->block_tx; 17336d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->flush = 0; /* this value is ignored by the FW */ 17346d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17356d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 17366d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (ret < 0) { 17376d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_error("failed to send channel switch command"); 17386d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out_free; 17396d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17406d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17416d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free: 17426d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi kfree(cmd); 17436d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17446d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout: 17456d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi return ret; 17466d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi} 17476d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17486d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) 17496d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{ 17506d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct wl12xx_cmd_stop_channel_switch *cmd; 17516d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi int ret; 17526d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17536d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); 17546d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17556d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 17566d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (!cmd) { 17576d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = -ENOMEM; 17586d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out; 17596d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17606d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17616d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); 17626d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (ret < 0) { 17636d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_error("failed to stop channel switch command"); 17646d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out_free; 17656d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17666d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17676d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free: 17686d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi kfree(cmd); 17696d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17706d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout: 17716d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi return ret; 17726d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi} 1773