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" 320f4e31222a2c0b93f25a87effd2033cb78c7a79cLuciano Coelho#include "debug.h" 3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "reg.h" 3400d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h" 3500d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "acx.h" 36f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl12xx_80211.h" 3700d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "cmd.h" 3800d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "event.h" 3998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov#include "tx.h" 40f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 4116092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen#define WL1271_CMD_FAST_POLL_COUNT 50 42f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 43f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* 44f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send command to firmware 45f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 46f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 47f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: command id 48f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, must work with dma 49f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer 50f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 51fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinenint wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, 52fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen size_t res_len) 53f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 54f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_header *cmd; 55f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho unsigned long timeout; 56f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 intr; 57f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 58ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen u16 status; 59bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal u16 poll_count = 0; 60f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 61f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = buf; 62d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->id = cpu_to_le16(id); 63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->status = 0; 64f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 65f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WARN_ON(len % 4 != 0); 6624225b37bd78d3e2edaa1a39316c54786adaa465Arik Nemtsov WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); 67f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 687b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_write(wl, wl->cmd_box_addr, buf, len, false); 69f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 707b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); 71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); 73f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 747b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); 75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { 76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (time_after(jiffies, timeout)) { 77f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("command complete timeout"); 78f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ETIMEDOUT; 79f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov goto fail; 80f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 81f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 82bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal poll_count++; 8316092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen if (poll_count < WL1271_CMD_FAST_POLL_COUNT) 8416092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen udelay(10); 8516092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen else 8616092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen msleep(1); 87f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 887b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); 89f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 90f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 913b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen /* read back the status code of the command */ 92fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen if (res_len == 0) 93fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen res_len = sizeof(struct wl1271_cmd_header); 947b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); 953b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen 96ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen status = le16_to_cpu(cmd->status); 97ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen if (status != CMD_STATUS_SUCCESS) { 98ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen wl1271_error("command execute failure %d", status); 993b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen ret = -EIO; 100f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov goto fail; 1013b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen } 1023b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen 1037b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, 1047b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi WL1271_ACX_INTR_CMD_COMPLETE); 105f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov return 0; 106f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 107f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsovfail: 108f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov WARN_ON(1); 109baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv wl12xx_queue_recovery_work(wl); 110f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 111f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 112f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 11398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_general_parms(struct wl1271 *wl) 11498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{ 11598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho struct wl1271_general_parms_cmd *gen_parms; 11649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl1271_ini_general_params *gp = 11749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi &((struct wl1271_nvs_file *)wl->nvs)->general_params; 11849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi bool answer = false; 11949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi int ret; 12049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 12149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (!wl->nvs) 12249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi return -ENODEV; 12349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 1242131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 1252131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs wl1271_warning("FEM index from INI out of bounds"); 1262131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs return -EINVAL; 1272131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs } 1282131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs 12949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 13049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (!gen_parms) 13149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi return -ENOMEM; 13249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 13349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 13449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 13549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 13649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 13749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (gp->tx_bip_fem_auto_detect) 13849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi answer = true; 13949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 140b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi /* Override the REF CLK from the NVS with the one from platform data */ 141b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi gen_parms->general_params.ref_clock = wl->ref_clock; 142b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi 14349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 14449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (ret < 0) { 14549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 14649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi goto out; 14749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi } 14849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 14949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi gp->tx_bip_fem_manufacturer = 15049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi gen_parms->general_params.tx_bip_fem_manufacturer; 15149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 1522131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 1532131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs wl1271_warning("FEM index from FW out of bounds"); 1542131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs ret = -EINVAL; 1552131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs goto out; 1562131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs } 1572131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs 15849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 15949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); 16049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 16149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviout: 16249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi kfree(gen_parms); 16349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi return ret; 16449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi} 16549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 16649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_general_parms(struct wl1271 *wl) 16749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{ 16849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl128x_general_parms_cmd *gen_parms; 16949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl128x_ini_general_params *gp = 17049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi &((struct wl128x_nvs_file *)wl->nvs)->general_params; 1714b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen bool answer = false; 17298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho int ret; 17398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 174152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen if (!wl->nvs) 175152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen return -ENODEV; 176152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen 1772131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 1782131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs wl1271_warning("FEM index from ini out of bounds"); 1792131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs return -EINVAL; 1802131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs } 1812131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs 18298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 18398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho if (!gen_parms) 18498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho return -ENOMEM; 18598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 18698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 18798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 1884b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 1894b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen 1904b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen if (gp->tx_bip_fem_auto_detect) 1914b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen answer = true; 19276c0f8d396bd306111d349cfe770e1c4fcf70248Luciano Coelho 193b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi /* Replace REF and TCXO CLKs with the ones from platform data */ 194b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi gen_parms->general_params.ref_clock = wl->ref_clock; 195b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock; 196b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi 1974b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 1984b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen if (ret < 0) { 19998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 2004b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen goto out; 2014b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen } 20298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 2034b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen gp->tx_bip_fem_manufacturer = 2044b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen gen_parms->general_params.tx_bip_fem_manufacturer; 2054b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen 2062131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 2072131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs wl1271_warning("FEM index from FW out of bounds"); 2082131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs ret = -EINVAL; 2092131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs goto out; 2102131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs } 2112131d3c2f99b081806fdae7662c92fe6acda52afPontus Fuchs 2124b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 2134b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); 2144b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen 2154b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinenout: 21698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho kfree(gen_parms); 21798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho return ret; 21898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho} 21998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 22098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_radio_parms(struct wl1271 *wl) 22198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{ 222bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; 22398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho struct wl1271_radio_parms_cmd *radio_parms; 224bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi struct wl1271_ini_general_params *gp = &nvs->general_params; 225152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen int ret; 226152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen 227152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen if (!wl->nvs) 228152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen return -ENODEV; 22998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 23098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 23198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho if (!radio_parms) 23298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho return -ENOMEM; 23398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 23498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 23598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 236a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen /* 2.4GHz parameters */ 237bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 238eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen sizeof(struct wl1271_ini_band_params_2)); 239eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen memcpy(&radio_parms->dyn_params_2, 240bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, 241eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen sizeof(struct wl1271_ini_fem_params_2)); 242152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen 243a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen /* 5GHz parameters */ 244a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen memcpy(&radio_parms->static_params_5, 245bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi &nvs->stat_radio_params_5, 246a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen sizeof(struct wl1271_ini_band_params_5)); 247a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen memcpy(&radio_parms->dyn_params_5, 248bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, 249a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen sizeof(struct wl1271_ini_fem_params_5)); 25098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 25198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 25298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho radio_parms, sizeof(*radio_parms)); 25398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 25498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 25598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho if (ret < 0) 25698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 25798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 25898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho kfree(radio_parms); 25998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho return ret; 26098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho} 26198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 26249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_radio_parms(struct wl1271 *wl) 26349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{ 26449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; 26549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl128x_radio_parms_cmd *radio_parms; 26649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi struct wl128x_ini_general_params *gp = &nvs->general_params; 26749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi int ret; 26849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 26949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (!wl->nvs) 27049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi return -ENODEV; 27149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 27249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 27349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi if (!radio_parms) 27449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi return -ENOMEM; 27549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 27649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 27749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 27849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi /* 2.4GHz parameters */ 27949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 28049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi sizeof(struct wl128x_ini_band_params_2)); 28149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi memcpy(&radio_parms->dyn_params_2, 28249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, 28349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi sizeof(struct wl128x_ini_fem_params_2)); 28449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 28549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi /* 5GHz parameters */ 28649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi memcpy(&radio_parms->static_params_5, 28749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi &nvs->stat_radio_params_5, 28849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi sizeof(struct wl128x_ini_band_params_5)); 28949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi memcpy(&radio_parms->dyn_params_5, 29049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, 29149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi sizeof(struct wl128x_ini_fem_params_5)); 29249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 29349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; 29449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 29549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 29649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi radio_parms, sizeof(*radio_parms)); 29749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi 29849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 29998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho if (ret < 0) 30098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 30198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 30298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho kfree(radio_parms); 30398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho return ret; 30498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho} 30598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho 306644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinenint wl1271_cmd_ext_radio_parms(struct wl1271 *wl) 307644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen{ 308644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen struct wl1271_ext_radio_parms_cmd *ext_radio_parms; 309644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen struct conf_rf_settings *rf = &wl->conf.rf; 310644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen int ret; 311644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 312644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen if (!wl->nvs) 313644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen return -ENODEV; 314644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 315644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); 316644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen if (!ext_radio_parms) 317644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen return -ENOMEM; 318644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 319644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; 320644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 321644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, 322644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen rf->tx_per_channel_power_compensation_2, 323644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen CONF_TX_PWR_COMPENSATION_LEN_2); 324644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, 325644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen rf->tx_per_channel_power_compensation_5, 326644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen CONF_TX_PWR_COMPENSATION_LEN_5); 327644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 328644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", 329644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen ext_radio_parms, sizeof(*ext_radio_parms)); 330644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 331644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); 332644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen if (ret < 0) 333644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); 334644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 335644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen kfree(ext_radio_parms); 336644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen return ret; 337644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen} 338644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen 33999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho/* 34099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * Poll the mailbox event field until any of the bits in the mask is set or a 34199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) 34299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho */ 34305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) 34499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho{ 34599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho u32 events_vector, event; 34699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho unsigned long timeout; 34799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 34899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); 34999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 35099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho do { 35152b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen if (time_after(jiffies, timeout)) { 35205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", 35305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov (int)mask); 35499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho return -ETIMEDOUT; 35552b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen } 35699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 35799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho msleep(1); 35899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 35999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho /* read from both event fields */ 36099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho wl1271_read(wl, wl->mbox_ptr[0], &events_vector, 36199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho sizeof(events_vector), false); 36299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho event = events_vector & mask; 36399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho wl1271_read(wl, wl->mbox_ptr[1], &events_vector, 36499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho sizeof(events_vector), false); 36599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho event |= events_vector & mask; 36699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho } while (!event); 36799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 36899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho return 0; 36999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho} 37099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho 37105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) 37205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov{ 37305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov int ret; 37405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov 37505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); 37605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov if (ret != 0) { 377baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv wl12xx_queue_recovery_work(wl); 37805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov return ret; 37905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov } 38005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov 38105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov return 0; 38205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov} 38305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov 384784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Pellerint wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, 385784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller u8 *role_id) 386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 387c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_enable *cmd; 388c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 389c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 390c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd role enable"); 391c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 392c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) 393c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return -EBUSY; 394c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 395c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 396c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 397c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -ENOMEM; 398c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 399c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 400c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 401c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller /* get role id */ 402c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); 403c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (cmd->role_id >= WL12XX_MAX_ROLES) { 404c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -EBUSY; 405c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 406c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 407c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 408784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller memcpy(cmd->mac_address, addr, ETH_ALEN); 409c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->role_type = role_type; 410c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 411c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); 412c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 413c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role enable"); 414c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 415c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 416c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 417c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller __set_bit(cmd->role_id, wl->roles_map); 418c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller *role_id = cmd->role_id; 419f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 420c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free: 421c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 422c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 423c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout: 424c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return ret; 425c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 426c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 427c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) 428c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 429c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_disable *cmd; 430c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 431c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 432c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd role disable"); 433c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 434c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) 435c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return -ENOENT; 436c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 437c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 438c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 439f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 440f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 441f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 442c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->role_id = *role_id; 443c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 444c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); 445c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 446c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role disable"); 447c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 448c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 449f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 450c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller __clear_bit(*role_id, wl->roles_map); 451c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller *role_id = WL12XX_INVALID_ROLE_ID; 452f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 453c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free: 454c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 455c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 456c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout: 457c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return ret; 458c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 459c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 460c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerint wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) 461c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 462c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); 463c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (link >= WL12XX_MAX_LINKS) 464c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return -EBUSY; 465c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 466c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller __set_bit(link, wl->links_map); 467c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller __set_bit(link, wlvif->links_map); 468c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller *hlid = link; 469c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return 0; 470c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 471c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 472c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellervoid wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) 473c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 474c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (*hlid == WL12XX_INVALID_LINK_ID) 475c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return; 476c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 477c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller __clear_bit(*hlid, wl->links_map); 478c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller __clear_bit(*hlid, wlvif->links_map); 479c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller *hlid = WL12XX_INVALID_LINK_ID; 480c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 481c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 48298b8625301e55bd3e4340f704edc378e4707e577Eliad Pellerstatic int wl12xx_get_new_session_id(struct wl1271 *wl, 48398b8625301e55bd3e4340f704edc378e4707e577Eliad Peller struct wl12xx_vif *wlvif) 484712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov{ 48598b8625301e55bd3e4340f704edc378e4707e577Eliad Peller if (wlvif->session_counter >= SESSION_COUNTER_MAX) 48698b8625301e55bd3e4340f704edc378e4707e577Eliad Peller wlvif->session_counter = 0; 487712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov 48898b8625301e55bd3e4340f704edc378e4707e577Eliad Peller wlvif->session_counter++; 489712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov 49098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller return wlvif->session_counter; 491712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov} 492712e9bf750c5d0db63040c5695dacf38aed4f42cArik Nemtsov 493679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerstatic int wl12xx_cmd_role_start_dev(struct wl1271 *wl, 494679a673414473239d189b5b41ea4014b088be7b9Eliad Peller struct wl12xx_vif *wlvif) 49504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller{ 49604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller struct wl12xx_cmd_role_start *cmd; 49704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller int ret; 49804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 49904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 50004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (!cmd) { 50104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller ret = -ENOMEM; 50204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out; 50304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 50404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 5057edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); 50604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 5077edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller cmd->role_id = wlvif->dev_role_id; 5081b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller if (wlvif->band == IEEE80211_BAND_5GHZ) 50904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->band = WL12XX_BAND_5GHZ; 51061f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller cmd->channel = wlvif->channel; 51104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 512afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { 513c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); 51404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (ret) 51504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out_free; 51604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 517afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller cmd->device.hlid = wlvif->dev_hlid; 51898b8625301e55bd3e4340f704edc378e4707e577Eliad Peller cmd->device.session = wlvif->session_counter; 51904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 52004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", 52104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->role_id, cmd->device.hlid, cmd->device.session); 52204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 52304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); 52404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (ret < 0) { 52504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller wl1271_error("failed to initiate cmd role enable"); 52604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto err_hlid; 52704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 52804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 52904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out_free; 53004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 53104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellererr_hlid: 53204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller /* clear links on error */ 533c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); 53404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 53504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout_free: 53604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller kfree(cmd); 53704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 53804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout: 53904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller return ret; 54004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller} 54104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 542679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerstatic int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, 543679a673414473239d189b5b41ea4014b088be7b9Eliad Peller struct wl12xx_vif *wlvif) 54404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller{ 54504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller struct wl12xx_cmd_role_stop *cmd; 54604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller int ret; 54704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 548afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID)) 54904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller return -EINVAL; 55004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 55104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 55204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (!cmd) { 55304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller ret = -ENOMEM; 55404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out; 55504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 55604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 55704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller wl1271_debug(DEBUG_CMD, "cmd role stop dev"); 55804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 5597edebf56ca424484b9e0e51a6188c93c7fdd3a41Eliad Peller cmd->role_id = wlvif->dev_role_id; 56004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->disc_type = DISCONNECT_IMMEDIATE; 56104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); 56204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 56304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); 56404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (ret < 0) { 56504e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller wl1271_error("failed to initiate cmd role stop"); 56604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out_free; 56704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 56804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 56904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); 57004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller if (ret < 0) { 57104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller wl1271_error("cmd role stop dev event completion error"); 57204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller goto out_free; 57304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller } 57404e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 575c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); 57604e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 57704e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout_free: 57804e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller kfree(cmd); 57904e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 58004e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Pellerout: 58104e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller return ret; 58204e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller} 58304e8079c69d6fa1aa023b0b6f58f818f965c10bbEliad Peller 58487fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) 585c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 586cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 587c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_start *cmd; 588c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 589f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 590c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 591c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 592c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -ENOMEM; 593c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 594c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 595f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 5960603d891c5b5153f667a79357d4652824c22b54eEliad Peller wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); 597c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 5980603d891c5b5153f667a79357d4652824c22b54eEliad Peller cmd->role_id = wlvif->role_id; 5991b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller if (wlvif->band == IEEE80211_BAND_5GHZ) 600c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->band = WL12XX_BAND_5GHZ; 60161f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller cmd->channel = wlvif->channel; 60287fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); 6036a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); 604c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; 6051fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller cmd->sta.ssid_len = wlvif->ssid_len; 6061fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); 607cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); 60830d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); 609c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 610154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { 611c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); 612c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret) 613c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 614c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 615154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller cmd->sta.hlid = wlvif->sta.hlid; 61698b8625301e55bd3e4340f704edc378e4707e577Eliad Peller cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); 61730d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); 618c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 619c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " 620c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller "basic_rate_set: 0x%x, remote_rates: 0x%x", 6210603d891c5b5153f667a79357d4652824c22b54eEliad Peller wlvif->role_id, cmd->sta.hlid, cmd->sta.session, 62230d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller wlvif->basic_rate_set, wlvif->rate_set); 623c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 624c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); 625c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 626c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role start sta"); 627c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto err_hlid; 628c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 629c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 630c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 631c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 632c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellererr_hlid: 633c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller /* clear links on error. */ 634c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); 635c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 636c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free: 637c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 638c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 639c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout: 640c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return ret; 641c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 642f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 64331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller/* use this function to stop ibss as well */ 6440603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) 645c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 646c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_stop *cmd; 647c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 648c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 649154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) 650c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return -EINVAL; 651c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 652c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 653c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 654c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -ENOMEM; 655c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 656c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 657a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi 6580603d891c5b5153f667a79357d4652824c22b54eEliad Peller wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); 659f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6600603d891c5b5153f667a79357d4652824c22b54eEliad Peller cmd->role_id = wlvif->role_id; 661c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->disc_type = DISCONNECT_IMMEDIATE; 662c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); 663f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 664c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); 665c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 666c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role stop sta"); 667c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 668c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 66972c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller 670c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); 671c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 672c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free: 673c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 674c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 675c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout: 676c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return ret; 677c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 678c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 67987fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) 680c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 681c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_start *cmd; 6826e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 6836e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 684c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 685c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 6860603d891c5b5153f667a79357d4652824c22b54eEliad Peller wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); 687c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 68868eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov /* trying to use hidden SSID with an old hostapd version */ 6891fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { 69068eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov wl1271_error("got a null SSID from beacon/bss"); 691c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -EINVAL; 692c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 693c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 694c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 695c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 696c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 697c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -ENOMEM; 698c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 699c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 700c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 701c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); 702e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov if (ret < 0) 703e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov goto out_free; 704e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 705c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); 706e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov if (ret < 0) 707e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov goto out_free_global; 708e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 7090603d891c5b5153f667a79357d4652824c22b54eEliad Peller cmd->role_id = wlvif->role_id; 710c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); 711c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->ap.bss_index = WL1271_AP_BSS_INDEX; 712a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller cmd->ap.global_hlid = wlvif->ap.global_hlid; 713a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; 71487fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); 7156a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); 716c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->ap.dtim_interval = bss_conf->dtim_period; 717c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; 71861f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller cmd->channel = wlvif->channel; 71968eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov 72068eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov if (!bss_conf->hidden_ssid) { 72168eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov /* take the SSID from the beacon for backward compatibility */ 72268eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; 7231fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller cmd->ap.ssid_len = wlvif->ssid_len; 7241fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); 72568eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov } else { 72668eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; 72768eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov cmd->ap.ssid_len = bss_conf->ssid_len; 72868eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); 72968eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov } 73068eaaf6ee5ac35d8e592834219cee9c9e88fdb24Arik Nemtsov 731c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->ap.local_rates = cpu_to_le32(0xffffffff); 732c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 7331b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller switch (wlvif->band) { 734c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller case IEEE80211_BAND_2GHZ: 735c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->band = RADIO_BAND_2_4GHZ; 736c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller break; 737c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller case IEEE80211_BAND_5GHZ: 738c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->band = RADIO_BAND_5GHZ; 739c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller break; 740c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller default: 7411b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); 742c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->band = RADIO_BAND_2_4GHZ; 743c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller break; 744c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 745c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 746c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); 747c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 748c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role start ap"); 749e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov goto out_free_bcast; 750c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 751f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 752e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov goto out_free; 753e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 754e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsovout_free_bcast: 755c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); 756e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 757e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsovout_free_global: 758c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); 759e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 760f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free: 761c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 762f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 763f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 764f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 765f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 766f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 7670603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) 768c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller{ 769c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_role_stop *cmd; 770c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller int ret; 771c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 772c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 773c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (!cmd) { 774c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = -ENOMEM; 775c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out; 776c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 777c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 7780603d891c5b5153f667a79357d4652824c22b54eEliad Peller wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); 779c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 7800603d891c5b5153f667a79357d4652824c22b54eEliad Peller cmd->role_id = wlvif->role_id; 781c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 782c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); 783c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (ret < 0) { 784c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd role stop ap"); 785c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller goto out_free; 786c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller } 787c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 788c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); 789c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); 790e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov 791c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout_free: 792c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller kfree(cmd); 793c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 794c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerout: 795c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller return ret; 796c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller} 797c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 79887fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) 79931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller{ 800cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 80131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller struct wl12xx_cmd_role_start *cmd; 8026e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 80331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller int ret; 80431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 80531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 80631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller if (!cmd) { 80731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller ret = -ENOMEM; 80831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller goto out; 80931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller } 81031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 8110603d891c5b5153f667a79357d4652824c22b54eEliad Peller wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); 81231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 8130603d891c5b5153f667a79357d4652824c22b54eEliad Peller cmd->role_id = wlvif->role_id; 8141b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller if (wlvif->band == IEEE80211_BAND_5GHZ) 81531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd->band = WL12XX_BAND_5GHZ; 81661f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller cmd->channel = wlvif->channel; 81787fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); 8186a8997964366f51c39d8efcfdc0e6319b2bd01faEliad Peller cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); 81931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd->ibss.dtim_interval = bss_conf->dtim_period; 82031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; 8211fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller cmd->ibss.ssid_len = wlvif->ssid_len; 8221fe9f1616ee0852e9422d1f676630e9a4531ace3Eliad Peller memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); 823cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); 82430d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); 82531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 826154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { 827c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); 82831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller if (ret) 82931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller goto out_free; 83031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller } 831154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller cmd->ibss.hlid = wlvif->sta.hlid; 83230d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); 83331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 83431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " 83531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller "basic_rate_set: 0x%x, remote_rates: 0x%x", 8360603d891c5b5153f667a79357d4652824c22b54eEliad Peller wlvif->role_id, cmd->sta.hlid, cmd->sta.session, 83730d0c8fd5b87d1c5486705d6420545a21533e115Eliad Peller wlvif->basic_rate_set, wlvif->rate_set); 83831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 839cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", 840cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller vif->bss_conf.bssid); 84131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 84231cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); 84331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller if (ret < 0) { 84431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller wl1271_error("failed to initiate cmd role enable"); 84531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller goto err_hlid; 84631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller } 84731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 84831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller goto out_free; 84931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 85031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellererr_hlid: 85131cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller /* clear links on error. */ 852c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); 85331cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 85431cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellerout_free: 85531cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller kfree(cmd); 85631cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 85731cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Pellerout: 85831cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller return ret; 85931cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller} 86031cd3aed29ca7ebcdaa2570a891a3fab75fe35f6Eliad Peller 861c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 862f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 863f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware 864f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 865f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 866f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma 867f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer 868f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed 869f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 870f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) 871f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 872f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 873fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen size_t res_len = 0; 874f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 875f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd test"); 876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 877fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen if (answer) 878fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen res_len = buf_len; 879fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen 880fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); 881f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 882f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TEST command failed"); 884f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 885f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 887fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen return ret; 888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware 892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 894f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id 895f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma 89625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @len: length of buf 897f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 898f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) 899f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 900f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct acx_header *acx = buf; 901f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 902f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd interrogate"); 904f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 905d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->id = cpu_to_le16(id); 906f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* payload length, does not include any headers */ 908d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->len = cpu_to_le16(len - sizeof(*acx)); 909f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 910fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); 911fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen if (ret < 0) 912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("INTERROGATE command failed"); 913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 918f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware 919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id 922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma 923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf 924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) 926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct acx_header *acx = buf; 928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 930c91d06006dd327153d163e5299b8c92f82da86b3Eliad Peller wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); 931f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 932d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->id = cpu_to_le16(id); 933f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 934f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* payload length, does not include any headers */ 935d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->len = cpu_to_le16(len - sizeof(*acx)); 936f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 937fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); 938f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 939f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("CONFIGURE command NOK"); 940f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 941f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 942f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 943f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return 0; 944f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 945f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 94694210897e2b7df8446fdecd360342149e5b4a400Luciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, bool enable) 947f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 948f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct cmd_enabledisable_path *cmd; 949f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 950f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u16 cmd_rx, cmd_tx; 951f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 952f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd data path"); 953f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 954f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 955f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 956f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 957f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 958f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 959f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 96094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho /* the channel here is only used for calibration, so hardcoded to 1 */ 96194210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho cmd->channel = 1; 962f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 963f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (enable) { 964f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_rx = CMD_ENABLE_RX; 965f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_tx = CMD_ENABLE_TX; 966f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else { 967f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_rx = CMD_DISABLE_RX; 968f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_tx = CMD_DISABLE_TX; 969f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 970f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 971fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); 972f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 973f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("rx %s cmd for channel %d failed", 97494210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho enable ? "start" : "stop", cmd->channel); 975f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 976f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 977f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 978f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", 97994210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho enable ? "start" : "stop", cmd->channel); 980f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 981fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); 982f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 983f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("tx %s cmd for channel %d failed", 98494210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho enable ? "start" : "stop", cmd->channel); 9851b00f2b560028a68cdbc57a0352163afd79822ddJuuso Oikarinen goto out; 986f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 987f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 988f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", 98994210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho enable ? "start" : "stop", cmd->channel); 990f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 991f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 992f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 993f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 994f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 995f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 9960603d891c5b5153f667a79357d4652824c22b54eEliad Pellerint wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, 9970603d891c5b5153f667a79357d4652824c22b54eEliad Peller u8 ps_mode) 998f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 999f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_ps_params *ps_params = NULL; 1000f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 1001f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1002f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd set ps mode"); 1003f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1004f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); 1005f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!ps_params) { 1006f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 1007f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 1008f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1009f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 10100603d891c5b5153f667a79357d4652824c22b54eEliad Peller ps_params->role_id = wlvif->role_id; 1011f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params->ps_mode = ps_mode; 1012f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1013f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, 1014fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen sizeof(*ps_params), 0); 1015f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 1016f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("cmd set_ps_mode failed"); 1017f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 1018f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1019f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1020f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 1021f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(ps_params); 1022f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 1023f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1024f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1025f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, 1026606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen void *buf, size_t buf_len, int index, u32 rates) 1027f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1028f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_template_set *cmd; 1029f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 1030f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1031f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); 1032f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1033f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); 1034f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); 1035f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1036f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1037f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 1038f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 1039f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 1040f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1041f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1042f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->len = cpu_to_le16(buf_len); 1043f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->template_type = template_id; 1044606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen cmd->enabled_rates = cpu_to_le32(rates); 10451e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; 10461e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; 1047bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen cmd->index = index; 1048f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1049f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (buf) 1050f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->template_data, buf, buf_len); 1051f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1052fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); 1053f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 1054f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("cmd set_template failed: %d", ret); 1055f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out_free; 1056f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1057f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1058f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free: 1059f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 1060f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1061f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 1062f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 1063f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1064f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1065d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1066f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1067a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen struct sk_buff *skb = NULL; 1068a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen int size; 1069a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen void *ptr; 1070a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen int ret = -ENOMEM; 1071f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1072f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1073536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (wlvif->bss_type == BSS_TYPE_IBSS) { 1074a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen size = sizeof(struct wl12xx_null_data_template); 1075a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen ptr = NULL; 1076a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen } else { 1077d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller skb = ieee80211_nullfunc_get(wl->hw, 1078d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller wl12xx_wlvif_to_vif(wlvif)); 1079a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen if (!skb) 1080a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen goto out; 1081a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen size = skb->len; 1082a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen ptr = skb->data; 1083a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen } 1084a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen 1085606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0, 1086d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller wlvif->basic_rate); 1087f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1088899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout: 1089899e6e65c39990a76c17940625dbe6001f618734Kalle Valo dev_kfree_skb(skb); 1090a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen if (ret) 1091a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen wl1271_warning("cmd buld null data failed %d", ret); 1092a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen 1093899e6e65c39990a76c17940625dbe6001f618734Kalle Valo return ret; 1094f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1095f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1096f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1097d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, 1098d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller struct wl12xx_vif *wlvif) 1099bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen{ 1100d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 1101bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen struct sk_buff *skb = NULL; 1102bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen int ret = -ENOMEM; 1103bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 1104d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller skb = ieee80211_nullfunc_get(wl->hw, vif); 1105bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen if (!skb) 1106bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen goto out; 1107bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 1108bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, 1109bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen skb->data, skb->len, 1110606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen CMD_TEMPL_KLV_IDX_NULL_DATA, 1111d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller wlvif->basic_rate); 1112bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 1113bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenout: 1114bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen dev_kfree_skb(skb); 1115bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen if (ret) 1116bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen wl1271_warning("cmd build klv null data failed %d", ret); 1117bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 1118bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen return ret; 1119bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 1120bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen} 1121bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen 112287fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Pellerint wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, 112387fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller u16 aid) 1124f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 11256e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 1126899e6e65c39990a76c17940625dbe6001f618734Kalle Valo struct sk_buff *skb; 1127899e6e65c39990a76c17940625dbe6001f618734Kalle Valo int ret = 0; 1128c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen 11296e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller skb = ieee80211_pspoll_get(wl->hw, vif); 1130899e6e65c39990a76c17940625dbe6001f618734Kalle Valo if (!skb) 1131899e6e65c39990a76c17940625dbe6001f618734Kalle Valo goto out; 1132f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1133899e6e65c39990a76c17940625dbe6001f618734Kalle Valo ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, 113487fbcb0f8c5c8fd57a4e3e7e638977c04ce1e0caEliad Peller skb->len, 0, wlvif->basic_rate_set); 1135f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1136899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout: 1137899e6e65c39990a76c17940625dbe6001f618734Kalle Valo dev_kfree_skb(skb); 1138899e6e65c39990a76c17940625dbe6001f618734Kalle Valo return ret; 1139f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1140f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 114183587505a2b63bb434f76b26a22f48283b86a467Eliad Pellerint wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1142818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo const u8 *ssid, size_t ssid_len, 1143818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo const u8 *ie, size_t ie_len, u8 band) 1144f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 114583587505a2b63bb434f76b26a22f48283b86a467Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 1146818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo struct sk_buff *skb; 1147abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi int ret; 1148af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller u32 rate; 1149f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 115083587505a2b63bb434f76b26a22f48283b86a467Eliad Peller skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, 1151818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo ie, ie_len); 1152818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo if (!skb) { 1153818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo ret = -ENOMEM; 1154818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo goto out; 1155818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo } 1156818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo 1157818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); 1158f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 115983587505a2b63bb434f76b26a22f48283b86a467Eliad Peller rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); 1160abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == IEEE80211_BAND_2GHZ) 1161abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, 1162af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller skb->data, skb->len, 0, rate); 1163abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else 1164abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, 1165af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller skb->data, skb->len, 0, rate); 1166818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo 1167818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoout: 1168818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo dev_kfree_skb(skb); 1169abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi return ret; 1170f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1171f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 11722f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenstruct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, 117383587505a2b63bb434f76b26a22f48283b86a467Eliad Peller struct wl12xx_vif *wlvif, 11742f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen struct sk_buff *skb) 11752f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen{ 117683587505a2b63bb434f76b26a22f48283b86a467Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 11772f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen int ret; 1178af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller u32 rate; 11792f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 11802f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen if (!skb) 118183587505a2b63bb434f76b26a22f48283b86a467Eliad Peller skb = ieee80211_ap_probereq_get(wl->hw, vif); 11822f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen if (!skb) 11832f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen goto out; 11842f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 11852f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); 11862f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 11871b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); 11881b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller if (wlvif->band == IEEE80211_BAND_2GHZ) 11892f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, 1190af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller skb->data, skb->len, 0, rate); 11912f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen else 11922f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, 1193af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller skb->data, skb->len, 0, rate); 11942f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 11952f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen if (ret < 0) 11962f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen wl1271_error("Unable to set ap probe request template."); 11972f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 11982f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenout: 11992f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen return skb; 12002f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen} 12012f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen 1202d2d66c56cf6c8727662aa321991f791604c22094Eliad Pellerint wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1203d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller __be32 ip_addr) 1204c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller{ 1205c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller int ret; 12066e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); 1207c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller struct wl12xx_arp_rsp_template tmpl; 1208c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller struct ieee80211_hdr_3addr *hdr; 1209c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller struct arphdr *arp_hdr; 1210c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1211c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller memset(&tmpl, 0, sizeof(tmpl)); 1212c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1213c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller /* mac80211 header */ 1214c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller hdr = &tmpl.hdr; 1215c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 1216c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller IEEE80211_STYPE_DATA | 1217c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller IEEE80211_FCTL_TODS); 12186e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); 12196e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller memcpy(hdr->addr2, vif->addr, ETH_ALEN); 1220c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller memset(hdr->addr3, 0xff, ETH_ALEN); 1221c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1222c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller /* llc layer */ 1223c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); 12246177eaea277527e48753d050723cd138494c98a8Eliad Peller tmpl.llc_type = cpu_to_be16(ETH_P_ARP); 1225c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1226c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller /* arp header */ 1227c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller arp_hdr = &tmpl.arp_hdr; 12286177eaea277527e48753d050723cd138494c98a8Eliad Peller arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); 12296177eaea277527e48753d050723cd138494c98a8Eliad Peller arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); 1230c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller arp_hdr->ar_hln = ETH_ALEN; 1231c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller arp_hdr->ar_pln = 4; 12326177eaea277527e48753d050723cd138494c98a8Eliad Peller arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); 1233c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1234c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller /* arp payload */ 12356e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN); 1236c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller tmpl.sender_ip = ip_addr; 1237c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1238c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, 1239c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller &tmpl, sizeof(tmpl), 0, 1240d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller wlvif->basic_rate); 1241c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1242c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller return ret; 1243c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller} 1244c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller 1245784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Pellerint wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) 1246023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo{ 1247d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 1248023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo struct ieee80211_qos_hdr template; 1249023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1250023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo memset(&template, 0, sizeof(template)); 1251023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1252cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN); 1253784f694d0f3ca927361aa0c26de1aa340eb5b275Eliad Peller memcpy(template.addr2, vif->addr, ETH_ALEN); 1254cdf09495588fda7e9c15c25bc20cb828e07be314Eliad Peller memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN); 1255023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1256023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 1257023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo IEEE80211_STYPE_QOS_NULLFUNC | 1258023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo IEEE80211_FCTL_TODS); 1259023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1260023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo /* FIXME: not sure what priority to use here */ 1261023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo template.qos_ctrl = cpu_to_le16(0); 1262023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1263023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, 1264606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen sizeof(template), 0, 1265d2d66c56cf6c8727662aa321991f791604c22094Eliad Peller wlvif->basic_rate); 1266023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo} 1267023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo 1268c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) 1269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1270c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl1271_cmd_set_keys *cmd; 1271f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 1272f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1273f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); 1274f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1275f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1276f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 1277f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 1278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 1279f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1280f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1281c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->hlid = hlid; 128298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_id = id; 128398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; 128498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_action = cpu_to_le16(KEY_SET_ID); 128598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_type = KEY_WEP; 128698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 128798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); 128898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 1289c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_warning("cmd set_default_wep_key failed: %d", ret); 129098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 129198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 129298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 129398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 129498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 129598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 129698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 129798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 129898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1299a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Pellerint wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1300154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller u16 action, u8 id, u8 key_type, 1301ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen u8 key_size, const u8 *key, const u8 *addr, 1302ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen u32 tx_seq_32, u16 tx_seq_16) 1303f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1304c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl1271_cmd_set_keys *cmd; 1305f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 1306f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1307b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller /* hlid might have already been deleted */ 1308154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) 1309b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller return 0; 1310b42f068baab96a899bb5488ad9f0e72b14743ec5Eliad Peller 1311f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1312f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 1313f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 1314f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 1315f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1316f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1317154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller cmd->hlid = wlvif->sta.hlid; 1318c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller 1319c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller if (key_type == KEY_WEP) 1320c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; 1321c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller else if (is_broadcast_ether_addr(addr)) 1322c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->lid_key_type = BROADCAST_LID_TYPE; 1323c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller else 1324c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->lid_key_type = UNICAST_LID_TYPE; 1325f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1326d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->key_action = cpu_to_le16(action); 1327f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->key_size = key_size; 1328f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->key_type = key_type; 1329f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1330d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); 1331d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); 1332ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 1333c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller cmd->key_id = id; 1334f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1335f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (key_type == KEY_TKIP) { 1336f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* 1337f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * We get the key in the following form: 1338f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) 1339f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * but the target is expecting: 1340f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * TKIP - RX MIC - TX MIC 1341f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 1342f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key, key, 16); 1343f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key + 16, key + 24, 8); 1344f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key + 24, key + 16, 8); 1345f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1346f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else { 1347f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key, key, key_size); 1348f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1349f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1350f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); 1351f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1352fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); 1353f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 1354f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("could not set keys"); 1355152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen goto out; 1356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1357f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1358f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 1359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 1360f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 1362f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 136325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 1364c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller/* 1365c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller * TODO: merge with sta/ibss into 1 set_key function. 1366c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller * note there are slight diffs 1367c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller */ 1368a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Pellerint wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1369a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller u16 action, u8 id, u8 key_type, 1370a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, 1371a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller u16 tx_seq_16) 137298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{ 1373c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl1271_cmd_set_keys *cmd; 137498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov int ret = 0; 137598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov u8 lid_type; 137698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 137798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 137898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (!cmd) 137998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return -ENOMEM; 138098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1381a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller if (hlid == wlvif->ap.bcast_hlid) { 138298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (key_type == KEY_WEP) 138398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov lid_type = WEP_DEFAULT_LID_TYPE; 138498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov else 138598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov lid_type = BROADCAST_LID_TYPE; 138698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } else { 138798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov lid_type = UNICAST_LID_TYPE; 138898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 138998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 139098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" 139198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov " hlid: %d", (int)action, (int)id, (int)lid_type, 139298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov (int)key_type, (int)hlid); 139398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 139498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->lid_key_type = lid_type; 139598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->hlid = hlid; 139698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_action = cpu_to_le16(action); 139798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_size = key_size; 139898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_type = key_type; 139998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->key_id = id; 140098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); 140198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); 140298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 140398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (key_type == KEY_TKIP) { 140498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov /* 140598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov * We get the key in the following form: 140698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) 140798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov * but the target is expecting: 140898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov * TKIP - RX MIC - TX MIC 140998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov */ 141098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->key, key, 16); 141198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->key + 16, key + 24, 8); 141298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->key + 24, key + 16, 8); 141398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } else { 141498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->key, key, key_size); 141598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 141698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 141798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); 141898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 141998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); 142098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 142198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov wl1271_warning("could not set ap keys"); 142298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 142398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 142498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 142598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 142698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 142798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 142898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 142998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1430b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Pellerint wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) 1431be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen{ 1432c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_set_peer_state *cmd; 1433be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen int ret = 0; 1434be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1435b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Peller wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); 1436be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1437be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1438be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen if (!cmd) { 1439be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen ret = -ENOMEM; 1440be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen goto out; 1441be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen } 1442be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1443b67476ef1a6417b92d3bb52510ceee266cd9ea1eEliad Peller cmd->hlid = hlid; 1444be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen cmd->state = WL1271_CMD_STA_STATE_CONNECTED; 1445be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1446c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); 1447be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen if (ret < 0) { 1448c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to send set peer state command"); 1449be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen goto out_free; 1450be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen } 1451be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1452be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout_free: 1453be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen kfree(cmd); 1454be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen 1455be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout: 1456be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen return ret; 1457be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen} 145899d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov 14591b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerint wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, 14601b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller struct ieee80211_sta *sta, u8 hlid) 146198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{ 1462c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_add_peer *cmd; 14631ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller int i, ret; 146499d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov u32 sta_rates; 146598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1466c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); 146798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 146898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 146998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (!cmd) { 147098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = -ENOMEM; 147198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 147298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 147398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 147498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov memcpy(cmd->addr, sta->addr, ETH_ALEN); 147598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->bss_index = WL1271_AP_BSS_INDEX; 147698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->aid = sta->aid; 147798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->hlid = hlid; 14781ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->sp_len = sta->max_sp; 1479b4d38db121c19fe94862357763b374e44fc23ebbArik Nemtsov cmd->wmm = sta->wme ? 1 : 0; 148098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 14811ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) 14821ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller if (sta->wme && (sta->uapsd_queues & BIT(i))) 14831ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; 14841ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller else 14851ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->psd_type[i] = WL1271_PSD_LEGACY; 14861ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller 14871b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller sta_rates = sta->supp_rates[wlvif->band]; 148899d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov if (sta->ht_cap.ht_supported) 148999d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; 149099d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov 149199d5ad7b9ccedee4a9ff8e24688c7c20e428cd21Arik Nemtsov cmd->supported_rates = 1492af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, 14931b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wlvif->band)); 149498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 14951ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", 14961ec23f7f709b7ab5552cb9c34089633c384ec657Eliad Peller cmd->supported_rates, sta->uapsd_queues); 149798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1498c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); 149998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 1500c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd add peer"); 150198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out_free; 150298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 150398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 150498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free: 150598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 150698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 150798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 150898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 150998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 151098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1511c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Pellerint wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) 151298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{ 1513c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller struct wl12xx_cmd_remove_peer *cmd; 151498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov int ret; 151598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1516c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); 151798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 151898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 151998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (!cmd) { 152098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov ret = -ENOMEM; 152198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out; 152298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 152398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 152498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->hlid = hlid; 152598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov /* We never send a deauth, mac80211 is in charge of this */ 152698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->reason_opcode = 0; 152798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov cmd->send_deauth_flag = 0; 152898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 1529c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); 153098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov if (ret < 0) { 1531c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_error("failed to initiate cmd remove peer"); 153298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov goto out_free; 153398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov } 153498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 153505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov /* 153605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov * We are ok with a timeout here. The event is sometimes not sent 153705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov * due to a firmware bug. 153805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov */ 1539c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller wl1271_cmd_wait_for_event_or_timeout(wl, 1540c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller PEER_REMOVE_COMPLETE_EVENT_ID); 154198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 154298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free: 154398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov kfree(cmd); 154498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov 154598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout: 154698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov return ret; 154798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov} 154895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 154995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_config_fwlog(struct wl1271 *wl) 155095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 155195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_config_fwlog *cmd; 155295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 155395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 155495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); 155595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 155695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 155795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 155895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 155995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 156095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 156195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 156295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->logger_mode = wl->conf.fwlog.mode; 156395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->log_severity = wl->conf.fwlog.severity; 156495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->timestamp = wl->conf.fwlog.timestamp; 156595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->output = wl->conf.fwlog.output; 156695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd->threshold = wl->conf.fwlog.threshold; 156795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 156895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); 156995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 157095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send config firmware logger command"); 157195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 157295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 157395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 157495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 157595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 157695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 157795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 157895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 157995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 158095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 158195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_start_fwlog(struct wl1271 *wl) 158295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 158395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_start_fwlog *cmd; 158495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 158595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 158695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); 158795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 158895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 158995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 159095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 159195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 159295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 159395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 159495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); 159595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 159695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send start firmware logger command"); 159795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 159895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 159995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 160095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 160195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 160295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 160395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 160495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 160595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 160695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 160795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_stop_fwlog(struct wl1271 *wl) 160895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{ 160995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv struct wl12xx_cmd_stop_fwlog *cmd; 161095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv int ret = 0; 161195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 161295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); 161395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 161495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 161595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (!cmd) { 161695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = -ENOMEM; 161795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out; 161895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 161995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 162095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); 162195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv if (ret < 0) { 162295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv wl1271_error("failed to send stop firmware logger command"); 162395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv goto out_free; 162495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv } 162595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 162695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free: 162795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv kfree(cmd); 162895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv 162995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout: 163095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv return ret; 163195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv} 1632a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 16331b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerstatic int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, 16341b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller u8 role_id) 1635a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{ 1636a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller struct wl12xx_cmd_roc *cmd; 1637a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller int ret = 0; 1638a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 163961f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); 1640a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1641a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) 1642a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return -EINVAL; 1643a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1644a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1645a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (!cmd) { 1646a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -ENOMEM; 1647a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out; 1648a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1649a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1650a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->role_id = role_id; 165161f845f4f441a90e5328a78c6c4e0646d99fc2f0Eliad Peller cmd->channel = wlvif->channel; 16521b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller switch (wlvif->band) { 1653a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller case IEEE80211_BAND_2GHZ: 1654a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->band = RADIO_BAND_2_4GHZ; 1655a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller break; 1656a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller case IEEE80211_BAND_5GHZ: 1657a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->band = RADIO_BAND_5GHZ; 1658a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller break; 1659a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller default: 16601b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wl1271_error("roc - unknown band: %d", (int)wlvif->band); 1661a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -EINVAL; 1662a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1663a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1664a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1665a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1666a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); 1667a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (ret < 0) { 1668a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_error("failed to send ROC command"); 1669a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1670a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1671a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1672a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free: 1673a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller kfree(cmd); 1674a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1675a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout: 1676a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return ret; 1677a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller} 1678a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1679a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerstatic int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) 1680a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller{ 1681a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller struct wl12xx_cmd_croc *cmd; 1682a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller int ret = 0; 1683a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1684a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); 1685a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1686a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1687a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (!cmd) { 1688a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = -ENOMEM; 1689a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out; 1690a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1691a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller cmd->role_id = role_id; 1692a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1693a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, 1694a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller sizeof(*cmd), 0); 1695a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller if (ret < 0) { 1696a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller wl1271_error("failed to send ROC command"); 1697a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller goto out_free; 1698a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller } 1699a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1700a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout_free: 1701a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller kfree(cmd); 1702a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller 1703a7cba38471bd457db8c536c94073673f41ef66f4Eliad Pellerout: 1704a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller return ret; 1705a7cba38471bd457db8c536c94073673f41ef66f4Eliad Peller} 1706251c177f886027fbce494202e44935762f103137Eliad Peller 17071b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Pellerint wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) 1708251c177f886027fbce494202e44935762f103137Eliad Peller{ 1709251c177f886027fbce494202e44935762f103137Eliad Peller int ret = 0; 1710251c177f886027fbce494202e44935762f103137Eliad Peller 1711251c177f886027fbce494202e44935762f103137Eliad Peller if (WARN_ON(test_bit(role_id, wl->roc_map))) 1712251c177f886027fbce494202e44935762f103137Eliad Peller return 0; 1713251c177f886027fbce494202e44935762f103137Eliad Peller 17141b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller ret = wl12xx_cmd_roc(wl, wlvif, role_id); 1715251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 1716251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1717251c177f886027fbce494202e44935762f103137Eliad Peller 1718251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl1271_cmd_wait_for_event(wl, 1719251c177f886027fbce494202e44935762f103137Eliad Peller REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); 1720251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) { 1721251c177f886027fbce494202e44935762f103137Eliad Peller wl1271_error("cmd roc event completion error"); 1722251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1723251c177f886027fbce494202e44935762f103137Eliad Peller } 1724251c177f886027fbce494202e44935762f103137Eliad Peller 1725251c177f886027fbce494202e44935762f103137Eliad Peller __set_bit(role_id, wl->roc_map); 1726251c177f886027fbce494202e44935762f103137Eliad Pellerout: 1727251c177f886027fbce494202e44935762f103137Eliad Peller return ret; 1728251c177f886027fbce494202e44935762f103137Eliad Peller} 1729251c177f886027fbce494202e44935762f103137Eliad Peller 1730251c177f886027fbce494202e44935762f103137Eliad Pellerint wl12xx_croc(struct wl1271 *wl, u8 role_id) 1731251c177f886027fbce494202e44935762f103137Eliad Peller{ 1732251c177f886027fbce494202e44935762f103137Eliad Peller int ret = 0; 1733251c177f886027fbce494202e44935762f103137Eliad Peller 1734251c177f886027fbce494202e44935762f103137Eliad Peller if (WARN_ON(!test_bit(role_id, wl->roc_map))) 1735251c177f886027fbce494202e44935762f103137Eliad Peller return 0; 1736251c177f886027fbce494202e44935762f103137Eliad Peller 1737251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl12xx_cmd_croc(wl, role_id); 1738251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 1739251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 1740251c177f886027fbce494202e44935762f103137Eliad Peller 1741251c177f886027fbce494202e44935762f103137Eliad Peller __clear_bit(role_id, wl->roc_map); 1742251c177f886027fbce494202e44935762f103137Eliad Pellerout: 1743251c177f886027fbce494202e44935762f103137Eliad Peller return ret; 1744251c177f886027fbce494202e44935762f103137Eliad Peller} 17456d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17466d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_channel_switch(struct wl1271 *wl, 17476d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct ieee80211_channel_switch *ch_switch) 17486d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{ 17496d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct wl12xx_cmd_channel_switch *cmd; 17506d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi int ret; 17516d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17526d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_debug(DEBUG_ACX, "cmd channel switch"); 17536d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17546d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 17556d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (!cmd) { 17566d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = -ENOMEM; 17576d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out; 17586d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17596d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17606d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->channel = ch_switch->channel->hw_value; 17616d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->switch_time = ch_switch->count; 17626d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->tx_suspend = ch_switch->block_tx; 17636d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd->flush = 0; /* this value is ignored by the FW */ 17646d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17656d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 17666d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (ret < 0) { 17676d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_error("failed to send channel switch command"); 17686d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out_free; 17696d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17706d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17716d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free: 17726d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi kfree(cmd); 17736d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17746d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout: 17756d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi return ret; 17766d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi} 17776d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17786d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviint wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) 17796d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi{ 17806d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi struct wl12xx_cmd_stop_channel_switch *cmd; 17816d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi int ret; 17826d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17836d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); 17846d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17856d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 17866d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (!cmd) { 17876d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = -ENOMEM; 17886d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out; 17896d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17906d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17916d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); 17926d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi if (ret < 0) { 17936d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi wl1271_error("failed to stop channel switch command"); 17946d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi goto out_free; 17956d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi } 17966d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 17976d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout_free: 17986d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi kfree(cmd); 17996d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi 18006d158ff38d8c99dc1bee775a66451168316692f4Shahar Leviout: 18016d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi return ret; 18026d158ff38d8c99dc1bee775a66451168316692f4Shahar Levi} 1803679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1804679a673414473239d189b5b41ea4014b088be7b9Eliad Peller/* start dev role and roc on its channel */ 1805679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerint wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1806679a673414473239d189b5b41ea4014b088be7b9Eliad Peller{ 1807679a673414473239d189b5b41ea4014b088be7b9Eliad Peller int ret; 1808679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1809679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || 1810679a673414473239d189b5b41ea4014b088be7b9Eliad Peller wlvif->bss_type == BSS_TYPE_IBSS))) 1811679a673414473239d189b5b41ea4014b088be7b9Eliad Peller return -EINVAL; 1812679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1813679a673414473239d189b5b41ea4014b088be7b9Eliad Peller ret = wl12xx_cmd_role_start_dev(wl, wlvif); 1814679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (ret < 0) 1815679a673414473239d189b5b41ea4014b088be7b9Eliad Peller goto out; 1816679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1817679a673414473239d189b5b41ea4014b088be7b9Eliad Peller ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); 1818679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (ret < 0) 1819679a673414473239d189b5b41ea4014b088be7b9Eliad Peller goto out_stop; 1820679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1821679a673414473239d189b5b41ea4014b088be7b9Eliad Peller return 0; 1822679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1823679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerout_stop: 1824679a673414473239d189b5b41ea4014b088be7b9Eliad Peller wl12xx_cmd_role_stop_dev(wl, wlvif); 1825679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerout: 1826679a673414473239d189b5b41ea4014b088be7b9Eliad Peller return ret; 1827679a673414473239d189b5b41ea4014b088be7b9Eliad Peller} 1828679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1829679a673414473239d189b5b41ea4014b088be7b9Eliad Peller/* croc dev hlid, and stop the role */ 1830679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerint wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1831679a673414473239d189b5b41ea4014b088be7b9Eliad Peller{ 1832679a673414473239d189b5b41ea4014b088be7b9Eliad Peller int ret; 1833679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1834679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || 1835679a673414473239d189b5b41ea4014b088be7b9Eliad Peller wlvif->bss_type == BSS_TYPE_IBSS))) 1836679a673414473239d189b5b41ea4014b088be7b9Eliad Peller return -EINVAL; 1837679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 18388aefffeaae5d2e10edc77c084f75dc36bcce0c68Eliad Peller /* flush all pending packets */ 18398aefffeaae5d2e10edc77c084f75dc36bcce0c68Eliad Peller wl1271_tx_work_locked(wl); 18408aefffeaae5d2e10edc77c084f75dc36bcce0c68Eliad Peller 1841679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (test_bit(wlvif->dev_role_id, wl->roc_map)) { 1842679a673414473239d189b5b41ea4014b088be7b9Eliad Peller ret = wl12xx_croc(wl, wlvif->dev_role_id); 1843679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (ret < 0) 1844679a673414473239d189b5b41ea4014b088be7b9Eliad Peller goto out; 1845679a673414473239d189b5b41ea4014b088be7b9Eliad Peller } 1846679a673414473239d189b5b41ea4014b088be7b9Eliad Peller 1847679a673414473239d189b5b41ea4014b088be7b9Eliad Peller ret = wl12xx_cmd_role_stop_dev(wl, wlvif); 1848679a673414473239d189b5b41ea4014b088be7b9Eliad Peller if (ret < 0) 1849679a673414473239d189b5b41ea4014b088be7b9Eliad Peller goto out; 1850679a673414473239d189b5b41ea4014b088be7b9Eliad Pellerout: 1851679a673414473239d189b5b41ea4014b088be7b9Eliad Peller return ret; 1852679a673414473239d189b5b41ea4014b088be7b9Eliad Peller} 1853