mwl8k.c revision 0bf22c3751d19f9be20205c0e7112723618a4858
1a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * drivers/net/wireless/mwl8k.c 3ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek * Driver for Marvell TOPDOG 802.11 Wireless cards 4a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 5a5fb297d634ba20bd53a7d6fecd611bbfd342e78Lennert Buytenhek * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc. 6a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * 7a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This file is licensed under the terms of the GNU General Public 8a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * License version 2. This program is licensed "as is" without any 9a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * warranty of any kind, whether express or implied. 10a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 11a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 12a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/init.h> 13a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/module.h> 14a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/kernel.h> 153d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek#include <linux/sched.h> 16a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/spinlock.h> 17a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/list.h> 18a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/pci.h> 19a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/delay.h> 20a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/completion.h> 21a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/etherdevice.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 23a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <net/mac80211.h> 24a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/moduleparam.h> 25a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/firmware.h> 26a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/workqueue.h> 27a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" 29a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_NAME KBUILD_MODNAME 30a5fb297d634ba20bd53a7d6fecd611bbfd342e78Lennert Buytenhek#define MWL8K_VERSION "0.12" 31a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 320863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo/* Module parameters */ 330863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolostatic unsigned ap_mode_default; 340863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolomodule_param(ap_mode_default, bool, 0); 350863ade8d6bde1d151f75720d999ff27f9fe3533Brian CavagnoloMODULE_PARM_DESC(ap_mode_default, 360863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo "Set to 1 to make ap mode the default instead of sta mode"); 370863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 38a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Register definitions */ 39a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_GEN_PTR 0x00000c10 40ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_MODE_STA 0x0000005a 41ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_MODE_AP 0x000000a5 42a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_INT_CODE 0x00000c14 43ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_FWSTA_READY 0xf0f1f2f4 44ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_FWAP_READY 0xf1f2f4a5 45ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 46a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_SCRATCH 0x00000c40 47a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 48a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Host->device communications */ 49a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_EVENTS 0x00000c18 50a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_STATUS 0x00000c1c 51a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20 52a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24 53a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 54ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_DUMMY (1 << 20) 55ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_RESET (1 << 15) 56ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_DOORBELL (1 << 1) 57ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_PPA_READY (1 << 0) 58a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 59a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Device->host communications */ 60a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c 61a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_STATUS 0x00000c30 62a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34 63a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 64a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c 65ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_DUMMY (1 << 20) 66ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) 67ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) 68ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) 69ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADIO_ON (1 << 6) 70ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) 71ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) 72ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_OPC_DONE (1 << 2) 73ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RX_READY (1 << 1) 74ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_TX_DONE (1 << 0) 75a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 76a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ 77a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_CHNL_SWITCHED | \ 78a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_QUEUE_EMPTY | \ 79a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADAR_DETECT | \ 80a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADIO_ON | \ 81a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADIO_OFF | \ 82a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_MAC_EVENT | \ 83a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_OPC_DONE | \ 84a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RX_READY | \ 85a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_TX_DONE) 86a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 87a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_QUEUES 1 88a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TX_QUEUES 4 89a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 9054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstruct rxd_ops { 9154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int rxd_size; 9254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); 9354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); 9420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status, 950d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise); 9654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 9754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 9845a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstruct mwl8k_device_info { 99a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *part_name; 100a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *helper_image; 1010863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_sta; 1020863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_ap; 10389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct rxd_ops *ap_rxd_ops; 104952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 fw_api_ap; 10545a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 10645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 107a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_rx_queue { 10845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int rxd_count; 109a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 110a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw receives here */ 11145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 112a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 113a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* refill descs here */ 11445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 115a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 11654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 11745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t rxd_dma; 118788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct { 119788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct sk_buff *skb; 12053b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori DEFINE_DMA_UNMAP_ADDR(dma); 121788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek } *buf; 122a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 123a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 124a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_queue { 125a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw transmits here */ 12645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 127a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* sw appends here */ 12945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 130a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1318ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo unsigned int len; 13245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct mwl8k_tx_desc *txd; 13345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t txd_dma; 13445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct sk_buff **skb; 135a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 137a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_priv { 138a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw; 139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct pci_dev *pdev; 140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek struct mwl8k_device_info *device_info; 14245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 143be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *sram; 144be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *regs; 145be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 146be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* firmware */ 147d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_helper; 148d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_ucode; 149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 150be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* hardware/firmware parameters */ 151be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek bool ap_fw; 152be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek struct rxd_ops *rxd_ops; 153777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_supported_band band_24; 154777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_channel channels_24[14]; 155777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_rate rates_24[14]; 1564eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_supported_band band_50; 1574eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_channel channels_50[4]; 1584eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_rate rates_50[9]; 159ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 ap_macids_supported; 160ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 sta_macids_supported; 161be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 162618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek /* firmware access */ 163618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mutex fw_mutex; 164618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct task_struct *fw_mutex_owner; 165618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int fw_mutex_depth; 166618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct completion *hostcmd_wait; 167618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 168a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* lock held over TX and TX reap */ 169a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spinlock_t tx_lock; 170a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 17188de754ad59025eba797e7a8375807755577f450Lennert Buytenhek /* TX quiesce completion, protected by fw_mutex and tx_lock */ 17288de754ad59025eba797e7a8375807755577f450Lennert Buytenhek struct completion *tx_wait; 17388de754ad59025eba797e7a8375807755577f450Lennert Buytenhek 174f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* List of interfaces. */ 175ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_used; 176f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head vif_list; 177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* power management status cookie from firmware */ 179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 *cookie; 180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t cookie_dma; 181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u16 num_mcaddrs; 183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 hw_rev; 1842aa7b01fe4f2d0978115bfd40364f52d86003606Lennert Buytenhek u32 fw_rev; 185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 186a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 187a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Running count of TX packets in flight, to avoid 188a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * iterating over the transmit rings each time. 189a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int pending_tx_pkts; 191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 192a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; 193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; 194a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 195c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek bool radio_on; 19668ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek bool radio_short_preamble; 197a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek bool sniffer_enabled; 1980439b1f55646ea944b0d58337f5065b79a1c1be0Lennert Buytenhek bool wmm_enabled; 199a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 200a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* XXX need to convert this to handle multiple interfaces */ 201a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek bool capture_beacon; 202d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek u8 capture_bssid[ETH_ALEN]; 203a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *beacon_skb; 204a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 205a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This FJ worker has to be global as it is scheduled from the 207a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * RX handler. At this point we don't know which interface it 208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * belongs to until the list of bssids waiting to complete join 209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * is checked. 210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct work_struct finalize_join_worker; 212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2131e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek /* Tasklet to perform TX reclaim. */ 2141e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct tasklet_struct poll_tx_task; 21567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 21667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Tasklet to perform RX. */ 21767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct tasklet_struct poll_rx_task; 2180d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 2190d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville /* Most recently reported noise in dBm */ 2200d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville s8 noise; 2210863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 2220863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 2230863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * preserve the queue configurations so they can be restored if/when 2240863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * the firmware image is swapped. 2250863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 2260863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; 22799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 22899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* async firmware loading state */ 22999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo unsigned fw_state; 23099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_pref; 23199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_alt; 23299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct completion firmware_loading_complete; 233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 235e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define MAX_WEP_KEY_LEN 13 236e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define NUM_WEP_KEYS 4 237e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Per interface specific private data */ 239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_vif { 240f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head list; 241f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif; 242f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 243f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek /* Firmware macid for this vif. */ 244f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek int macid; 245f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 246c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek /* Non AMPDU sequence number assigned by driver. */ 247a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u16 seqno; 248e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 249e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* Saved WEP keys */ 250e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct { 251e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 enabled; 252e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; 253e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } wep_key_conf[NUM_WEP_KEYS]; 254d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 255d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* BSSID */ 256d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 bssid[ETH_ALEN]; 257d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 258d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* A flag to indicate is HW crypto is enabled for this bssid */ 259d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam bool is_hw_crypto_enabled; 260a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 261a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) 262fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) 263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 264a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstruct mwl8k_sta { 265a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek /* Index into station database. Returned by UPDATE_STADB. */ 266a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u8 peer_id; 267a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek}; 268a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) 269a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 270777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_24[] = { 271a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2412, .hw_value = 1, }, 272a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2417, .hw_value = 2, }, 273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2422, .hw_value = 3, }, 274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2427, .hw_value = 4, }, 275a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2432, .hw_value = 5, }, 276a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2437, .hw_value = 6, }, 277a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2442, .hw_value = 7, }, 278a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2447, .hw_value = 8, }, 279a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2452, .hw_value = 9, }, 280a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2457, .hw_value = 10, }, 281a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2462, .hw_value = 11, }, 282647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2467, .hw_value = 12, }, 283647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2472, .hw_value = 13, }, 284647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2484, .hw_value = 14, }, 285a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 286a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 287777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_24[] = { 288a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 10, .hw_value = 2, }, 289a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 20, .hw_value = 4, }, 290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 55, .hw_value = 11, }, 2915dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 110, .hw_value = 22, }, 2925dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 220, .hw_value = 44, }, 293a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 301140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 302140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek}; 303140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek 3044eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_50[] = { 3054eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5180, .hw_value = 36, }, 3064eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5200, .hw_value = 40, }, 3074eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5220, .hw_value = 44, }, 3084eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5240, .hw_value = 48, }, 3094eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3104eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 3114eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_50[] = { 3124eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 3134eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 3144eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 3154eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 3164eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 3174eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 3184eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 3194eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 3204eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 3214eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3224eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Set or get info from Firmware */ 324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET 0x0000 32541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET 0x0001 32641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET_LIST 0x0002 327a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Firmware command codes */ 329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_CODE_DNLD 0x0001 330a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_HW_SPEC 0x0003 33142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek#define MWL8K_CMD_SET_HW_SPEC 0x0004 332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_STAT 0x0014 334ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RADIO_CONTROL 0x001c 335ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RF_TX_POWER 0x001e 33641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_TX_POWER 0x001f 33708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_CMD_RF_ANTENNA 0x0020 338aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ 339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_PRE_SCAN 0x0107 340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_POST_SCAN 0x0108 341ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RF_CHANNEL 0x010a 342ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_AID 0x010d 343ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RATE 0x0110 344ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 345ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RTS_THRESHOLD 0x0113 346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_SLOT 0x0114 347ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 348ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_WMM_MODE 0x0123 349a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MIMO_CONFIG 0x0125 350ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_USE_FIXED_RATE 0x0126 351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 352aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ 353a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 354aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ 355aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ 356fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ 357ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_UPDATE_STADB 0x1123 358a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 359b603742f49c3ec922522602e18ac22e8f6835132John W. Linvillestatic const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) 360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 361b603742f49c3ec922522602e18ac22e8f6835132John W. Linville u16 command = le16_to_cpu(cmd); 362b603742f49c3ec922522602e18ac22e8f6835132John W. Linville 363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMDNAME(x) case MWL8K_CMD_##x: do {\ 364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "%s", #x);\ 365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf;\ 366a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (0) 367b603742f49c3ec922522602e18ac22e8f6835132John W. Linville switch (command & ~0x8000) { 368a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(CODE_DNLD); 369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_HW_SPEC); 37042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek MWL8K_CMDNAME(SET_HW_SPEC); 371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MAC_MULTICAST_ADR); 372a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_STAT); 373a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RADIO_CONTROL); 374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RF_TX_POWER); 37541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam MWL8K_CMDNAME(TX_POWER); 37608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek MWL8K_CMDNAME(RF_ANTENNA); 377b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(SET_BEACON); 378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_PRE_SCAN); 379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_POST_SCAN); 380a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RF_CHANNEL); 381ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_AID); 382ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_RATE); 383ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_FINALIZE_JOIN); 384ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(RTS_THRESHOLD); 385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_SLOT); 386ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_EDCA_PARAMS); 387ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_WMM_MODE); 388a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MIMO_CONFIG); 389ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(USE_FIXED_RATE); 390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(ENABLE_SNIFFER); 39132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek MWL8K_CMDNAME(SET_MAC_ADDR); 392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RATEADAPT_MODE); 393b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(BSS_START); 3943f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek MWL8K_CMDNAME(SET_NEW_STN); 395fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_CMDNAME(UPDATE_ENCRYPTION); 396ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(UPDATE_STADB); 397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek default: 398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "0x%x", cmd); 399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 400a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#undef MWL8K_CMDNAME 401a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 402a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf; 403a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 404a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Hardware and firmware reset */ 406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_hw_reset(struct mwl8k_priv *priv) 407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 408a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 411a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msleep(20); 413a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 414a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 415a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Release fw image */ 416d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolostatic void mwl8k_release_fw(const struct firmware **fw) 417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 418a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw == NULL) 419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek release_firmware(*fw); 421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek *fw = NULL; 422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_release_firmware(struct mwl8k_priv *priv) 425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 42622be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_ucode); 42722be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo/* states for asynchronous f/w loading */ 43199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context); 43299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnoloenum { 43399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_INIT = 0, 43499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_PREF, 43599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_ALT, 43699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_ERROR, 43799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo}; 43899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Request fw image */ 440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_request_fw(struct mwl8k_priv *priv, 441d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const char *fname, const struct firmware **fw, 44299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 443a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 444a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* release current image */ 445a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw != NULL) 446a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_release_fw(fw); 447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 44899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 44999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return request_firmware_nowait(THIS_MODULE, 1, fname, 45099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->pdev->dev, GFP_KERNEL, 45199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv, mwl8k_fw_state_machine); 45299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 453d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo return request_firmware(fw, fname, &priv->pdev->dev); 454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 455a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, 45799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 458a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 459a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek struct mwl8k_device_info *di = priv->device_info; 460a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 461a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 462a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek if (di->helper_image != NULL) { 46399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 46499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 46599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, true); 46699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 46799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 46899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, false); 46999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 47099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 47199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 47299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 47399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc || nowait) 474a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek return rc; 475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 47799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) { 47899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* 47999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * if we get here, no helper image is needed. Skip the 48099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * FW_STATE_INIT state. 48199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo */ 48299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 48399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 48499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, 48599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 48699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 48799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 48899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, false); 489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 490c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: Error requesting firmware file %s\n", 4910863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo pci_name(priv->pdev), fw_image); 49222be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 497a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_pkt { 500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 code; 501a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 length; 502f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 seq_num; 503f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 macid; 504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 result; 505a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek char payload[0]; 506ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 508a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware loading. 510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 512a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) 513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int loops; 517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); 519a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 523a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 524a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek loops = 1000; 530a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 int_code; 532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int_code = ioread32(regs + MWL8K_HIU_INT_CODE); 534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { 535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 536a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 537a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 538a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5393d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek cond_resched(); 540a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 541a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 543a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); 544a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 545d4b7057052236e81ab0788cc8df306dc02b0e7beLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_load_fw_image(struct mwl8k_priv *priv, 549a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 550a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 551a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt *cmd; 552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int done; 553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc = 0; 554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kmalloc(sizeof(*cmd) + 256, GFP_KERNEL); 556a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); 560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->seq_num = 0; 561f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = 0; 562a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->result = 0; 563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (length) { 566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int block_size = length > 256 ? 256 : length; 567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(cmd->payload, data + done, block_size); 569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = cpu_to_le16(block_size); 570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, 572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek sizeof(*cmd) + block_size); 573a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 574a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += block_size; 577a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= block_size; 578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 581a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = 0; 582a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, sizeof(*cmd)); 583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_feed_fw_image(struct mwl8k_priv *priv, 591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned char *buffer; 594a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int may_continue, rc = 0; 595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 done, prev_block_size; 596a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 597a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek buffer = kmalloc(1024, GFP_KERNEL); 598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (buffer == NULL) 599a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 600a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = 0; 603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue = 1000; 604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (may_continue > 0) { 605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 block_size; 606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size = ioread32(priv->regs + MWL8K_HIU_SCRATCH); 608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size & 1) { 609a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size &= ~1; 610a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 612a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += prev_block_size; 613a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= prev_block_size; 614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 616a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size > 1024 || block_size > length) { 617a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EOVERFLOW; 618a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 619a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 621a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (length == 0) { 622a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = 0; 623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 626a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size == 0) { 627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EPROTO; 628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek continue; 631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 632a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = block_size; 634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(buffer, data + done, block_size); 635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, buffer, block_size); 637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc && length != 0) 642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EREMOTEIO; 643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(buffer); 645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 649c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhekstatic int mwl8k_load_firmware(struct ieee80211_hw *hw) 650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 651c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 652d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw = priv->fw_ucode; 653c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int rc; 654c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int loops; 655c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 656c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { 657d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *helper = priv->fw_helper; 658a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 659c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (helper == NULL) { 660c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: helper image needed but none " 661c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "given\n", pci_name(priv->pdev)); 662c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek return -EINVAL; 663c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek } 664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 665c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, helper->data, helper->size); 666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware " 668c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "helper image\n", pci_name(priv->pdev)); 669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 67189b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek msleep(5); 672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 673c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); 674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 675c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, fw->data, fw->size); 676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 679c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware image\n", 680c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_name(priv->pdev)); 681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 68489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); 685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 68689b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek loops = 500000; 687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 688eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek u32 ready_code; 689eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 690eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); 691eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek if (ready_code == MWL8K_FWAP_READY) { 692eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek priv->ap_fw = 1; 693eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek break; 694eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } else if (ready_code == MWL8K_FWSTA_READY) { 695eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek priv->ap_fw = 0; 696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 697eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } 698eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 699eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek cond_resched(); 700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 703a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* DMA header used by firmware and hardware. */ 708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_dma_data { 709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 fwlen; 710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr wh; 71120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek char data[0]; 712ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Routines to add/remove DMA header from skb. */ 71520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhekstatic inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) 716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 71720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek struct mwl8k_dma_data *tr; 71820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int hdrlen; 71920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 72020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 72120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek hdrlen = ieee80211_hdrlen(tr->wh.frame_control); 72220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 72320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(tr->wh)) { 72420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (ieee80211_is_data_qos(tr->wh.frame_control)) { 72520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen - 2); 72620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *((__le16 *)(tr->data - 2)) = qos; 72720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } else { 72820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen); 72920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } 730a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 73120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 73220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(*tr)) 73320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek skb_pull(skb, sizeof(*tr) - hdrlen); 734a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 736252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadamstatic void 737252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadammwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) 738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 740ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek int hdrlen; 741252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam int reqd_hdrlen; 742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_dma_data *tr; 743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 744ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek /* 745ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * Add a firmware DMA header; the firmware requires that we 746ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * present a 2-byte payload length followed by a 4-address 747ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * header (without QoS field), followed (optionally) by any 748ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * WEP/ExtIV header (but only filled in for CCMP). 749ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek */ 750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 751ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek 752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek hdrlen = ieee80211_hdrlen(wh->frame_control); 753252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam reqd_hdrlen = sizeof(*tr); 754252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam 755252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam if (hdrlen != reqd_hdrlen) 756252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam skb_push(skb, reqd_hdrlen - hdrlen); 757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 758ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 759252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam hdrlen -= IEEE80211_QOS_CTL_LEN; 760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 761a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (wh != &tr->wh) 763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memmove(&tr->wh, wh, hdrlen); 764ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (hdrlen != sizeof(tr->wh)) 765ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek memset(((void *)&tr->wh) + hdrlen, 0, sizeof(tr->wh) - hdrlen); 766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware length is the length of the fully formed "802.11 769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * payload". That is, everything except for the 802.11 header. 770a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This includes all crypto material including the MIC. 771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 772252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); 773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 775e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadamstatic void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) 776e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam{ 777e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_hdr *wh; 778e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_tx_info *tx_info; 779e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_key_conf *key_conf; 780e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam int data_pad; 781e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 782e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam wh = (struct ieee80211_hdr *)skb->data; 783e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 784e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam tx_info = IEEE80211_SKB_CB(skb); 785e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 786e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = NULL; 787e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (ieee80211_is_data(wh->frame_control)) 788e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = tx_info->control.hw_key; 789e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 790e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* 791e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * Make sure the packet header is in the DMA header format (4-address 792e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * without QoS), the necessary crypto padding between the header and the 793e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * payload has already been provided by mac80211, but it doesn't add tail 794e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * padding when HW crypto is enabled. 795e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * 796e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * We have the following trailer padding requirements: 797e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - WEP: 4 trailer bytes (ICV) 798e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - TKIP: 12 trailer bytes (8 MIC + 4 ICV) 799e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - CCMP: 8 trailer bytes (MIC) 800e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam */ 801e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 0; 802e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (key_conf != NULL) { 803e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam switch (key_conf->cipher) { 804e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 805e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 806e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 4; 807e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 808e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 809e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 12; 810e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 811e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 812e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 8; 813e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 814e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 815e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 816e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam mwl8k_add_dma_header(skb, data_pad); 817e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 818a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 819a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 82089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for 88w8366 AP firmware. 8216f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek */ 82289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_8366_ap { 8236f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 pkt_len; 8246f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 sq2; 8256f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rate; 8266f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 pkt_phys_addr; 8276f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 next_rxd_phys_addr; 8286f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 qos_control; 8296f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 htsig2; 8306f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_rssi_info; 8316f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_noise_floor_info; 8326f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 noise_floor; 8336f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 pad0[3]; 8346f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rssi; 8356f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_status; 8366f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 channel; 8376f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_ctrl; 838ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 8396f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 84089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80 84189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40 84289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f) 8438e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek 84489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 8456f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 846d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* 8366 AP rx_status bits */ 847d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 848d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF 849d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 850d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 851d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 852d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 85389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) 8546f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 85589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8566f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8576f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 85889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST; 8596f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 8606f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 86189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) 8626f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 86389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8646f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8656f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 8666f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 8676f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek wmb(); 8686f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->rx_ctrl = 0; 8696f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 8706f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8716f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhekstatic int 87289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, 8730d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 8746f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 87589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8766f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 87789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST)) 8786f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return -1; 8796f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rmb(); 8806f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8816f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 8826f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8836f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->signal = -rxd->rssi; 8840d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_floor; 8856f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 88689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) { 8876f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 88889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ) 8898e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 89089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate); 8916f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } else { 8926f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek int i; 8936f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 894777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { 895777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek if (mwl8k_rates_24[i].hw_value == rxd->rate) { 8966f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->rate_idx = i; 8976f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek break; 8986f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 8996f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9006f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9016f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 902854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 903854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 904854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 905854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 906854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 907854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 908854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 90959eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 91059eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 9116f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 91220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 91320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 914d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && 915d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && 916d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) 917d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 918d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 9196f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 9206f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9216f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 92289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_8366_ap_ops = { 92389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_8366_ap), 92489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_8366_ap_init, 92589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_8366_ap_refill, 92689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_8366_ap_process, 9276f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 9286f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9296f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek/* 93089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for STA firmware. 931a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 93289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_sta { 933a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 934a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 link_quality; 935a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 noise_level; 936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 93745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_rxd_phys_addr; 938a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 939a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pad0[4]; 941a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rssi; 942a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 channel; 943a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pad1; 944a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_ctrl; 945a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_status; 946a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 pad2[2]; 947ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 94989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000 95089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) 95189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) 95289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_40MHZ 0x0004 95389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002 95489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 95554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 95689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 957d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 958d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* ICV=0 or MIC=1 */ 959d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 960d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* Key is uploaded only in failure case */ 961d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 96254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 96389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) 96454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 96589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 96654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 96754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 96889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST; 96954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 97054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 97189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) 97254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 97389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 97454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 97554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 97654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 97754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek wmb(); 97854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->rx_ctrl = 0; 97954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 98054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 98154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic int 98289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, 9830d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 98454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 98589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 98654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek u16 rate_info; 98754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 98889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST)) 98954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return -1; 99054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rmb(); 99154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rate_info = le16_to_cpu(rxd->rate_info); 99354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 99554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->signal = -rxd->rssi; 9970d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_level; 99889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info); 99989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); 100054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 100189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) 100254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORTPRE; 100389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) 100454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 100589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) 100654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORT_GI; 100789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) 100854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 100954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1010854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 1011854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 1012854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 1013854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 1014854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 1015854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 1016854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 101759eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 101859eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 101954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 102020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 1021d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && 1022d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) 1023d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 102420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 102554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 102654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 102754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 102889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_sta_ops = { 102989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_sta), 103089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_sta_init, 103189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_sta_refill, 103289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_sta_process, 103354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 103454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 103554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1036a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_DESCS 256 1037a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_MAXSZ 3800 1038a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1039a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) 1040a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1041a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1042a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1043a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1044a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1045a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 104645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count = 0; 104745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->head = 0; 104845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->tail = 0; 1049a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 105054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size; 1051a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 105245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); 105345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (rxq->rxd == NULL) { 10545db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX descriptors\n"); 1055a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 105745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(rxq->rxd, 0, size); 1058a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1059788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); 1060788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf == NULL) { 10615db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); 106245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); 1063a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1064a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1065788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); 1066a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1067a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 106854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int desc_size; 106954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1070a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 107154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dma_addr_t next_dma_addr; 107254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 107354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek desc_size = priv->rxd_ops->rxd_size; 107454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size); 1075a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 107654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = i + 1; 107754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (nexti == MWL8K_RX_DESCS) 107854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = 0; 107954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek next_dma_addr = rxq->rxd_dma + (nexti * desc_size); 1080a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 108154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_init(rxd, next_dma_addr); 1082a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1083a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1084a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1085a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1086a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_refill(struct ieee80211_hw *hw, int index, int limit) 1088a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1089a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1090a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1091a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int refilled; 1092a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1093a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled = 0; 109445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { 1095a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1096788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek dma_addr_t addr; 1097a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rx; 109854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1099a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1100a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb = dev_alloc_skb(MWL8K_RX_MAXSZ); 1101a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (skb == NULL) 1102a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1104788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek addr = pci_map_single(priv->pdev, skb->data, 1105788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); 1106a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 110754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->rxd_count++; 110854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rx = rxq->tail++; 110954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->tail == MWL8K_RX_DESCS) 111054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->tail = 0; 1111788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rx].skb = skb; 111253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rx], dma, addr); 111354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 111454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size); 111554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ); 1116a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1117a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled++; 1118a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1119a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1120a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return refilled; 1121a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1122a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1123a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Must be called only when the card's reception is completely halted */ 1124a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) 1125a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1126a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1127a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1129a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1130a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 1131788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf[i].skb != NULL) { 1132788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 113353b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[i], dma), 1134788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 113553b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[i], dma, 0); 1136788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1137788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree_skb(rxq->buf[i].skb); 1138788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[i].skb = NULL; 1139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1141a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1142788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree(rxq->buf); 1143788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf = NULL; 1144a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1145a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 114654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek MWL8K_RX_DESCS * priv->rxd_ops->rxd_size, 114745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd, rxq->rxd_dma); 114845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = NULL; 1149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1150a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1151a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1152a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1153a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Scan a list of BSSIDs to process for finalize join. 1154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Allows for extension to process multiple BSSIDs. 1155a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline int 1157a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) 1158a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1159a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return priv->capture_beacon && 1160a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_is_beacon(wh->frame_control) && 1161a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek !compare_ether_addr(wh->addr3, priv->capture_bssid); 1162a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1163a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 11643779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhekstatic inline void mwl8k_save_beacon(struct ieee80211_hw *hw, 11653779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct sk_buff *skb) 1166a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 11673779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 11683779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek 1169a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = false; 1170d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memset(priv->capture_bssid, 0, ETH_ALEN); 1171a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1172a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Use GFP_ATOMIC as rxq_process is called from 1174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * the primary interrupt handler, memory allocation call 1175a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * must not sleep. 1176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); 1178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 11793779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek ieee80211_queue_work(hw, &priv->finalize_join_worker); 1180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1182d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, 1183d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 *bssid) 1184d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 1185d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif; 1186d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1187d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_for_each_entry(mwl8k_vif, 1188d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam vif_list, list) { 1189d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (memcmp(bssid, mwl8k_vif->bssid, 1190d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ETH_ALEN) == 0) 1191d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return mwl8k_vif; 1192d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1193d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1194d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return NULL; 1195d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1196d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1197a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_process(struct ieee80211_hw *hw, int index, int limit) 1198a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1199a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1200d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif = NULL; 1201a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1202a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int processed; 1203a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1204a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed = 0; 120545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count && limit--) { 1206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 120754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 120854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int pkt_len; 1209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_rx_status status; 1210d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct ieee80211_hdr *wh; 121120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek __le16 qos; 1212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1213788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek skb = rxq->buf[rxq->head].skb; 1214d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek if (skb == NULL) 1215d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek break; 121654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 121754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); 121854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 12190d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos, 12200d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville &priv->noise); 122154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (pkt_len < 0) 122254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek break; 122354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1224788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rxq->head].skb = NULL; 1225788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1226788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 122753b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[rxq->head], dma), 1228788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 122953b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); 1230a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 123154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head++; 123254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->head == MWL8K_RX_DESCS) 123354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head = 0; 123454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 123545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count--; 1236a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1237d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1240c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * Check for a pending join operation. Save a 1241c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * copy of the beacon and schedule a tasklet to 1242c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * send a FINALIZE_JOIN command to the firmware. 1243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 124454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (mwl8k_capture_bssid(priv, (void *)skb->data)) 12453779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek mwl8k_save_beacon(hw, skb); 1246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1247d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (ieee80211_has_protected(wh->frame_control)) { 1248d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1249d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* Check if hw crypto has been enabled for 1250d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * this bss. If yes, set the status flags 1251d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * accordingly 1252d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1253d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, 1254d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh->addr1); 1255d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1256d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif != NULL && 1257d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled == true) { 1258d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* 1259d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * When MMIC ERROR is encountered 1260d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * by the firmware, payload is 1261d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * dropped and only 32 bytes of 1262d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * mwl8k Firmware header is sent 1263d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * to the host. 1264d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 1265d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * We need to add four bytes of 1266d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * key information. In it 1267d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * MAC80211 expects keyidx set to 1268d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 0 for triggering Counter 1269d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * Measure of MMIC failure. 1270d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1271d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (status.flag & RX_FLAG_MMIC_ERROR) { 1272d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_dma_data *tr; 1273d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam tr = (struct mwl8k_dma_data *)skb->data; 1274d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memset((void *)&(tr->data), 0, 4); 1275d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam pkt_len += 4; 1276d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1277d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1278d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (!ieee80211_is_auth(wh->frame_control)) 1279d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status.flag |= RX_FLAG_IV_STRIPPED | 1280d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_DECRYPTED | 1281d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_MMIC_STRIPPED; 1282d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1283d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1284d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1285d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam skb_put(skb, pkt_len); 1286d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_remove_dma_header(skb, qos); 1287f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 1288f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg ieee80211_rx_irqsafe(hw, skb); 1289a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed++; 1291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1292a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1293a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return processed; 1294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Packet transmission. 1299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK 0x00000001 1302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 1303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 1304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 1305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 1306a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1307e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_QLEN_UNSPEC 0xff00 1308e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_MASK 0x0060 1309e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000 1310e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060 1311e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_EOSP 0x0010 1312e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek 1313a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_desc { 1314a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 status; 1315a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 data_rate; 1316a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 tx_priority; 1317a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 1318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 1319a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 1320d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 dest_MAC_addr[ETH_ALEN]; 132145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_txd_phys_addr; 1322a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 reserved; 1323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 1324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 peer_id; 1325a1fe24b0fd8bf16b4e551ae3fb785bfc574b9ffbBrian Cavagnolo __u8 tx_frag_cnt; 1326ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1327a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TX_DESCS 128 1329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1330a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_txq_init(struct ieee80211_hw *hw, int index) 1331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1334a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 13378ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len = 0; 133845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = 0; 133945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 1340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); 1342a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 134345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); 134445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->txd == NULL) { 13455db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX descriptors\n"); 1346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 134845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(txq->txd, 0, size); 1349a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 135045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); 135145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->skb == NULL) { 13525db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); 135345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); 1354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1355a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 135645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(txq->skb, 0, MWL8K_TX_DESCS * sizeof(*txq->skb)); 1357a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1358a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_DESCS; i++) { 1359a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 1361a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 136245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + i; 1363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek nexti = (i + 1) % MWL8K_TX_DESCS; 1364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status = 0; 136645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc->next_txd_phys_addr = 136745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc)); 1368a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1370a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1372a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1373a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline void mwl8k_tx_start(struct mwl8k_priv *priv) 1374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1375a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_PPA_READY, 1376a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1377a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 1378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ioread32(priv->regs + MWL8K_HIU_INT_CODE); 1380a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1381a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 13827e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekstatic void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) 1383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 13847e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 13857e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int i; 13867e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 13877e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) { 13887e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + i; 13897e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int fw_owned = 0; 13907e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int drv_owned = 0; 13917e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int unused = 0; 13927e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int desc; 13937e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { 13957e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_desc *tx_desc = txq->txd + desc; 13967e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek u32 status; 1397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 13987e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek status = le32_to_cpu(tx_desc->status); 1399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) 14007e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek fw_owned++; 1401a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek else 14027e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek drv_owned++; 1403a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1404a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_desc->pkt_len == 0) 14057e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unused++; 1406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1408c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 1409c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "txq[%d] len=%d head=%d tail=%d " 1410c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "fw_owned=%d drv_owned=%d unused=%d\n", 1411c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches i, 1412c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches txq->len, txq->head, txq->tail, 1413c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches fw_owned, drv_owned, unused); 14147e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 1415a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1416a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1417618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 141888de754ad59025eba797e7a8375807755577f450Lennert Buytenhek * Must be called with priv->fw_mutex held and tx queues stopped. 1419618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 142062abd3cfb2f1a0ab1963ac4c4087c477da6b1f2aLennert Buytenhek#define MWL8K_TX_WAIT_TIMEOUT_MS 5000 14217e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1422950d5b0191dc3e71017f336017f75f6189f39f08Lennert Buytenhekstatic int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 142588de754ad59025eba797e7a8375807755577f450Lennert Buytenhek DECLARE_COMPLETION_ONSTACK(tx_wait); 14267e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int retry; 14277e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int rc; 1428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek might_sleep(); 1430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14317e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek /* 14327e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * The TX queues are stopped at this point, so this test 14337e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * doesn't need to take ->tx_lock. 14347e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek */ 14357e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (!priv->pending_tx_pkts) 14367e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return 0; 14377e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14387e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 0; 14397e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = 0; 14407e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 14427e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek priv->tx_wait = &tx_wait; 14437e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek while (!rc) { 14447e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int oldcount; 14457e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unsigned long timeout; 1446a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14477e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek oldcount = priv->pending_tx_pkts; 1448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14497e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 145088de754ad59025eba797e7a8375807755577f450Lennert Buytenhek timeout = wait_for_completion_timeout(&tx_wait, 14517e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS)); 1452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 14537e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14547e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (timeout) { 14557e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek WARN_ON(priv->pending_tx_pkts); 14567e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (retry) { 1457c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, "tx rings drained\n"); 14587e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14597e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek break; 14607e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14617e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14627e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (priv->pending_tx_pkts < oldcount) { 1463c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, 1464c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "waiting for tx rings to drain (%d -> %d pkts)\n", 1465c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches oldcount, priv->pending_tx_pkts); 14667e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 1; 14677e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek continue; 14687e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14697e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->tx_wait = NULL; 1471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1472c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n", 1473c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_TX_WAIT_TIMEOUT_MS); 14747e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek mwl8k_dump_tx_rings(hw); 14757e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14767e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = -ETIMEDOUT; 1477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 14787e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 1479a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14807e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return rc; 1481a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1482a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1483c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek#define MWL8K_TXD_SUCCESS(status) \ 1484c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek ((status) & (MWL8K_TXD_STATUS_OK | \ 1485c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_RETRY | \ 1486c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_MORE_RETRY)) 1487a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1488efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekstatic int 1489efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekmwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) 1490a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1492a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1493efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek int processed; 1494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1495efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed = 0; 14968ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo while (txq->len > 0 && limit--) { 1497a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int tx; 1498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long addr; 1500ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek int size; 1501a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1502a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *info; 1503a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 1504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 150545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->head; 150645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + tx; 1507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1508a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = le32_to_cpu(tx_desc->status); 1509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) { 1511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!force) 1512a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status &= 1514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); 1515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 151745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = (tx + 1) % MWL8K_TX_DESCS; 15188ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo BUG_ON(txq->len == 0); 15198ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len--; 1520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts--; 1521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek addr = le32_to_cpu(tx_desc->pkt_phys_addr); 1523ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek size = le16_to_cpu(tx_desc->pkt_len); 152445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek skb = txq->skb[tx]; 152545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[tx] = NULL; 1526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek BUG_ON(skb == NULL); 1528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); 1529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 153020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek mwl8k_remove_dma_header(skb, tx_desc->qos_control); 1531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Mark descriptor as unused */ 1533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_phys_addr = 0; 1534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_len = 0; 1535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1536a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = IEEE80211_SKB_CB(skb); 1537a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_info_clear_status(info); 15380bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 15390bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam /* Rate control is happening in the firmware. 15400bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam * Ensure no tx rate is being reported. 15410bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam */ 15420bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam info->status.rates[0].idx = -1; 15430bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam info->status.rates[0].count = 1; 15440bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 1545ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek if (MWL8K_TXD_SUCCESS(status)) 1546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->flags |= IEEE80211_TX_STAT_ACK; 1547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_status_irqsafe(hw, skb); 1549a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1550efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed++; 1551a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1553efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) 1554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_wake_queue(hw, index); 1555efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek 1556efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek return processed; 1557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* must be called only when the card's transmit is completely halted */ 1560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) 1561a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1562a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1565efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, index, INT_MAX, 1); 1566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 156745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek kfree(txq->skb); 156845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb = NULL; 1569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 1571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), 157245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd, txq->txd_dma); 157345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = NULL; 1574a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 1577a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) 1578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *tx_info; 158123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek struct mwl8k_vif *mwl8k_vif; 1582a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 1583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq; 1584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx; 1585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma; 158623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u32 txstatus; 158723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u8 txdatarate; 158823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u16 qos; 1589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 159023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 159123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 159223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); 159323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 159423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = 0; 1595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1596d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (priv->ap_fw) 1597d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_encapsulate_tx_frame(skb); 1598d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam else 1599d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_add_dma_header(skb, 0); 1600d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 160123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_info = IEEE80211_SKB_CB(skb); 1604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif = MWL8K_VIF(tx_info->control.vif); 1605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 1607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 1608657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); 1609657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek mwl8k_vif->seqno += 0x10; 1610a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 161223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek /* Setup firmware control bit fields for each frame type. */ 161323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus = 0; 161423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 161523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_mgmt(wh->frame_control) || 161623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek ieee80211_is_ctl(wh->frame_control)) { 161723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 1618e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP; 161923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } else if (ieee80211_is_data(wh->frame_control)) { 162023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 1; 162123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (is_multicast_ether_addr(wh->addr1)) 162223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; 162323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 1624e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos &= ~MWL8K_QOS_ACK_POLICY_MASK; 162523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) 1626e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK; 162723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 1628e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_NORMAL; 162923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } 1630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma = pci_map_single(priv->pdev, skb->data, 1632a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb->len, PCI_DMA_TODEVICE); 1633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma)) { 1635c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 1636c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "failed to dma map skb, dropping TX frame.\n"); 163723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek dev_kfree_skb(skb); 1638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return NETDEV_TX_OK; 1639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 164123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek spin_lock_bh(&priv->tx_lock); 1642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 164323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txq = priv->txq + index; 1644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 164545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek BUG_ON(txq->skb[txq->tail] != NULL); 164645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[txq->tail] = skb; 1647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 164845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->txd + txq->tail; 164923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->data_rate = txdatarate; 165023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->tx_priority = index; 1651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->qos_control = cpu_to_le16(qos); 1652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_phys_addr = cpu_to_le32(dma); 1653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_len = cpu_to_le16(skb->len); 165423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->rate_info = 0; 1655a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek if (!priv->ap_fw && tx_info->control.sta != NULL) 1656a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; 1657a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek else 1658a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek tx->peer_id = 0; 1659a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wmb(); 166023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); 166123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 16628ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len++; 1663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts++; 1664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 166545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail++; 166645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->tail == MWL8K_TX_DESCS) 166745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 166823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 166945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->head == txq->tail) 1670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queue(hw, index); 1671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 167223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek mwl8k_tx_start(priv); 1673a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 1675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return NETDEV_TX_OK; 1677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1681618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * Firmware access. 1682618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 1683618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * We have the following requirements for issuing firmware commands: 1684618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - Some commands require that the packet transmit path is idle when 1685618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the command is issued. (For simplicity, we'll just quiesce the 1686618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * transmit path for every command.) 1687618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - There are certain sequences of commands that need to be issued to 1688618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the hardware sequentially, with no other intervening commands. 1689618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 1690618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * This leads to an implementation of a "firmware lock" as a mutex that 1691618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * can be taken recursively, and which is taken by both the low-level 1692618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * command submission function (mwl8k_post_cmd) as well as any users of 1693618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * that function that require issuing of an atomic sequence of commands, 1694618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * and quiesces the transmit path whenever it's taken. 1695618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 1696618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic int mwl8k_fw_lock(struct ieee80211_hw *hw) 1697618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 1698618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1699618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1700618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->fw_mutex_owner != current) { 1701618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int rc; 1702618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1703618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_lock(&priv->fw_mutex); 1704618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_stop_queues(hw); 1705618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1706618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek rc = mwl8k_tx_wait_empty(hw); 1707618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (rc) { 1708618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_wake_queues(hw); 1709618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 1710618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1711618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return rc; 1712618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1713618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1714618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = current; 1715618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1716618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1717618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_depth++; 1718618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1719618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return 0; 1720618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 1721618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1722618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic void mwl8k_fw_unlock(struct ieee80211_hw *hw) 1723618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 1724618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1725618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1726618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!--priv->fw_mutex_depth) { 1727618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_wake_queues(hw); 1728618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = NULL; 1729618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 1730618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1731618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 1732618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1733618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1734618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 1735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Command processing. 1736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 17380c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek/* Timeout firmware commands after 10s */ 17390c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek#define MWL8K_CMD_TIMEOUT_MS 10000 1740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) 1742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek DECLARE_COMPLETION_ONSTACK(cmd_wait); 1744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 1746a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 1747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned int dma_size; 1748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 1749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long timeout = 0; 1750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 buf[32]; 1751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1752b603742f49c3ec922522602e18ac22e8f6835132John W. Linville cmd->result = (__force __le16) 0xffff; 1753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_size = le16_to_cpu(cmd->length); 1754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, cmd, dma_size, 1755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek PCI_DMA_BIDIRECTIONAL); 1756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 1757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1759618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek rc = mwl8k_fw_lock(hw); 176039a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek if (rc) { 176139a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, dma_size, 176239a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek PCI_DMA_BIDIRECTIONAL); 1763618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return rc; 176439a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek } 1765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hostcmd_wait = &cmd_wait; 1767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 1768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 1769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1770a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 1771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek timeout = wait_for_completion_timeout(&cmd_wait, 1774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); 1775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1776618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->hostcmd_wait = NULL; 1777618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1778618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mwl8k_fw_unlock(hw); 1779618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 178037055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, dma_size, 178137055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek PCI_DMA_BIDIRECTIONAL); 178237055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek 1783a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!timeout) { 17845db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", 1785c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 1786c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_CMD_TIMEOUT_MS); 1787a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -ETIMEDOUT; 1788a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 17890c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek int ms; 17900c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 17910c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(timeout); 17920c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 1793ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek rc = cmd->result ? -EINVAL : 0; 1794a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 17955db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s error 0x%x\n", 1796c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 1797c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches le16_to_cpu(cmd->result)); 17980c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek else if (ms > 2000) 17995db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_notice(hw->wiphy, "Command %s took %d ms\n", 1800c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, 1801c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches buf, sizeof(buf)), 1802c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches ms); 1803a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 1806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1807a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1808f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhekstatic int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, 1809f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct ieee80211_vif *vif, 1810f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct mwl8k_cmd_pkt *cmd) 1811f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek{ 1812f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek if (vif != NULL) 1813f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = MWL8K_VIF(vif)->macid; 1814f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek return mwl8k_post_cmd(hw, cmd); 1815f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek} 1816f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 1817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 18181349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek * Setup code shared between STA and AP firmware images. 18191349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek */ 18201349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhekstatic void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) 18211349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek{ 18221349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 18231349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18241349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); 18251349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); 18261349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18271349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); 18281349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); 18291349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18301349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.band = IEEE80211_BAND_2GHZ; 18311349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.channels = priv->channels_24; 18321349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); 18331349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.bitrates = priv->rates_24; 18341349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); 18351349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18361349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; 18371349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek} 18381349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18394eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) 18404eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek{ 18414eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 18424eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18434eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); 18444eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); 18454eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18464eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); 18474eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); 18484eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18494eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.band = IEEE80211_BAND_5GHZ; 18504eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.channels = priv->channels_50; 18514eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); 18524eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.bitrates = priv->rates_50; 18534eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); 18544eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18554eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; 18564eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek} 18574eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18581349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek/* 185904b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek * CMD_GET_HW_SPEC (STA version). 1860a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 186104b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_sta { 1862a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 1863a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 hw_rev; 1864a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 host_interface; 1865a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 num_mcaddrs; 1866d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 1867a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 region_code; 1868a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 fw_rev; 1869a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 ps_cookie; 1870a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps; 1871a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 mcs_bitmap[16]; 1872a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 rx_queue_ptr; 1873a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_queues; 1874a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; 1875a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps2; 1876a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_desc_per_queue; 187745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 total_rxd; 1878ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1879a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1880341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MAX_AMSDU 0x20000000 1881341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_GREENFIELD 0x08000000 1882341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_AMPDU 0x04000000 1883341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_STBC 0x01000000 1884341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_STBC 0x00800000 1885341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 1886341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 1887341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 1888341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 1889341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_DELAY_BA 0x00003000 1890341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MIMO 0x00000200 1891341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_40MHZ 0x00000100 189206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_BAND_MASK 0x00000007 189306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_5GHZ 0x00000004 189406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_2GHZ4 0x00000001 1895341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 189606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 189706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_ht_caps(struct ieee80211_hw *hw, 189806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct ieee80211_supported_band *band, u32 cap) 1899341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek{ 1900341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int rx_streams; 1901341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int tx_streams; 1902341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1903777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ht_supported = 1; 1904341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1905341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_MAX_AMSDU) 1906777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; 1907341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_GREENFIELD) 1908777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; 1909341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_AMPDU) { 1910341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; 1911777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 1912777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 1913341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 1914341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_RX_STBC) 1915777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; 1916341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_TX_STBC) 1917777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; 1918341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_40MHZ) 1919777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; 1920341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_20MHZ) 1921777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; 1922341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_DELAY_BA) 1923777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; 1924341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_40MHZ) 1925777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 1926341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1927341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); 1928341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); 1929341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1930777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[0] = 0xff; 1931341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 2) 1932777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[1] = 0xff; 1933341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 3) 1934777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[2] = 0xff; 1935777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[4] = 0x01; 1936777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 1937341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1938341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams != tx_streams) { 1939777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 1940777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= (tx_streams - 1) << 1941341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 1942341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 1943341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek} 1944341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 194506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 194606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) 194706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek{ 194806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 194906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 195006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { 195106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_2ghz_band(hw); 195206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 195306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_24, caps); 195406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 195506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 195606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_5GHZ) { 195706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_5ghz_band(hw); 195806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 195906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_50, caps); 196006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 196106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek} 196206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 196304b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) 1964a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1965a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 196604b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_sta *cmd; 1967a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 1968a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1969a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1970a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1971a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 1972a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1973a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 1975a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 1976a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1977a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 1978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 197945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 19804ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); 1981a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 198245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); 19834ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 198445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 1985a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1986a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 1987a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1988a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 1989a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 1990a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 19914ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 1992a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hw_rev = cmd->hw_rev; 199306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); 1994ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x00000000; 1995ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->sta_macids_supported = 0x00000001; 1996a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1998a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 1999a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2000a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2001a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2002a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 200342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_GET_HW_SPEC (AP version). 200442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 200542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_ap { 200642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 200742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 200842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 200942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_wcb; 201042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 201142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 201242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 201342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_antenna; 201442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 201542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase0; 201642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxwrptr; 201742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxrdptr; 201842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 201942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase1; 202042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase2; 202142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase3; 2022952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo __le32 fw_api_version; 2023ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 202442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 202542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) 202642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 202742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 202842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_ap *cmd; 202942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int rc; 2030952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 api_version; 203142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 203242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 203342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 203442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 203542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 203642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 203742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 203842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 203942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 204042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 204142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 204242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 204342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 204442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) { 204542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int off; 204642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2047952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version = le32_to_cpu(cmd->fw_api_version); 2048952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo if (priv->device_info->fw_api_ap != api_version) { 2049952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo printk(KERN_ERR "%s: Unsupported fw API version for %s." 2050952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo " Expected %d got %d.\n", MWL8K_NAME, 2051952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->part_name, 2052952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->fw_api_ap, 2053952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version); 2054952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo rc = -EINVAL; 2055952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo goto done; 2056952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo } 205742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 205842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 205942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 206042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->hw_rev = cmd->hw_rev; 20611349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek mwl8k_setup_2ghz_band(hw); 2062ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x000000ff; 2063ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->sta_macids_supported = 0x00000000; 206442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 206542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->wcbbase0) & 0xffff; 2066b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->txq[0].txd_dma, priv->sram + off); 206742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 206842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxwrptr) & 0xffff; 2069b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 207042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 207142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxrdptr) & 0xffff; 2072b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 207342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 207442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->wcbbase1) & 0xffff; 2075b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->txq[1].txd_dma, priv->sram + off); 207642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 207742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->wcbbase2) & 0xffff; 2078b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->txq[2].txd_dma, priv->sram + off); 207942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 208042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->wcbbase3) & 0xffff; 2081b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->txq[3].txd_dma, priv->sram + off); 208242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 208342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2084952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolodone: 208542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 208642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 208742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 208842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 208942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 209042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_SET_HW_SPEC. 209142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 209242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_set_hw_spec { 209342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 209442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 209542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 209642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 209742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 209842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 209942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 210042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 210142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 caps; 210242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rx_queue_ptr; 210342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_queues; 210442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; 210542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 flags; 210642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_desc_per_queue; 210742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 total_rxd; 2108ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 210942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2110b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 2111b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 2112b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 211342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 211442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) 211542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 211642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 211742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_set_hw_spec *cmd; 211842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int rc; 211942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int i; 212042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 212142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 212242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 212342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 212442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 212542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC); 212642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 212742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 212842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 212942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 213042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); 213142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 213242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); 2133b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | 2134b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | 2135b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); 213642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 213742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 213842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 213942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 214042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 214142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 214242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 214342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 214442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 214542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 2146a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_MAC_MULTICAST_ADR. 2147a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2148a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_mac_multicast_adr { 2149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2150a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2151a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 numaddr; 2152ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek __u8 addr[0][ETH_ALEN]; 2153a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 2154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2155d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_DIRECTED 0x0001 2156d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_MULTICAST 0x0002 2157d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 2158d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_BROADCAST 0x0008 2159ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2160e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic struct mwl8k_cmd_pkt * 2161447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, 216222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 2163a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2164e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2165a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_mac_multicast_adr *cmd; 2166e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek int size; 216722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int mc_count = 0; 216822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko 216922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko if (mc_list) 217022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko mc_count = netdev_hw_addr_list_count(mc_list); 2171e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2172447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (allmulti || mc_count > priv->num_mcaddrs) { 2173d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek allmulti = 1; 2174d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek mc_count = 0; 2175d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } 2176e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2177e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek size = sizeof(*cmd) + mc_count * ETH_ALEN; 2178ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2179e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek cmd = kzalloc(size, GFP_ATOMIC); 2180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2181e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return NULL; 2182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); 2184a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(size); 2185d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED | 2186d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek MWL8K_ENABLE_RX_BROADCAST); 2187d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2188d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek if (allmulti) { 2189d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST); 2190d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } else if (mc_count) { 219122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 219222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int i = 0; 2193d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2194d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); 2195d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->numaddr = cpu_to_le16(mc_count); 219622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_hw_addr_list_for_each(ha, mc_list) { 219722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko memcpy(cmd->addr[i], ha->addr, ETH_ALEN); 2198a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2199a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2200a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2201e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return &cmd->header; 2202a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2203a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2204a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 220555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_GET_STAT. 2206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 220755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_get_stat { 2208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 stats[64]; 2210ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_ACK_FAILURE 9 2213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_FAILURE 12 2214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_FCS_ERROR 24 2215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_SUCCESS 11 2216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 221755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, 221855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_low_level_stats *stats) 2219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 222055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_get_stat *cmd; 2221a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2222a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2224a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2225a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2226a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2227a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); 2228a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2229a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2230a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2231a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 2232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11ACKFailureCount = 2233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]); 2234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSFailureCount = 2235a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]); 2236a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11FCSErrorCount = 2237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]); 2238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSSuccessCount = 2239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]); 2240a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2241a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 224755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RADIO_CONTROL. 2248a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 224955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_radio_control { 2250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 control; 2253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 radio_on; 2254ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2256c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhekstatic int 225755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) 2258a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 226055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_radio_control *cmd; 2261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2263c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek if (enable == priv->radio_on && !force) 2264a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 2265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2266a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2267a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2268a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2269a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2270a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); 2271a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2272a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 227368ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); 2274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); 2275a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2276a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2277a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2278a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2279a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) 2280c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek priv->radio_on = enable; 2281a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2282a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2283a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2284a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 228555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw) 2286c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 228755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 0, 0); 2288c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2289c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 229055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) 2291c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 229255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 0); 2293c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2294c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 2295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 2296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) 2297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 229899200a992e365a73dc67a6570524e5f3af4386ddLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 230068ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek priv->radio_short_preamble = short_preamble; 2301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 230255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 1); 2303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 230655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RF_TX_POWER. 2307a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 230841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 2309a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 231055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_rf_tx_power { 2311a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2312a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2313a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 support_level; 2314a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 current_level; 2315a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 reserved; 231641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL]; 2317ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 231955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) 2320a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 232155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_rf_tx_power *cmd; 2322a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2325a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2326a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2327a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER); 2329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2330a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->support_level = cpu_to_le16(dBm); 2332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2334a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 234041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam * CMD_TX_POWER. 234141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam */ 234241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_TX_POWER_LEVEL_TOTAL 12 234341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 234441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstruct mwl8k_cmd_tx_power { 234541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_pkt header; 234641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 action; 234741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 band; 234841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 channel; 234941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 bw; 235041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 sub_ch; 235141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; 235241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam} __attribute__((packed)); 235341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 235441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstatic int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, 235541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_conf *conf, 235641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam unsigned short pwr) 235741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam{ 235841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_channel *channel = conf->channel; 235941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_tx_power *cmd; 236041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int rc; 236141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int i; 236241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 236341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 236441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (cmd == NULL) 236541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return -ENOMEM; 236641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 236741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER); 236841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 236941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST); 237041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 237141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (channel->band == IEEE80211_BAND_2GHZ) 237241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x1); 237341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (channel->band == IEEE80211_BAND_5GHZ) 237441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x4); 237541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 237641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->channel = channel->hw_value; 237741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 237841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_NO_HT || 237941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam conf->channel_type == NL80211_CHAN_HT20) { 238041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x2); 238141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } else { 238241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x4); 238341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_HT40MINUS) 238441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x3); 238541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 238641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x1); 238741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } 238841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 238941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++) 239041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->power_level_list[i] = cpu_to_le16(pwr); 239141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 239241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_post_cmd(hw, &cmd->header); 239341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam kfree(cmd); 239441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 239541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return rc; 239641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam} 239741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 239841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam/* 239908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek * CMD_RF_ANTENNA. 240008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek */ 240108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstruct mwl8k_cmd_rf_antenna { 240208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_pkt header; 240308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 antenna; 240408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 mode; 2405ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 240608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 240708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_RX 1 240808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_TX 2 240908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 241008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstatic int 241108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekmwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) 241208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek{ 241308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_rf_antenna *cmd; 241408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek int rc; 241508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 241608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 241708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (cmd == NULL) 241808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return -ENOMEM; 241908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 242008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA); 242108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 242208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->antenna = cpu_to_le16(antenna); 242308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->mode = cpu_to_le16(mask); 242408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 242508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 242608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek kfree(cmd); 242708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 242808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return rc; 242908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek} 243008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 243108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek/* 2432b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_SET_BEACON. 2433b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 2434b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_set_beacon { 2435b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 2436b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le16 beacon_len; 2437b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __u8 beacon[0]; 2438b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek}; 2439b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2440aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, 2441aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, u8 *beacon, int len) 2442b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 2443b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_beacon *cmd; 2444b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 2445b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2446b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); 2447b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 2448b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 2449b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2450b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); 2451b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); 2452b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->beacon_len = cpu_to_le16(len); 2453b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->beacon, beacon, len); 2454b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2455aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 2456b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 2457b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2458b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 2459b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 2460b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2461b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 2462a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_PRE_SCAN. 2463a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2464a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_pre_scan { 2465a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2466ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2467a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) 2469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_pre_scan *cmd; 2471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2472a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2474a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN); 2478a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2479a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2480a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2481a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2482a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2483a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2484a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2485a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2486a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2487a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_POST_SCAN. 2488a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_post_scan { 2490a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 isibss; 2492d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 bssid[ETH_ALEN]; 2493ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 24960a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhekmwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) 2497a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_post_scan *cmd; 2499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2501a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2502a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2503a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2505a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN); 2506a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->isibss = 0; 2508d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memcpy(cmd->bssid, mac, ETH_ALEN); 2509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2512a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_RF_CHANNEL. 2518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2519a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_rf_channel { 2520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 current_channel; 2523a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 channel_flags; 2524ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, 2527610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_conf *conf) 2528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2529610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_channel *channel = conf->channel; 2530a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_rf_channel *cmd; 2531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2536a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2537a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL); 2538a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2539a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2540a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->current_channel = channel->hw_value; 2541610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 2542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (channel->band == IEEE80211_BAND_2GHZ) 2543610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000001); 254442574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek else if (channel->band == IEEE80211_BAND_5GHZ) 254542574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000004); 2546610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 2547610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek if (conf->channel_type == NL80211_CHAN_NO_HT || 2548610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek conf->channel_type == NL80211_CHAN_HT20) 2549610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000080); 2550610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40MINUS) 2551610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000001900); 2552610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 2553610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000000900); 2554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2556a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2561a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 256255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_AID. 2563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 256455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_DISABLED 0x00 256555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11G 0x07 256655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 256755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 2568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 256955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_set_aid { 257055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 257155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 aid; 2572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 257355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* AP's MAC address (BSSID) */ 257455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 bssid[ETH_ALEN]; 257555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 protection_mode; 257655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 supp_rates[14]; 2577ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2579c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekstatic void legacy_rate_mask_to_array(u8 *rates, u32 mask) 2580c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek{ 2581c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int i; 2582c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int j; 2583c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 2584c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek /* 2585c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek * Clear nonstandard rates 4 and 13. 2586c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek */ 2587c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek mask &= 0x1fef; 2588c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 2589c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek for (i = 0, j = 0; i < 14; i++) { 2590c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek if (mask & (1 << i)) 2591777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek rates[j++] = mwl8k_rates_24[i].hw_value; 2592c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek } 2593c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek} 2594c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 259555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 2596c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_aid(struct ieee80211_hw *hw, 2597c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, u32 legacy_rate_mask) 2598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 259955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_set_aid *cmd; 260055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek u16 prot_mode; 2601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 260755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); 2608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 26097dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek cmd->aid = cpu_to_le16(vif->bss_conf.aid); 26100a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); 2611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 26127dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.use_cts_prot) { 261355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11G; 261455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 26157dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek switch (vif->bss_conf.ht_operation_mode & 261655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek IEEE80211_HT_OP_MODE_PROTECTION) { 261755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: 261855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; 261955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 262055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: 262155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; 262255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 262355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek default: 262455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_DISABLED; 262555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 262655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 262755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 262855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->protection_mode = cpu_to_le16(prot_mode); 2629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2630c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); 2631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2632a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 263955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATE. 264032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek */ 264155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate { 264255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 264355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 legacy_rates[14]; 264455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 264555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Bitmap for supported MCS codes. */ 264655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mcs_set[16]; 264755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 reserved[16]; 2648ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 264932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 265055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 2651c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 265213935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u32 legacy_rate_mask, u8 *mcs_rates) 265332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek{ 265455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate *cmd; 265532060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek int rc; 265632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 265732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 265832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (cmd == NULL) 265932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return -ENOMEM; 266032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 266155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); 266232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2663c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); 266413935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->mcs_set, mcs_rates, 16); 266532060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 266632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 266732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek kfree(cmd); 266832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 266932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return rc; 267032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek} 267132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 267232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek/* 267355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_FINALIZE_JOIN. 2674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 267555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FJ_BEACON_MAXLEN 128 267655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 267755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_finalize_join { 2678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 267955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 sleep_interval; /* Number of beacon periods to sleep */ 268055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; 2681ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 268355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, 268455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int framelen, int dtim) 2685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 268655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_finalize_join *cmd; 268755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_mgmt *payload = frame; 268855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int payload_len; 2689a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 269555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); 2696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 269755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); 269855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 269955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = framelen - ieee80211_hdrlen(payload->frame_control); 270055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (payload_len < 0) 270155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = 0; 270255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) 270355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = MWL8K_FJ_BEACON_MAXLEN; 270455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 270555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); 2706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 271455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RTS_THRESHOLD. 2715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 271655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rts_threshold { 2717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 271955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 threshold; 2720ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2722c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekstatic int 2723c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekmwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) 2724a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 272555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rts_threshold *cmd; 2726a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2727a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2728a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2729a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2730a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2731a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 273255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); 2733a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2734c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2735c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->threshold = cpu_to_le16(rts_thresh); 2736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 274455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_SLOT. 2745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 274655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_slot { 2747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 274955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 short_slot; 2750ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 275255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) 2753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 275455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_slot *cmd; 2755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2759a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 276155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); 2762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 276355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 276455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->short_slot = short_slot_time; 2765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2770a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_EDCA_PARAMS. 2774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_edca_params { 2776a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* See MWL8K_SET_EDCA_XXX below */ 2779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* TX opportunity in units of 32 us */ 2782a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 txop; 2783a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 27842e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek union { 27852e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 27862e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 27872e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_max; 27882e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 27892e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 27902e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_min; 27912e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 27922e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 27932e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 27942e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 27952e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 27962e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 27972e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } ap; 27982e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 27992e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 28002e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_max; 2801a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28022e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 28032e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_min; 2804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28052e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 28062e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 2807a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28082e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 28092e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 28102e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } sta; 28112e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek }; 2812ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2814a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_CW 0x01 2815a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_TXOP 0x02 2816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_AIFS 0x04 2817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2818a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_ALL (MWL8K_SET_EDCA_CW | \ 2819a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_TXOP | \ 2820a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_AIFS) 2821a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2822a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 282355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, 282455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u16 cw_min, __u16 cw_max, 282555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 aifs, __u16 txop) 2826a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 28272e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2828a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_edca_params *cmd; 2829a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2830a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2831a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2832a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2833a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2834a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2835a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); 2836a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2837a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); 2838a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->txop = cpu_to_le16(txop); 28392e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek if (priv->ap_fw) { 28402e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1)); 28412e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1)); 28422e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.aifs = aifs; 28432e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.txq = qnum; 28442e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } else { 28452e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1); 28462e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1); 28472e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.aifs = aifs; 28482e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.txq = qnum; 28492e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } 2850a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2851a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2853a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2854a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2855a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2856a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2857a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 285855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_WMM_MODE. 2859a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 286055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_wmm_mode { 2861a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 286255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 2863ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2864a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 286555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) 2866a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 286755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 286855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_wmm_mode *cmd; 2869a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2870a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2871a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2872a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2873a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2874a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 287555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); 2876a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 287755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(!!enable); 2878a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2879a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2880a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 288116cec43da50c4b4702653ca710549fd3457a4e6cLennert Buytenhek 288255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (!rc) 288355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek priv->wmm_enabled = enable; 2884a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2885a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2886a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2887a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2888a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 288955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_MIMO_CONFIG. 2890a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 289155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_mimo_config { 289255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 289355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 289455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 rx_antenna_map; 289555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 tx_antenna_map; 2896ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2897a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 289855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) 2899a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 290055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_mimo_config *cmd; 2901a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2902a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2903a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2904a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2905a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2906a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 290755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); 2908a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 290955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); 291055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->rx_antenna_map = rx; 291155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->tx_antenna_map = tx; 2912a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2913a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2914a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2915a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2916a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2917a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2918a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2919a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2920b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek * CMD_USE_FIXED_RATE (STA version). 2921a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2922b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_sta { 2923b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_pkt header; 2924b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 action; 2925b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 allow_rate_drop; 2926b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 num_rates; 2927b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct { 2928b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 is_ht_rate; 2929b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 enable_retry; 2930b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate; 2931b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 retry_count; 2932b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek } rate_entry[8]; 2933b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate_type; 2934b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved1; 2935b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved2; 2936ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2937a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2938b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_USE_AUTO_RATE 0x0002 2939b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_UCAST_RATE 0 2940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2941b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstatic int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) 2942a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2943b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_sta *cmd; 2944a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2945a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2946a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2950a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 2951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2952b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 2953b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); 2954a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2955a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2956a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2957a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2958a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2959a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2960a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 296155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 2962088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek * CMD_USE_FIXED_RATE (AP version). 2963088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek */ 2964088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_ap { 2965088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_pkt header; 2966088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 action; 2967088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 allow_rate_drop; 2968088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 num_rates; 2969088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_rate_entry_ap { 2970088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 is_ht_rate; 2971088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 enable_retry; 2972088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 rate; 2973088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 retry_count; 2974088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek } rate_entry[4]; 2975088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate; 2976088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate_type; 2977088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 management_rate; 2978ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2979088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 2980088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstatic int 2981088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekmwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) 2982088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek{ 2983088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_ap *cmd; 2984088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek int rc; 2985088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 2986088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2987088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek if (cmd == NULL) 2988088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return -ENOMEM; 2989088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 2990088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 2991088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2992088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 2993088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->multicast_rate = mcast; 2994088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->management_rate = mgmt; 2995088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 2996088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2997088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek kfree(cmd); 2998088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 2999088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return rc; 3000088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek} 3001088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3002088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek/* 300355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_ENABLE_SNIFFER. 300455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 300555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_enable_sniffer { 300655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 300755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 3008ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 300955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 301055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) 301155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 301255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_enable_sniffer *cmd; 301355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 301455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 301555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 301655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 301755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 301855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 301955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); 302055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 302155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32(!!enable); 302255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 302355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 302455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 302555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 302655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 302755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 302855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 302955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 303055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_MAC_ADDR. 303155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 303255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_mac_addr { 303355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 303455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek union { 303555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct { 303655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mac_type; 303755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 303855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } mbss; 303955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 304055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek }; 3041ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 304255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3043ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 3044ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 3045ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_AP 2 3046ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_AP 3 3047a9e00b151ec2121b7ae09d84a2b5a68b6461e98aLennert Buytenhek 3048aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, 3049aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, u8 *mac) 305055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 305155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3052ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 305355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_mac_addr *cmd; 3054ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek int mac_type; 305555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 305655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3057ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3058ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { 3059ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) 3060ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; 3061ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3062ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; 3063ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { 3064ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) 3065ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3066ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3067ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; 3068ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 3069ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 307055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 307155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 307255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 307355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 307455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); 307555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 307655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (priv->ap_fw) { 3077ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek cmd->mbss.mac_type = cpu_to_le16(mac_type); 307855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); 307955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 308055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mac_addr, mac, ETH_ALEN); 308155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 308255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3083aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 308455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 308555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 308655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 308755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 308855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 308955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 309055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATEADAPT_MODE. 309155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 309255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate_adapt_mode { 309355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 309455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 309555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mode; 3096ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 309755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 309855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) 309955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 310055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate_adapt_mode *cmd; 310155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 310255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 310355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 310455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 310555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 310655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 310755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); 310855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 310955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 311055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->mode = cpu_to_le16(mode); 311155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 311255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 311355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 311455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 311555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 311655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 311755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 311855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 3119b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_BSS_START. 3120b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 3121b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_bss_start { 3122b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 3123b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le32 enable; 3124ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3125b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3126aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, 3127aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, int enable) 3128b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3129b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_bss_start *cmd; 3130b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3131b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3132b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3133b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3134b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3135b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3136b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); 3137b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3138b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->enable = cpu_to_le32(enable); 3139b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3140aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3141b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3142b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3143b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3144b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3145b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3146b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 31473f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek * CMD_SET_NEW_STN. 31483f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek */ 31493f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstruct mwl8k_cmd_set_new_stn { 31503f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_pkt header; 31513f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 aid; 31523f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_addr[6]; 31533f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stn_id; 31543f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 action; 31553f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 rsvd; 31563f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 legacy_rates; 31573f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 ht_rates[4]; 31583f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 cap_info; 31593f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 ht_capabilities_info; 31603f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_ht_param_info; 31613f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 rev; 31623f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 control_channel; 31633f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_channel; 31643f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 op_mode; 31653f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stbc; 31663f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_qos_info; 31673f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 is_qos_sta; 31683f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 fw_sta_ptr; 3169ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 31703f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 31713f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_ADD 0 31723f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_REMOVE 2 31733f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 31743f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, 31753f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, 31763f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_sta *sta) 31773f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 31783f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 31798707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 31803f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek int rc; 31813f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 31823f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 31833f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 31843f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 31853f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 31863f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 31873f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 31883f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->aid = cpu_to_le16(sta->aid); 31893f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); 31903f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->stn_id = cpu_to_le16(sta->aid); 31913f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); 31928707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 31938707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 31948707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 31958707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 31968707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek cmd->legacy_rates = cpu_to_le32(rates); 31973f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (sta->ht_cap.ht_supported) { 31983f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; 31993f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; 32003f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; 32013f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; 32023f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); 32033f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | 32043f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 32053f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->is_qos_sta = 1; 32063f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek } 32073f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3208aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 32093f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 32103f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32113f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 32123f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 32133f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3214b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, 3215b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_vif *vif) 3216b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3217b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 3218b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3219b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3220b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3221b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3222b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3223b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3224b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 3225b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3226b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); 3227b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3228aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3229b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3230b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3231b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3232b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3233b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 32343f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, 32353f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 32363f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 32373f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 32383f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek int rc; 32393f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32403f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 32413f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 32423f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 32433f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32443f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 32453f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 32463f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, addr, ETH_ALEN); 32473f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); 32483f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3249aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 32503f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 32513f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32523f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 32533f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 32543f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32553f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek/* 3256fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam * CMD_UPDATE_ENCRYPTION. 3257fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam */ 3258fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3259fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MAX_ENCR_KEY_LENGTH 16 3260fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MIC_KEY_LENGTH 8 3261fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3262fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_update_encryption { 3263fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 3264fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3265fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 3266fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 3267fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 3268fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 encr_type; 3269fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3270fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} __attribute__((packed)); 3271fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3272fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_set_key { 3273fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 3274fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3275fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 3276fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 3277fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 length; 3278fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_type_id; 3279fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_info; 3280fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_id; 3281fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_len; 3282fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 key_material[MAX_ENCR_KEY_LENGTH]; 3283fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; 3284fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; 3285fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_rsc_low; 3286fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_rsc_high; 3287fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_tsc_low; 3288fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_tsc_high; 3289fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 3290fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} __attribute__((packed)); 3291fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3292fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 3293fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_ENABLE, 3294fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_KEY, 3295fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_REMOVE_KEY, 3296fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_GROUP_KEY, 3297fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 3298fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3299fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 3300fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 3301fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 3302fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 3303fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 3304fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3305fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 3306fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_WEP, 3307fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_TKIP, 3308fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_CCMP, 3309fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 3310fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3311fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 3312fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 3313fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 3314fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 3315fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 3316fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3317fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, 3318fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3319fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3320fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type) 3321fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3322fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_update_encryption *cmd; 3323fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3324fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3325fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3326fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3327fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3328fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3329fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3330fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3331fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); 3332fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 3333fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->encr_type = encr_type; 3334fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3335fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3336fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3337fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3338fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3339fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3340fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3341fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, 3342fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3343fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3344fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3345fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3346fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3347fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->length = cpu_to_le16(sizeof(*cmd) - 3348fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam offsetof(struct mwl8k_cmd_set_key, length)); 3349fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_id = cpu_to_le32(key->keyidx); 3350fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_len = cpu_to_le16(key->keylen); 3351fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 3352fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3353fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 3354fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 3355fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 3356fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); 3357fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->keyidx == 0) 3358fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); 3359fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3360fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3361fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 3362fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); 3363fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3364fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3365fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3366fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID 3367fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam | MWL8K_KEY_FLAG_TSC_VALID); 3368fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3369fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 3370fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); 3371fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3372fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3373fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3374fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3375fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 3376fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOTSUPP; 3377fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3378fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3379fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return 0; 3380fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3381fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3382fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, 3383fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3384fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3385fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3386fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3387fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 3388fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3389fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int keymlen; 3390fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u32 action; 3391fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 idx; 3392fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3393fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3394fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3395fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3396fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3397fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3398fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3399fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 3400fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3401fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3402fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam idx = key->keyidx; 3403fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3404fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3405fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 3406fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3407fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_GROUP_KEY; 3408fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3409fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 3410fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 3411fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 3412fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (!mwl8k_vif->wep_key_conf[idx].enabled) { 3413fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(mwl8k_vif->wep_key_conf[idx].key, key, 3414fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam sizeof(*key) + key->keylen); 3415fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[idx].enabled = 1; 3416fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3417fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3418fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = 0; 3419fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 3420fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3421fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 3422fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; 3423fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3424fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 3425fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = key->keylen; 3426fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3427fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 3428fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = -ENOTSUPP; 3429fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3430fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3431fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3432fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->key_material, key->key, keymlen); 3433fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(action); 3434fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3435fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3436fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 3437fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3438fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3439fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3440fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3441fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3442fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, 3443fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3444fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3445fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3446fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3447fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 3448fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3449fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3450fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3451fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3452fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3453fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3454fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3455fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3456fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 3457fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3458fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3459fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || 3460fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam WLAN_CIPHER_SUITE_WEP104) 3461fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; 3462fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3463fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); 3464fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3465fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3466fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 3467fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3468fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3469fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3470fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3471fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3472fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_set_key(struct ieee80211_hw *hw, 3473fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam enum set_key_cmd cmd_param, 3474fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3475fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_sta *sta, 3476fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3477fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3478fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc = 0; 3479fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type; 3480fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr; 3481fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3482fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3483fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (vif->type == NL80211_IFTYPE_STATION) 3484fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -EOPNOTSUPP; 3485fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3486fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (sta == NULL) 3487fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam addr = hw->wiphy->perm_addr; 3488fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3489fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam addr = sta->addr; 3490fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3491fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd_param == SET_KEY) { 3492fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 3493fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); 3494fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3495fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3496fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3497fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) 3498fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) 3499fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; 3500fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3501fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; 3502fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3503fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, 3504fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type); 3505fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3506fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3507fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3508fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = true; 3509fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3510fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } else { 3511fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); 3512fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3513fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3514fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3515fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3516fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = false; 3517fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3518fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3519fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamout: 3520fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3521fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3522fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3523fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam/* 352455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_UPDATE_STADB. 352555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 352625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct ewc_ht_info { 352725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control1; 352825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control2; 352925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control3; 3530ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 353125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 353225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct peer_capability_info { 353325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Peer type - AP vs. STA. */ 353425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 peer_type; 353525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 353625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Basic 802.11 capabilities from assoc resp. */ 353725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 basic_caps; 353825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 353925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Set if peer supports 802.11n high throughput (HT). */ 354025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_support; 354125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 354225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Valid if HT is supported. */ 354325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 ht_caps; 354425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 extended_ht_caps; 354525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek struct ewc_ht_info ewc_info; 354625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 354725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Legacy rate table. Intersection of our rates and peer rates. */ 354825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 legacy_rates[12]; 354925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 355025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* HT rate table. Intersection of our rates and peer rates. */ 355125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_rates[16]; 355225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad[16]; 355325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 355425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* If set, interoperability mode, no proprietary extensions. */ 355525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 interop; 355625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad2; 355725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 station_id; 355825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 amsdu_enabled; 3559ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 356025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 356155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_stadb { 356255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 356355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 356455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* See STADB_ACTION_TYPE */ 356555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 356655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 356755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer MAC address */ 356855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 peer_addr[ETH_ALEN]; 356955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 357055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 reserved; 357155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 357255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer info - valid during add/update. */ 357355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct peer_capability_info peer_info; 3574ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 357555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3576a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_MODIFY_ENTRY 1 3577a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_DEL_ENTRY 2 3578a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3579a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek/* Peer Entry flags - used to define the type of the peer node */ 3580a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_PEER_TYPE_ACCESSPOINT 2 3581a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3582a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, 3583c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, 358413935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek struct ieee80211_sta *sta) 358555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 358655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 3587a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct peer_capability_info *p; 35888707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 358955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 359055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 359155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 359255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 359355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 359455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 359555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 359655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3597a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); 359813935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); 359955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3600a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p = &cmd->peer_info; 3601a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; 3602a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); 360313935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->ht_support = sta->ht_cap.ht_supported; 3604b603742f49c3ec922522602e18ac22e8f6835132John W. Linville p->ht_caps = cpu_to_le16(sta->ht_cap.cap); 360513935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | 360613935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 36078707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 36088707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 36098707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 36108707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 36118707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek legacy_rate_mask_to_array(p->legacy_rates, rates); 361213935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); 3613a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->interop = 1; 3614a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->amsdu_enabled = 0; 3615a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3616a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3617a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek kfree(cmd); 3618a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3619a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek return rc ? rc : p->station_id; 3620a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek} 3621a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3622a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, 3623a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 3624a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek{ 3625a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 3626a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek int rc; 3627a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3628a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3629a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek if (cmd == NULL) 3630a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek return -ENOMEM; 3631a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3632a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 3633a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3634a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); 3635bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek memcpy(cmd->peer_addr, addr, ETH_ALEN); 363655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3637a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 363855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 363955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 364055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 364155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 364255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Interrupt handling. 3646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic irqreturn_t mwl8k_interrupt(int irq, void *dev_id) 3648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = dev_id; 3650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 3652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 3654a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!status) 3655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_NONE; 3656a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 36571e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (status & MWL8K_A2H_INT_TX_DONE) { 36581e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek status &= ~MWL8K_A2H_INT_TX_DONE; 36591e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 36601e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 36611e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 3662a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_RX_READY) { 366367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek status &= ~MWL8K_A2H_INT_RX_READY; 366467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 3665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 366767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (status) 366867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 366967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 3670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_OPC_DONE) { 3671618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->hostcmd_wait != NULL) 3672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek complete(priv->hostcmd_wait); 3673a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { 3676618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!mutex_is_locked(&priv->fw_mutex) && 367788de754ad59025eba797e7a8375807755577f450Lennert Buytenhek priv->radio_on && priv->pending_tx_pkts) 3678618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mwl8k_tx_start(priv); 3679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_HANDLED; 3682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 36841e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhekstatic void mwl8k_tx_poll(unsigned long data) 36851e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek{ 36861e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 36871e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 36881e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int limit; 36891e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int i; 36901e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 36911e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit = 32; 36921e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 36931e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_lock_bh(&priv->tx_lock); 36941e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 36951e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 36961e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit -= mwl8k_txq_reclaim(hw, i, limit, 0); 36971e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 36981e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { 36991e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek complete(priv->tx_wait); 37001e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->tx_wait = NULL; 37011e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 37021e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37031e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 37041e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37051e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (limit) { 37061e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek writel(~MWL8K_A2H_INT_TX_DONE, 37071e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 37081e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } else { 37091e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 37101e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 37111e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek} 37121e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 371367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhekstatic void mwl8k_rx_poll(unsigned long data) 371467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek{ 371567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 371667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 371767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek int limit; 371867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 371967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit = 32; 372067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_process(hw, 0, limit); 372167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_refill(hw, 0, limit); 372267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 372367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (limit) { 372467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek writel(~MWL8K_A2H_INT_RX_READY, 372567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 372667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } else { 372767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 372867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } 372967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek} 373067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 3731a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3732a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3733a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Core driver operations. 3734a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 3736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int index = skb_get_queue_mapping(skb); 3739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37419189c10087a738c764046fa27651d332594cd8e6Lennert Buytenhek if (!priv->radio_on) { 3742c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 3743c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "dropped TX frame since radio disabled\n"); 3744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(skb); 3745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return NETDEV_TX_OK; 3746a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_txq_xmit(hw, index, skb); 3749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_start(struct ieee80211_hw *hw) 3754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3758a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 3759a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 3760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 37615db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 37622ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek return -EIO; 3763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3764a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 376567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Enable TX reclaim and RX tasklets. */ 37661e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_enable(&priv->poll_tx_task); 376767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_enable(&priv->poll_rx_task); 37682ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 3769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Enable interrupts */ 3770c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37722ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek rc = mwl8k_fw_lock(hw); 37732ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) { 377455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 3775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37765e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!priv->ap_fw) { 37775e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 377855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_enable_sniffer(hw, 0); 3779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37805e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 37815e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_pre_scan(hw); 37825e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek 37835e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 37845e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_post_scan(hw, 37855e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek "\x00\x00\x00\x00\x00\x00"); 37865e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek } 37872ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 37882ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 378955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_rateadapt_mode(hw, 0); 3790a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37912ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 379255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 0); 3793a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37942ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek mwl8k_fw_unlock(hw); 37952ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 37962ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 37972ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (rc) { 37982ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 37992ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek free_irq(priv->pdev->irq, hw); 38001e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 380167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 38022ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 3803a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3807a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_stop(struct ieee80211_hw *hw) 3808a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3809a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3810a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 3811a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 381255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_radio_disable(hw); 3813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3814a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 3815a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 3817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3818a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 3819a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3820a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop finalize join worker */ 3821a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cancel_work_sync(&priv->finalize_join_worker); 3822a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 3823a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(priv->beacon_skb); 3824a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 382567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Stop TX reclaim and RX tasklets. */ 38261e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 382767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 3828a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3829a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 3830a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 3831efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 3832a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3833a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38340863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image); 38350863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 3836a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_add_interface(struct ieee80211_hw *hw, 3837f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif) 3838a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3839a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3840a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 3841ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_supported; 38420863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo int macid, rc; 38430863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 3844a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3845a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 3846a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Reject interface creation if sniffer mode is active, as 3847a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * STA operation is mutually exclusive with hardware sniffer 3848b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * mode. (Sniffer mode is only used on STA firmware.) 3849a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 3850a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 3851c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 3852c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "unable to create STA interface because sniffer mode is enabled\n"); 3853a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return -EINVAL; 3854a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 3855a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 38560863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 3857ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek switch (vif->type) { 3858ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_AP: 38590863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!priv->ap_fw && di->fw_image_ap) { 38600863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* we must load the ap fw to meet this request */ 38610863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!list_empty(&priv->vif_list)) 38620863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return -EBUSY; 38630863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo rc = mwl8k_reload_firmware(hw, di->fw_image_ap); 38640863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (rc) 38650863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return rc; 38660863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 3867ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->ap_macids_supported; 3868ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 3869ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_STATION: 38700863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (priv->ap_fw && di->fw_image_sta) { 38710863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* we must load the sta fw to meet this request */ 38720863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!list_empty(&priv->vif_list)) 38730863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return -EBUSY; 38740863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo rc = mwl8k_reload_firmware(hw, di->fw_image_sta); 38750863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (rc) 38760863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return rc; 38770863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 3878ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->sta_macids_supported; 3879ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 3880ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek default: 3881ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EINVAL; 3882ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 3883ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 3884ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macid = ffs(macids_supported & ~priv->macids_used); 3885ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (!macid--) 3886ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EBUSY; 3887ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 3888f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* Setup driver private area. */ 38891ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg mwl8k_vif = MWL8K_VIF(vif); 3890a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); 3891f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif->vif = vif; 3892ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mwl8k_vif->macid = macid; 3893a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif->seqno = 0; 3894d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); 3895d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = false; 3896a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3897aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek /* Set the mac address. */ 3898aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); 3899aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 3900aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek if (priv->ap_fw) 3901aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_new_stn_add_self(hw, vif); 3902aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 3903ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->macids_used |= 1 << mwl8k_vif->macid; 3904f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek list_add_tail(&mwl8k_vif->list, &priv->vif_list); 3905a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3906a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 3907a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3908a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3909a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_remove_interface(struct ieee80211_hw *hw, 39101ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg struct ieee80211_vif *vif) 3911a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3912a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3913f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3914a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3915b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (priv->ap_fw) 3916b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); 3917b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3918aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); 391932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 3920ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->macids_used &= ~(1 << mwl8k_vif->macid); 3921f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek list_del(&mwl8k_vif->list); 3922a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3923a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3924ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekstatic int mwl8k_config(struct ieee80211_hw *hw, u32 changed) 3925a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3926a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_conf *conf = &hw->conf; 3927a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3928ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek int rc; 3929a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 39307595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek if (conf->flags & IEEE80211_CONF_IDLE) { 393155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_radio_disable(hw); 3932ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return 0; 39337595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek } 39347595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek 3935ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek rc = mwl8k_fw_lock(hw); 3936ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3937ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 3938a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 393955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 3940ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3941ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek goto out; 3942a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3943610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek rc = mwl8k_cmd_set_rf_channel(hw, conf); 3944ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3945ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek goto out; 3946ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek 3947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (conf->power_level > 18) 3948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek conf->power_level = 18; 3949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 395008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (priv->ap_fw) { 395141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); 395241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (rc) 395341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto out; 395441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 3955da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); 3956da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam if (rc) 3957da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); 3958da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); 3959da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam if (rc) 3960da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); 3961da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam 396208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } else { 396341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); 396441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (rc) 396541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto out; 396608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); 396708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } 3968a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3969ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekout: 3970ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek mwl8k_fw_unlock(hw); 3971a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3972ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 3973a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3975b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 3976b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 3977b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 3978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3979a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3980c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek u32 ap_legacy_rates; 398113935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u8 ap_mcs_rates[16]; 39823a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek int rc; 39833a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 3984c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (mwl8k_fw_lock(hw)) 39853a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek return; 3986a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3987c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 3988c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek * No need to capture a beacon if we're no longer associated. 3989c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 3990c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) 3991c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek priv->capture_beacon = false; 39923a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 3993c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 399413935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek * Get the AP's legacy and MCS rates. 3995c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 39967dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.assoc) { 3997c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_sta *ap; 3998c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek 3999c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek rcu_read_lock(); 4000c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4001c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); 4002c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (ap == NULL) { 4003c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4004c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek goto out; 4005c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4006c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 40078707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { 40088707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; 40098707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } else { 40108707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = 40118707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; 40128707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } 401313935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); 4014c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 4015c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4016c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4017c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4018c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { 401913935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); 40203a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40213a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4023b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek rc = mwl8k_cmd_use_fixed_rate_sta(hw); 40243a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40253a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4026c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4027a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4028c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 40297dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 40307dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek vif->bss_conf.use_short_preamble); 40313a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40323a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4033c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4034a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4035c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_SLOT) { 40367dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); 40373a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40383a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4039c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4040a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4041c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek if (vif->bss_conf.assoc && 4042c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | 4043c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek BSS_CHANGED_HT))) { 4044c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); 40453a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40463a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4047c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4048a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4049c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (vif->bss_conf.assoc && 4050c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { 4051a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4052a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Finalize the join. Tell rx handler to process 4053a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * next beacon from our BSSID. 4054a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 40550a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); 4056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = true; 4057a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4058a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 40593a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhekout: 40603a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek mwl8k_fw_unlock(hw); 4061a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4062a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4063b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4064b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4065b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4066b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4067b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 4068b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4069b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (mwl8k_fw_lock(hw)) 4070b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return; 4071b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4072b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 4073b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 4074b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek vif->bss_conf.use_short_preamble); 4075b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (rc) 4076b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek goto out; 4077b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4078b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4079b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BASIC_RATES) { 4080b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int idx; 4081b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rate; 4082b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4083b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek /* 4084b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * Use lowest supported basic rate for multicasts 4085b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * and management frames (such as probe responses -- 4086b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * beacons will always go out at 1 Mb/s). 4087b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 4088b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek idx = ffs(vif->bss_conf.basic_rates); 40898707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (idx) 40908707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek idx--; 40918707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek 40928707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 40938707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_24[idx].hw_value; 40948707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 40958707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_50[idx].hw_value; 4096b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4097b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); 4098b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4099b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4100b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { 4101b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct sk_buff *skb; 4102b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4103b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek skb = ieee80211_beacon_get(hw, vif); 4104b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (skb != NULL) { 4105aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); 4106b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree_skb(skb); 4107b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4108b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4109b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4110b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BEACON_ENABLED) 4111aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); 4112b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4113b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekout: 4114b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_fw_unlock(hw); 4115b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4116b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4117b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4118b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4119b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4120b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4121b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4122b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4123b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (!priv->ap_fw) 4124b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_sta(hw, vif, info, changed); 4125b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek else 4126b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_ap(hw, vif, info, changed); 4127b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4128b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4129e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, 413022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 4131e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek{ 4132e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_cmd_pkt *cmd; 4133e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4134447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 4135447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * Synthesize and return a command packet that programs the 4136447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * hardware multicast address filter. At this point we don't 4137447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * know whether FIF_ALLMULTI is being requested, but if it is, 4138447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * we'll end up throwing this packet away and creating a new 4139447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * one in mwl8k_configure_filter(). 4140447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 414122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_list); 4142e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4143e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return (unsigned long)cmd; 4144e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek} 4145e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4146a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekstatic int 4147a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekmwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, 4148a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int changed_flags, 4149a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int *total_flags) 4150a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek{ 4151a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4152a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4153a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 4154a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Hardware sniffer mode is mutually exclusive with STA 4155a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * operation, so refuse to enable sniffer mode if a STA 4156a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * interface is active. 4157a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 4158f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) { 4159a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (net_ratelimit()) 4160c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 4161c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "not enabling sniffer mode because STA interface is active\n"); 4162a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 4163a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4164a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4165a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (!priv->sniffer_enabled) { 416655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (mwl8k_cmd_enable_sniffer(hw, 1)) 4167a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 4168a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = true; 4169a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4170a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4171a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | 4172a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | 4173a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_OTHER_BSS; 4174a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4175a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 1; 4176a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek} 4177a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4178f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhekstatic struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) 4179f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek{ 4180f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) 4181f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return list_entry(priv->vif_list.next, struct mwl8k_vif, list); 4182f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 4183f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return NULL; 4184f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek} 4185f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 4186e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhekstatic void mwl8k_configure_filter(struct ieee80211_hw *hw, 4187e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int changed_flags, 4188e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int *total_flags, 4189e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek u64 multicast) 4190e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek{ 4191e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4192a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; 4193a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4194a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 4195c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * AP firmware doesn't allow fine-grained control over 4196c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * the receive filter. 4197c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek */ 4198c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek if (priv->ap_fw) { 4199c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 4200c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek kfree(cmd); 4201c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek return; 4202c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek } 4203c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek 4204c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek /* 4205a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Enable hardware sniffer mode if FIF_CONTROL or 4206a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * FIF_OTHER_BSS is requested. 4207a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 4208a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (*total_flags & (FIF_CONTROL | FIF_OTHER_BSS) && 4209a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek mwl8k_configure_filter_sniffer(hw, changed_flags, total_flags)) { 4210a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek kfree(cmd); 4211a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return; 4212a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4214e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek /* Clear unsupported feature flags */ 4215447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 4216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 421790852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek if (mwl8k_fw_lock(hw)) { 421890852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek kfree(cmd); 4219e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek return; 422090852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek } 4221a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4222a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 422355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_enable_sniffer(hw, 0); 4224a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = false; 4225a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4226a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4227e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 422877165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { 422977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 423077165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Disable the BSS filter. 423177165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 4232e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_pre_scan(hw); 423377165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek } else { 4234f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 42350a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek const u8 *bssid; 4236a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 423777165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 423877165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Enable the BSS filter. 423977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * 424077165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * If there is an active STA interface, use that 424177165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * interface's BSSID, otherwise use a dummy one 424277165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * (where the OUI part needs to be nonzero for 424377165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * the BSSID to be accepted by POST_SCAN). 424477165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 4245f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif = mwl8k_first_vif(priv); 4246f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (mwl8k_vif != NULL) 4247f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = mwl8k_vif->vif->bss_conf.bssid; 4248f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek else 4249f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = "\x01\x00\x00\x00\x00\x00"; 4250a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 4251e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_post_scan(hw, bssid); 4252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4255447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 4256447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * If FIF_ALLMULTI is being requested, throw away the command 4257447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packet that ->prepare_multicast() built and replace it with 4258447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * a command packet that enables reception of all multicast 4259447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packets. 4260447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 4261447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (*total_flags & FIF_ALLMULTI) { 4262447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 426322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, NULL); 4264447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek } 4265447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek 4266447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (cmd != NULL) { 4267447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek mwl8k_post_cmd(hw, cmd); 4268447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 4269e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek } 4270a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4271e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_fw_unlock(hw); 4272a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 4275a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4276c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek return mwl8k_cmd_set_rts_threshold(hw, value); 4277a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4278a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 42794a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_remove(struct ieee80211_hw *hw, 42804a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 42814a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 42823f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 42833f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 42843f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 42854a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (priv->ap_fw) 42864a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr); 42874a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg else 42884a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr); 4289bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 4290bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 42914a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_add(struct ieee80211_hw *hw, 42924a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 42934a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 4294bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek{ 4295bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 42964a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg int ret; 4297fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int i; 4298fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4299fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key; 4300bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 43014a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (!priv->ap_fw) { 43024a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); 43034a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (ret >= 0) { 43044a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg MWL8K_STA(sta)->peer_id = ret; 4305fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ret = 0; 43064a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg } 4307bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 4308d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } else { 4309d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); 4310bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek } 43114a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg 4312d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam for (i = 0; i < NUM_WEP_KEYS; i++) { 4313d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); 4314d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif->wep_key_conf[i].enabled) 4315d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_set_key(hw, SET_KEY, vif, sta, key); 4316d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 4317fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return ret; 4318bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 4319bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 4320a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, 4321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const struct ieee80211_tx_queue_params *params) 4322a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 43233e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 4325a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43263e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek rc = mwl8k_fw_lock(hw); 43273e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!rc) { 43280863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo BUG_ON(queue > MWL8K_TX_QUEUES - 1); 43290863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo memcpy(&priv->wmm_params[queue], params, sizeof(*params)); 43300863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 43313e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!priv->wmm_enabled) 433255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 1); 4333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43343e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!rc) 433555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_edca_params(hw, queue, 433655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_min, 433755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_max, 433855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->aifs, 433955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->txop); 43403e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 43413e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek mwl8k_fw_unlock(hw); 4342a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 43433e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 4344a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 4345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_get_stats(struct ieee80211_hw *hw, 4348a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_low_level_stats *stats) 4349a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 435055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_get_stat(hw, stats); 4351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4352a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43530d462bbb0e20863b6c796abd779bfdb534d60278John W. Linvillestatic int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, 43540d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct survey_info *survey) 43550d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville{ 43560d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct mwl8k_priv *priv = hw->priv; 43570d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct ieee80211_conf *conf = &hw->conf; 43580d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43590d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville if (idx != 0) 43600d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return -ENOENT; 43610d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43620d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->channel = conf->channel; 43630d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->filled = SURVEY_INFO_NOISE_DBM; 43640d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->noise = priv->noise; 43650d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43660d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return 0; 43670d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville} 43680d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 4369a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekstatic int 4370a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekmwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4371a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek enum ieee80211_ampdu_mlme_action action, 43720b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg struct ieee80211_sta *sta, u16 tid, u16 *ssn, 43730b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg u8 buf_size) 4374a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek{ 4375a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek switch (action) { 4376a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_START: 4377a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_STOP: 4378a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) 4379a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return -ENOTSUPP; 4380a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return 0; 4381a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek default: 4382a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return -ENOTSUPP; 4383a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek } 4384a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek} 4385a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek 4386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic const struct ieee80211_ops mwl8k_ops = { 4387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .tx = mwl8k_tx, 4388a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .start = mwl8k_start, 4389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .stop = mwl8k_stop, 4390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .add_interface = mwl8k_add_interface, 4391a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .remove_interface = mwl8k_remove_interface, 4392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .config = mwl8k_config, 4393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .bss_info_changed = mwl8k_bss_info_changed, 43943ac64beecd27400d12cc7afb4108eef26c499f6aJohannes Berg .prepare_multicast = mwl8k_prepare_multicast, 4395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .configure_filter = mwl8k_configure_filter, 4396fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam .set_key = mwl8k_set_key, 4397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .set_rts_threshold = mwl8k_set_rts_threshold, 43984a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_add = mwl8k_sta_add, 43994a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_remove = mwl8k_sta_remove, 4400a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .conf_tx = mwl8k_conf_tx, 4401a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .get_stats = mwl8k_get_stats, 44020d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville .get_survey = mwl8k_get_survey, 4403a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek .ampdu_action = mwl8k_ampdu_action, 4404a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 4405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_finalize_join_worker(struct work_struct *work) 4407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4408a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = 4409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek container_of(work, struct mwl8k_priv, finalize_join_worker); 4410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb = priv->beacon_skb; 441156007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 441256007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable); 441356007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM, 441456007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mgmt->u.beacon.variable, len); 441556007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int dtim_period = 1; 441656007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg 441756007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg if (tim && tim[1] >= 2) 441856007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg dtim_period = tim[3]; 4419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 442056007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period); 4421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4422f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek dev_kfree_skb(skb); 4423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = NULL; 4424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4426bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linvilleenum { 44279e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8363 = 0, 44289e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8687, 4429bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville MWL8366, 44306f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 44316f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 4432952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define MWL8K_8366_AP_FW_API 1 4433952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" 4434952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) 4435952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo 4436bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linvillestatic struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { 44379e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek [MWL8363] = { 44389e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .part_name = "88w8363", 44399e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .helper_image = "mwl8k/helper_8363.fw", 44400863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8363.fw", 44419e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek }, 444249eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8687] = { 4443bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8687", 4444bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8687.fw", 44450863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8687.fw", 4446bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 444749eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8366] = { 4448bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8366", 4449bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8366.fw", 44500863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8366.fw", 4451952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API), 4452952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_api_ap = MWL8K_8366_AP_FW_API, 445389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .ap_rxd_ops = &rxd_8366_ap_ops, 4454bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 445545a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 445645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 4457c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8363.fw"); 4458c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); 4459c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8687.fw"); 4460c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); 4461c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8366.fw"); 4462c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); 4463952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian CavagnoloMODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); 4464c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert Buytenhek 446545a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstatic DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { 4466e5868ba10c3c5d8a56c06bbafe098103356ac03fBenjamin Larsson { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, 44679e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, 44689e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, 4469bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, 4470bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, 4471bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, 4472ca66527c60385dcec878ebd90749d1fdc43bc870Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, 4473bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { }, 447445a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 447545a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert BuytenhekMODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); 447645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 447799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_alt_fw(struct mwl8k_priv *priv) 447899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 447999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 448099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting preferred fw %s.\n" 448199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo "Trying alternative firmware %s\n", pci_name(priv->pdev), 448299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref, priv->fw_alt); 448399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true); 448499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 448599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 448699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), priv->fw_alt); 448799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 448899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 448999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return 0; 449099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 449199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 449299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv); 449399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context) 449499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 449599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_priv *priv = context; 449699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_device_info *di = priv->device_info; 449799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 449899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 449999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo switch (priv->fw_state) { 450099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_INIT: 450199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 450299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 450399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 450499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 450599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 450699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_helper = fw; 450799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode, 450899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 450999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc && priv->fw_alt) { 451099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 451199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 451299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 451399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 451499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (rc) 451599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 451699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 451799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 451899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 451999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 452099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_PREF: 452199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 452299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_alt) { 452399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 452499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 452599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 452699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 452799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 452899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 452999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else { 453099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 453199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 453299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 453399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 453499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 453599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 453699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 453799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 453899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 453999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_ALT: 454099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 454199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 454299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 454399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 454499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 454599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 454699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 454799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 454899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 454999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 455099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 455199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 455299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 455399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo default: 455499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n", 455599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo MWL8K_NAME, priv->fw_state); 455699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo BUG_ON(1); 455799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 455899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 455999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return; 456099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 456199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolofail: 456299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_ERROR; 456399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 456499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo device_release_driver(&priv->pdev->dev); 456599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 456699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 456799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 456899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, 456999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 4570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 45713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 4572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 4573be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4574be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reset firmware and hardware */ 4575be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 4576be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4577be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Ask userland hotplug daemon for the device firmware */ 457899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_firmware(priv, fw_image, nowait); 4579be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek if (rc) { 45805db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Firmware files not found\n"); 45813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 4582be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek } 4583be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 458499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 458599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 458699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 4587be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Load firmware into hardware */ 4588be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek rc = mwl8k_load_firmware(hw); 45893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 45905db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot start firmware\n"); 4591be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4592be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reclaim memory once firmware is successfully loaded */ 4593be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_release_firmware(priv); 4594be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 45953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 45963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 45973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 45983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* initialize hw after successfully loading a firmware image */ 45993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_probe_hw(struct ieee80211_hw *hw) 46003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 46013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 46023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc = 0; 46033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i; 4604be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 460591942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->ap_fw) { 460689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = priv->device_info->ap_rxd_ops; 460791942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->rxd_ops == NULL) { 4608c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 4609c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "Driver does not have AP firmware image support for this hardware\n"); 461091942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek goto err_stop_firmware; 461191942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 461291942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } else { 461389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = &rxd_sta_ops; 461491942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 4615be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4616be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->sniffer_enabled = false; 4617be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->wmm_enabled = false; 4618be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->pending_tx_pkts = 0; 4619be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_rxq_init(hw, 0); 4621a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 46223cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 4623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rxq_refill(hw, 0, INT_MAX); 4624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) { 4626a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_txq_init(hw, i); 4627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 4628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 4629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 4632c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 463367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, 46341e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); 4635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 4636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4637a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 4638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 4639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 46405db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 4641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 4642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Temporarily enable interrupts. Initial firmware host 4646c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek * commands use interrupts and avoid polling. Disable 4647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * interrupts when done. 4648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 4649c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Get config data, mac addrs etc */ 465242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (priv->ap_fw) { 465342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_ap(hw); 465442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) 465542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_set_hw_spec(hw); 465642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } else { 465742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_sta(hw); 465842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 4659a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 46605db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot initialise firmware\n"); 4661be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 4662a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Turn radio off */ 466555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_disable(hw); 4666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 46675db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot disable\n"); 4668be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 4669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 467132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek /* Clear MAC address */ 4672aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); 467332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (rc) { 46745db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot clear MAC address\n"); 4675be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 467632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek } 467732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 4678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 4679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 4681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4682c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", 4683c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->device_info->part_name, 4684c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->hw_rev, hw->wiphy->perm_addr, 4685c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->ap_fw ? "AP" : "STA", 4686c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, 4687c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); 4688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4689a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 4690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_irq: 4692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 4694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4695a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_queues: 4696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 4697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 4698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 4699a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 47003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_stop_firmware: 47013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_hw_reset(priv); 47023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 47043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 47053cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47063cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* 47073cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * invoke mwl8k_reload_firmware to change the firmware image after the device 47083cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * has already been registered 47093cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 47103cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) 47113cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 47123cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc = 0; 47133cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 47143cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47153cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_stop(hw); 47163cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 47173cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47183cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) 47193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 47203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 472199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, fw_image, false); 47223cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 47263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47283cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47293cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_start(hw); 47303cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47313cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47323cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47333cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_config(hw, ~0); 47343cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47353cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) { 47383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); 47393cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 47423cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47433cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 47443cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolofail: 47463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); 47473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 47483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 47493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv) 47513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 47523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw = priv->hw; 47533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc; 47543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 475599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_load_firmware(hw); 475699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 475799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 475899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wiphy_err(hw->wiphy, "Cannot start firmware\n"); 475999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 476099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 476199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 47623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 47633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * Extra headroom is the size of the required DMA header 47643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * minus the size of the smallest 802.11 frame (CTS frame). 47653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 47663cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->extra_tx_headroom = 47673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); 47683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->channel_change_time = 10; 47703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->queues = MWL8K_TX_QUEUES; 47723cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47733cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set rssi values to dBm */ 47740bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; 47753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->vif_data_size = sizeof(struct mwl8k_vif); 47763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->sta_data_size = sizeof(struct mwl8k_sta); 47773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->macids_used = 0; 47793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_LIST_HEAD(&priv->vif_list); 47803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set default radio state and preamble */ 47823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->radio_on = 0; 47833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->radio_short_preamble = 0; 47843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Finalize join worker */ 47863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); 47873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47883cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* TX reclaim and RX tasklets. */ 47893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); 47903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_tx_task); 47913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); 47923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_rx_task); 47933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Power management cookie */ 47953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); 47963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->cookie == NULL) 47973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return -ENOMEM; 47983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mutex_init(&priv->fw_mutex); 48003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_owner = NULL; 48013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_depth = 0; 48023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hostcmd_wait = NULL; 48033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo spin_lock_init(&priv->tx_lock); 48053cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48063cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->tx_wait = NULL; 48073cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48083cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 48093cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 48103cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_cookie; 48113cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48123cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes = 0; 48133cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->ap_macids_supported || priv->device_info->fw_image_ap) 48143cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); 48153cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sta_macids_supported || priv->device_info->fw_image_sta) 48163cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); 48173cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48183cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = ieee80211_register_hw(hw); 48193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 48203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot register device\n"); 48213cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_unprobe_hw; 48223cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return 0; 48253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_unprobe_hw: 48273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) 48283cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 48293cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 48303cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 4831be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_free_cookie: 4832a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->cookie != NULL) 4833a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 4, 4834a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->cookie, priv->cookie_dma); 4835a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 48363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 48373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 48383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int __devinit mwl8k_probe(struct pci_dev *pdev, 48393cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo const struct pci_device_id *id) 48403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 48413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo static int printed_version; 48423cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw; 48433cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv; 48440863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 48453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc; 48463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (!printed_version) { 48483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); 48493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printed_version = 1; 48503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_enable_device(pdev); 48543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 48553cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot enable new PCI device\n", 48563cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 48573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 48583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_request_regions(pdev, MWL8K_NAME); 48613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 48623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot obtain PCI resources\n", 48633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 48643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_disable_device; 48653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48663cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_master(pdev); 48683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); 48713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (hw == NULL) { 48723cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); 48733cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = -ENOMEM; 48743cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_reg; 48753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo SET_IEEE80211_DEV(hw, &pdev->dev); 48783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_drvdata(pdev, hw); 48793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv = hw->priv; 48813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hw = hw; 48823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->pdev = pdev; 48833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->device_info = &mwl8k_info_tbl[id->driver_data]; 48843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->sram = pci_iomap(pdev, 0, 0x10000); 48873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sram == NULL) { 48883cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); 48893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 48903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 48933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. 48943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. 48953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 48963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 1, 0x10000); 48973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 48983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 2, 0x10000); 48993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 49003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device registers\n"); 49013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 49023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49050863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 490699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * Choose the initial fw image depending on user input. If a second 490799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * image is available, make it the alternative image that will be 490899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * loaded if the first one fails. 49090863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 491099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo init_completion(&priv->firmware_loading_complete); 49110863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 491299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (ap_mode_default && di->fw_image_ap) { 491399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 491499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_sta; 491599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (!ap_mode_default && di->fw_image_sta) { 491699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 491799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_ap; 491899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { 49190863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); 492099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 49210863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { 49220863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); 492399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 492499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 492599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, priv->fw_pref, true); 49263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 49273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 492899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 49293cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 4930be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_stop_firmware: 4931be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 4932be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4933be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_iounmap: 4934a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->regs != NULL) 4935a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 4936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 49375b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek if (priv->sram != NULL) 49385b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 49395b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek 4940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 4941a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 4942a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4943a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_reg: 4944a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 49453db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhek 49463db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhekerr_disable_device: 4947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 4948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 4950a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4952230f7af0d8f6f2019e64920378b3b66e7d3e99a5Joerg Albertstatic void __devexit mwl8k_shutdown(struct pci_dev *pdev) 4953a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4954a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__); 4955a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4956a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4957230f7af0d8f6f2019e64920378b3b66e7d3e99a5Joerg Albertstatic void __devexit mwl8k_remove(struct pci_dev *pdev) 4958a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4959a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = pci_get_drvdata(pdev); 4960a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv; 4961a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 4962a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4963a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (hw == NULL) 4964a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 4965a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv = hw->priv; 4966a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 496799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wait_for_completion(&priv->firmware_loading_complete); 496899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 496999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_state == FW_STATE_ERROR) { 497099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_hw_reset(priv); 497199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto unmap; 497299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 497399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 4974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 4975a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 497660aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek ieee80211_unregister_hw(hw); 497760aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek 497867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Remove TX reclaim and RX tasklets. */ 49791e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_kill(&priv->poll_tx_task); 498067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_kill(&priv->poll_rx_task); 4981a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4982a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop hardware */ 4983a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_hw_reset(priv); 4984a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4985a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 4986a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 4987efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 4988a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4989a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 4990a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 4991a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4992a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 4993a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4994c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); 4995a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 499699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolounmap: 4997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 49985b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 4999a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 5000a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 5001a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 5002a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 5003a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5004a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5005a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic struct pci_driver mwl8k_driver = { 5006a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .name = MWL8K_NAME, 500745a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .id_table = mwl8k_pci_id_table, 5008a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .probe = mwl8k_probe, 5009a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .remove = __devexit_p(mwl8k_remove), 5010a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .shutdown = __devexit_p(mwl8k_shutdown), 5011a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 5012a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5013a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int __init mwl8k_init(void) 5014a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5015a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return pci_register_driver(&mwl8k_driver); 5016a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5017a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5018a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void __exit mwl8k_exit(void) 5019a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5020a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unregister_driver(&mwl8k_driver); 5021a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5023a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmodule_init(mwl8k_init); 5024a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmodule_exit(mwl8k_exit); 5025c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 5026c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_DESCRIPTION(MWL8K_DESC); 5027c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_VERSION(MWL8K_VERSION); 5028c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>"); 5029c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_LICENSE("GPL"); 5030