mwl8k.c revision 8a7a578c2e3ac463a17fe30b11ada0509658a952
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 898a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define MWL8K_MAX_AMPDU_QUEUES 8 90a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 9154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstruct rxd_ops { 9254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int rxd_size; 9354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); 9454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); 9520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status, 960d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise); 9754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 9854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 9945a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstruct mwl8k_device_info { 100a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *part_name; 101a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *helper_image; 1020863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_sta; 1030863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_ap; 10489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct rxd_ops *ap_rxd_ops; 105952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 fw_api_ap; 10645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 10745a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 108a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_rx_queue { 10945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int rxd_count; 110a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 111a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw receives here */ 11245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 113a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 114a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* refill descs here */ 11545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 116a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 11754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 11845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t rxd_dma; 119788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct { 120788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct sk_buff *skb; 12153b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori DEFINE_DMA_UNMAP_ADDR(dma); 122788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek } *buf; 123a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 124a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 125a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_queue { 126a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw transmits here */ 12745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 129a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* sw appends here */ 13045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 131a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1328ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo unsigned int len; 13345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct mwl8k_tx_desc *txd; 13445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t txd_dma; 13545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct sk_buff **skb; 136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 137a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 138a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_priv { 139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw; 140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct pci_dev *pdev; 141a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek struct mwl8k_device_info *device_info; 14345a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 144be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *sram; 145be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *regs; 146be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 147be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* firmware */ 148d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_helper; 149d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_ucode; 150a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 151be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* hardware/firmware parameters */ 152be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek bool ap_fw; 153be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek struct rxd_ops *rxd_ops; 154777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_supported_band band_24; 155777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_channel channels_24[14]; 156777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_rate rates_24[14]; 1574eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_supported_band band_50; 1584eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_channel channels_50[4]; 1594eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_rate rates_50[9]; 160ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 ap_macids_supported; 161ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 sta_macids_supported; 162be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 1638a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo /* Ampdu stream information */ 1648a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo u8 num_ampdu_queues; 1658a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo 166618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek /* firmware access */ 167618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mutex fw_mutex; 168618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct task_struct *fw_mutex_owner; 169618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int fw_mutex_depth; 170618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct completion *hostcmd_wait; 171618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 172a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* lock held over TX and TX reap */ 173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spinlock_t tx_lock; 174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 17588de754ad59025eba797e7a8375807755577f450Lennert Buytenhek /* TX quiesce completion, protected by fw_mutex and tx_lock */ 17688de754ad59025eba797e7a8375807755577f450Lennert Buytenhek struct completion *tx_wait; 17788de754ad59025eba797e7a8375807755577f450Lennert Buytenhek 178f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* List of interfaces. */ 179ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_used; 180f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head vif_list; 181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* power management status cookie from firmware */ 183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 *cookie; 184a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t cookie_dma; 185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 186a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u16 num_mcaddrs; 187a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 hw_rev; 1882aa7b01fe4f2d0978115bfd40364f52d86003606Lennert Buytenhek u32 fw_rev; 189a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Running count of TX packets in flight, to avoid 192a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * iterating over the transmit rings each time. 193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 194a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int pending_tx_pkts; 195a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 196a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; 1978a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; 1988a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo u32 txq_offset[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; 199a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 200c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek bool radio_on; 20168ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek bool radio_short_preamble; 202a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek bool sniffer_enabled; 2030439b1f55646ea944b0d58337f5065b79a1c1be0Lennert Buytenhek bool wmm_enabled; 204a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 205a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* XXX need to convert this to handle multiple interfaces */ 206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek bool capture_beacon; 207d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek u8 capture_bssid[ETH_ALEN]; 208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *beacon_skb; 209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This FJ worker has to be global as it is scheduled from the 212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * RX handler. At this point we don't know which interface it 213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * belongs to until the list of bssids waiting to complete join 214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * is checked. 215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct work_struct finalize_join_worker; 217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2181e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek /* Tasklet to perform TX reclaim. */ 2191e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct tasklet_struct poll_tx_task; 22067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 22167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Tasklet to perform RX. */ 22267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct tasklet_struct poll_rx_task; 2230d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 2240d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville /* Most recently reported noise in dBm */ 2250d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville s8 noise; 2260863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 2270863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 2280863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * preserve the queue configurations so they can be restored if/when 2290863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * the firmware image is swapped. 2300863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 2310863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; 23299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 23399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* async firmware loading state */ 23499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo unsigned fw_state; 23599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_pref; 23699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_alt; 23799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct completion firmware_loading_complete; 238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 240e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define MAX_WEP_KEY_LEN 13 241e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define NUM_WEP_KEYS 4 242e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Per interface specific private data */ 244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_vif { 245f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head list; 246f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif; 247f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 248f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek /* Firmware macid for this vif. */ 249f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek int macid; 250f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 251c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek /* Non AMPDU sequence number assigned by driver. */ 252a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u16 seqno; 253e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 254e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* Saved WEP keys */ 255e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct { 256e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 enabled; 257e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; 258e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } wep_key_conf[NUM_WEP_KEYS]; 259d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 260d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* BSSID */ 261d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 bssid[ETH_ALEN]; 262d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 263d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* A flag to indicate is HW crypto is enabled for this bssid */ 264d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam bool is_hw_crypto_enabled; 265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 266a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) 267fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) 268a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 269a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstruct mwl8k_sta { 270a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek /* Index into station database. Returned by UPDATE_STADB. */ 271a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u8 peer_id; 272a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek}; 273a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) 274a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 275777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_24[] = { 276a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2412, .hw_value = 1, }, 277a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2417, .hw_value = 2, }, 278a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2422, .hw_value = 3, }, 279a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2427, .hw_value = 4, }, 280a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2432, .hw_value = 5, }, 281a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2437, .hw_value = 6, }, 282a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2442, .hw_value = 7, }, 283a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2447, .hw_value = 8, }, 284a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2452, .hw_value = 9, }, 285a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2457, .hw_value = 10, }, 286a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2462, .hw_value = 11, }, 287647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2467, .hw_value = 12, }, 288647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2472, .hw_value = 13, }, 289647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2484, .hw_value = 14, }, 290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 292777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_24[] = { 293a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 10, .hw_value = 2, }, 294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 20, .hw_value = 4, }, 295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 55, .hw_value = 11, }, 2965dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 110, .hw_value = 22, }, 2975dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 220, .hw_value = 44, }, 298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 306140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 307140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek}; 308140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek 3094eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_50[] = { 3104eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5180, .hw_value = 36, }, 3114eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5200, .hw_value = 40, }, 3124eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5220, .hw_value = 44, }, 3134eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5240, .hw_value = 48, }, 3144eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3154eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 3164eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_50[] = { 3174eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 3184eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 3194eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 3204eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 3214eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 3224eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 3234eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 3244eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 3254eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 3264eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3274eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Set or get info from Firmware */ 329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET 0x0000 33041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET 0x0001 33141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET_LIST 0x0002 332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Firmware command codes */ 334a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_CODE_DNLD 0x0001 335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_HW_SPEC 0x0003 33642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek#define MWL8K_CMD_SET_HW_SPEC 0x0004 337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_STAT 0x0014 339ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RADIO_CONTROL 0x001c 340ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RF_TX_POWER 0x001e 34141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_TX_POWER 0x001f 34208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_CMD_RF_ANTENNA 0x0020 343aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ 344a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_PRE_SCAN 0x0107 345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_POST_SCAN 0x0108 346ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RF_CHANNEL 0x010a 347ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_AID 0x010d 348ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RATE 0x0110 349ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 350ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RTS_THRESHOLD 0x0113 351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_SLOT 0x0114 352ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 353ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_WMM_MODE 0x0123 354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MIMO_CONFIG 0x0125 355ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_USE_FIXED_RATE 0x0126 356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 357aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ 358a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 359aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ 360aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ 361fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ 362ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_UPDATE_STADB 0x1123 363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 364b603742f49c3ec922522602e18ac22e8f6835132John W. Linvillestatic const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) 365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 366b603742f49c3ec922522602e18ac22e8f6835132John W. Linville u16 command = le16_to_cpu(cmd); 367b603742f49c3ec922522602e18ac22e8f6835132John W. Linville 368a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMDNAME(x) case MWL8K_CMD_##x: do {\ 369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "%s", #x);\ 370a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf;\ 371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (0) 372b603742f49c3ec922522602e18ac22e8f6835132John W. Linville switch (command & ~0x8000) { 373a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(CODE_DNLD); 374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_HW_SPEC); 37542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek MWL8K_CMDNAME(SET_HW_SPEC); 376a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MAC_MULTICAST_ADR); 377a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_STAT); 378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RADIO_CONTROL); 379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RF_TX_POWER); 38041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam MWL8K_CMDNAME(TX_POWER); 38108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek MWL8K_CMDNAME(RF_ANTENNA); 382b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(SET_BEACON); 383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_PRE_SCAN); 384a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_POST_SCAN); 385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RF_CHANNEL); 386ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_AID); 387ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_RATE); 388ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_FINALIZE_JOIN); 389ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(RTS_THRESHOLD); 390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_SLOT); 391ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_EDCA_PARAMS); 392ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_WMM_MODE); 393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MIMO_CONFIG); 394ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(USE_FIXED_RATE); 395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(ENABLE_SNIFFER); 39632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek MWL8K_CMDNAME(SET_MAC_ADDR); 397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RATEADAPT_MODE); 398b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(BSS_START); 3993f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek MWL8K_CMDNAME(SET_NEW_STN); 400fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_CMDNAME(UPDATE_ENCRYPTION); 401ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(UPDATE_STADB); 402a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek default: 403a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "0x%x", cmd); 404a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#undef MWL8K_CMDNAME 406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf; 408a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Hardware and firmware reset */ 411a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_hw_reset(struct mwl8k_priv *priv) 412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 413a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 414a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 415a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 416a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msleep(20); 418a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Release fw image */ 421d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolostatic void mwl8k_release_fw(const struct firmware **fw) 422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw == NULL) 424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek release_firmware(*fw); 426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek *fw = NULL; 427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_release_firmware(struct mwl8k_priv *priv) 430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 43122be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_ucode); 43222be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo/* states for asynchronous f/w loading */ 43699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context); 43799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnoloenum { 43899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_INIT = 0, 43999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_PREF, 44099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_ALT, 44199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_ERROR, 44299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo}; 44399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 444a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Request fw image */ 445a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_request_fw(struct mwl8k_priv *priv, 446d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const char *fname, const struct firmware **fw, 44799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 449a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* release current image */ 450a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw != NULL) 451a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_release_fw(fw); 452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 45499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return request_firmware_nowait(THIS_MODULE, 1, fname, 45599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->pdev->dev, GFP_KERNEL, 45699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv, mwl8k_fw_state_machine); 45799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 458d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo return request_firmware(fw, fname, &priv->pdev->dev); 459a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 460a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 46199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, 46299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 463a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 464a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek struct mwl8k_device_info *di = priv->device_info; 465a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 466a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 467a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek if (di->helper_image != NULL) { 46899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 46999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 47099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, true); 47199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 47299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 47399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, false); 47499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 47599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 47699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 47799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 47899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc || nowait) 479a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek return rc; 480a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 481a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 48299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) { 48399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* 48499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * if we get here, no helper image is needed. Skip the 48599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * FW_STATE_INIT state. 48699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo */ 48799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 48899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 48999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, 49099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 49199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 49299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 49399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, false); 494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 495c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: Error requesting firmware file %s\n", 4960863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo pci_name(priv->pdev), fw_image); 49722be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 501a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 502a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 503a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_pkt { 505a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 code; 506a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 length; 507f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 seq_num; 508f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 macid; 509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 result; 510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek char payload[0]; 511ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 512a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware loading. 515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) 518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 519a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int loops; 522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 523a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); 524a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 530a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek loops = 1000; 535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 536a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 int_code; 537a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 538a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int_code = ioread32(regs + MWL8K_HIU_INT_CODE); 539a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { 540a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 541a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 543a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5443d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek cond_resched(); 545a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); 549a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 550d4b7057052236e81ab0788cc8df306dc02b0e7beLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 551a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_load_fw_image(struct mwl8k_priv *priv, 554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 556a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt *cmd; 557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int done; 558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc = 0; 559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kmalloc(sizeof(*cmd) + 256, GFP_KERNEL); 561a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 562a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); 565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->seq_num = 0; 566f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = 0; 567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->result = 0; 568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (length) { 571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int block_size = length > 256 ? 256 : length; 572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 573a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(cmd->payload, data + done, block_size); 574a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = cpu_to_le16(block_size); 575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, 577a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek sizeof(*cmd) + block_size); 578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 581a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += block_size; 582a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= block_size; 583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = 0; 587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, sizeof(*cmd)); 588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 594a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_feed_fw_image(struct mwl8k_priv *priv, 596a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 597a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned char *buffer; 599a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int may_continue, rc = 0; 600a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 done, prev_block_size; 601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek buffer = kmalloc(1024, GFP_KERNEL); 603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (buffer == NULL) 604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = 0; 608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue = 1000; 609a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (may_continue > 0) { 610a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 block_size; 611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 612a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size = ioread32(priv->regs + MWL8K_HIU_SCRATCH); 613a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size & 1) { 614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size &= ~1; 615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 616a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 617a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += prev_block_size; 618a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= prev_block_size; 619a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 621a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size > 1024 || block_size > length) { 622a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EOVERFLOW; 623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 626a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (length == 0) { 627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = 0; 628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size == 0) { 632a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EPROTO; 633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek continue; 636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = block_size; 639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(buffer, data + done, block_size); 640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, buffer, block_size); 642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc && length != 0) 647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EREMOTEIO; 648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(buffer); 650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 654c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhekstatic int mwl8k_load_firmware(struct ieee80211_hw *hw) 655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 656c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 657d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw = priv->fw_ucode; 658c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int rc; 659c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int loops; 660c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 661c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { 662d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *helper = priv->fw_helper; 663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 664c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (helper == NULL) { 665c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: helper image needed but none " 666c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "given\n", pci_name(priv->pdev)); 667c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek return -EINVAL; 668c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek } 669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 670c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, helper->data, helper->size); 671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware " 673c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "helper image\n", pci_name(priv->pdev)); 674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 67689b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek msleep(5); 677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 678c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); 679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 680c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, fw->data, fw->size); 681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 684c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware image\n", 685c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_name(priv->pdev)); 686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 68989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); 690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 69189b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek loops = 500000; 692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 693eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek u32 ready_code; 694eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 695eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); 696eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek if (ready_code == MWL8K_FWAP_READY) { 697eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek priv->ap_fw = 1; 698eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek break; 699eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } else if (ready_code == MWL8K_FWSTA_READY) { 700eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek priv->ap_fw = 0; 701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 702eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } 703eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 704eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek cond_resched(); 705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* DMA header used by firmware and hardware. */ 713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_dma_data { 714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 fwlen; 715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr wh; 71620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek char data[0]; 717ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Routines to add/remove DMA header from skb. */ 72020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhekstatic inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) 721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 72220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek struct mwl8k_dma_data *tr; 72320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int hdrlen; 72420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 72520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 72620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek hdrlen = ieee80211_hdrlen(tr->wh.frame_control); 72720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 72820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(tr->wh)) { 72920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (ieee80211_is_data_qos(tr->wh.frame_control)) { 73020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen - 2); 73120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *((__le16 *)(tr->data - 2)) = qos; 73220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } else { 73320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen); 73420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } 735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 73620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 73720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(*tr)) 73820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek skb_pull(skb, sizeof(*tr) - hdrlen); 739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 741252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadamstatic void 742252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadammwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) 743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 745ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek int hdrlen; 746252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam int reqd_hdrlen; 747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_dma_data *tr; 748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 749ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek /* 750ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * Add a firmware DMA header; the firmware requires that we 751ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * present a 2-byte payload length followed by a 4-address 752ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * header (without QoS field), followed (optionally) by any 753ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * WEP/ExtIV header (but only filled in for CCMP). 754ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek */ 755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 756ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek 757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek hdrlen = ieee80211_hdrlen(wh->frame_control); 758252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam reqd_hdrlen = sizeof(*tr); 759252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam 760252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam if (hdrlen != reqd_hdrlen) 761252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam skb_push(skb, reqd_hdrlen - hdrlen); 762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 763ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 764252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam hdrlen -= IEEE80211_QOS_CTL_LEN; 765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (wh != &tr->wh) 768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memmove(&tr->wh, wh, hdrlen); 769ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (hdrlen != sizeof(tr->wh)) 770ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek memset(((void *)&tr->wh) + hdrlen, 0, sizeof(tr->wh) - hdrlen); 771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware length is the length of the fully formed "802.11 774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * payload". That is, everything except for the 802.11 header. 775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This includes all crypto material including the MIC. 776a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 777252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); 778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 780e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadamstatic void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) 781e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam{ 782e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_hdr *wh; 783e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_tx_info *tx_info; 784e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_key_conf *key_conf; 785e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam int data_pad; 786e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 787e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam wh = (struct ieee80211_hdr *)skb->data; 788e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 789e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam tx_info = IEEE80211_SKB_CB(skb); 790e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 791e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = NULL; 792e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (ieee80211_is_data(wh->frame_control)) 793e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = tx_info->control.hw_key; 794e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 795e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* 796e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * Make sure the packet header is in the DMA header format (4-address 797e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * without QoS), the necessary crypto padding between the header and the 798e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * payload has already been provided by mac80211, but it doesn't add tail 799e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * padding when HW crypto is enabled. 800e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * 801e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * We have the following trailer padding requirements: 802e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - WEP: 4 trailer bytes (ICV) 803e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - TKIP: 12 trailer bytes (8 MIC + 4 ICV) 804e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - CCMP: 8 trailer bytes (MIC) 805e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam */ 806e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 0; 807e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (key_conf != NULL) { 808e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam switch (key_conf->cipher) { 809e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 810e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 811e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 4; 812e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 813e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 814e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 12; 815e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 816e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 817e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 8; 818e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 819e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 820e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 821e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam mwl8k_add_dma_header(skb, data_pad); 822e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 823a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 824a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 82589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for 88w8366 AP firmware. 8266f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek */ 82789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_8366_ap { 8286f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 pkt_len; 8296f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 sq2; 8306f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rate; 8316f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 pkt_phys_addr; 8326f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 next_rxd_phys_addr; 8336f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 qos_control; 8346f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 htsig2; 8356f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_rssi_info; 8366f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_noise_floor_info; 8376f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 noise_floor; 8386f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 pad0[3]; 8396f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rssi; 8406f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_status; 8416f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 channel; 8426f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_ctrl; 843ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 8446f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 84589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80 84689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40 84789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f) 8488e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek 84989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 8506f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 851d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* 8366 AP rx_status bits */ 852d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 853d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF 854d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 855d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 856d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 857d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 85889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) 8596f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 86089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8616f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8626f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 86389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST; 8646f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 8656f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 86689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) 8676f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 86889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8696f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8706f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 8716f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 8726f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek wmb(); 8736f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->rx_ctrl = 0; 8746f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 8756f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8766f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhekstatic int 87789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, 8780d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 8796f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 88089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 8816f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 88289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST)) 8836f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return -1; 8846f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rmb(); 8856f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8866f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 8876f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 8886f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->signal = -rxd->rssi; 8890d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_floor; 8906f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 89189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) { 8926f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 89389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ) 8948e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 89589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate); 8966f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } else { 8976f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek int i; 8986f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 899777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { 900777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek if (mwl8k_rates_24[i].hw_value == rxd->rate) { 9016f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->rate_idx = i; 9026f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek break; 9036f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9046f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9056f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9066f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 907854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 908854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 909854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 910854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 911854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 912854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 913854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 91459eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 91559eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 9166f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 91720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 91820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 919d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && 920d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && 921d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) 922d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 923d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 9246f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 9256f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9266f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 92789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_8366_ap_ops = { 92889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_8366_ap), 92989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_8366_ap_init, 93089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_8366_ap_refill, 93189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_8366_ap_process, 9326f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 9336f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9346f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek/* 93589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for STA firmware. 936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 93789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_sta { 938a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 939a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 link_quality; 940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 noise_level; 941a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 94245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_rxd_phys_addr; 943a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 944a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 945a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pad0[4]; 946a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rssi; 947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 channel; 948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pad1; 949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_ctrl; 950a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_status; 951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 pad2[2]; 952ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 953a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 95489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000 95589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) 95689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) 95789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_40MHZ 0x0004 95889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002 95989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 96054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 96189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 962d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 963d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* ICV=0 or MIC=1 */ 964d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 965d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* Key is uploaded only in failure case */ 966d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 96754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 96889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) 96954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 97089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 97154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 97254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 97389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST; 97454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 97554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 97689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) 97754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 97889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 97954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 98054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 98154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 98254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek wmb(); 98354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->rx_ctrl = 0; 98454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 98554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 98654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic int 98789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, 9880d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 98954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 99089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 99154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek u16 rate_info; 99254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST)) 99454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return -1; 99554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rmb(); 99654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rate_info = le16_to_cpu(rxd->rate_info); 99854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 99954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 100054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 100154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->signal = -rxd->rssi; 10020d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_level; 100389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info); 100489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); 100554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 100689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) 100754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORTPRE; 100889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) 100954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 101089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) 101154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORT_GI; 101289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) 101354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 101454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1015854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 1016854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 1017854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 1018854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 1019854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 1020854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 1021854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 102259eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 102359eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 102454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 102520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 1026d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && 1027d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) 1028d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 102920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 103054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 103154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 103254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 103389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_sta_ops = { 103489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_sta), 103589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_sta_init, 103689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_sta_refill, 103789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_sta_process, 103854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 103954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 104054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1041a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_DESCS 256 1042a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_MAXSZ 3800 1043a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1044a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) 1045a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1046a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1047a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1048a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1049a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1050a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 105145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count = 0; 105245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->head = 0; 105345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->tail = 0; 1054a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 105554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size; 1056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 105745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); 105845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (rxq->rxd == NULL) { 10595db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX descriptors\n"); 1060a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1061a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 106245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(rxq->rxd, 0, size); 1063a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1064b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL); 1065788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf == NULL) { 10665db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); 106745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); 1068a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1069a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1070a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1071a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 107254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int desc_size; 107354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1074a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 107554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dma_addr_t next_dma_addr; 107654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 107754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek desc_size = priv->rxd_ops->rxd_size; 107854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size); 1079a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 108054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = i + 1; 108154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (nexti == MWL8K_RX_DESCS) 108254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = 0; 108354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek next_dma_addr = rxq->rxd_dma + (nexti * desc_size); 1084a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 108554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_init(rxd, next_dma_addr); 1086a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1088a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1089a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1090a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1091a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_refill(struct ieee80211_hw *hw, int index, int limit) 1092a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1093a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1094a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1095a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int refilled; 1096a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1097a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled = 0; 109845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { 1099a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1100788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek dma_addr_t addr; 1101a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rx; 110254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1104a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb = dev_alloc_skb(MWL8K_RX_MAXSZ); 1105a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (skb == NULL) 1106a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1107a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1108788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek addr = pci_map_single(priv->pdev, skb->data, 1109788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); 1110a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 111154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->rxd_count++; 111254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rx = rxq->tail++; 111354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->tail == MWL8K_RX_DESCS) 111454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->tail = 0; 1115788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rx].skb = skb; 111653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rx], dma, addr); 111754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 111854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size); 111954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ); 1120a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1121a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled++; 1122a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1123a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1124a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return refilled; 1125a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1126a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1127a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Must be called only when the card's reception is completely halted */ 1128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) 1129a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1130a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1131a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1132a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1133a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 113473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (rxq->rxd == NULL) 113573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return; 113673b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 1137a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 1138788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf[i].skb != NULL) { 1139788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 114053b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[i], dma), 1141788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 114253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[i], dma, 0); 1143788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1144788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree_skb(rxq->buf[i].skb); 1145788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[i].skb = NULL; 1146a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1147a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1148a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1149788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree(rxq->buf); 1150788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf = NULL; 1151a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1152a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 115354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek MWL8K_RX_DESCS * priv->rxd_ops->rxd_size, 115445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd, rxq->rxd_dma); 115545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = NULL; 1156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1157a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1158a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1159a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1160a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Scan a list of BSSIDs to process for finalize join. 1161a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Allows for extension to process multiple BSSIDs. 1162a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1163a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline int 1164a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) 1165a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1166a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return priv->capture_beacon && 1167a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_is_beacon(wh->frame_control) && 1168a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek !compare_ether_addr(wh->addr3, priv->capture_bssid); 1169a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1170a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 11713779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhekstatic inline void mwl8k_save_beacon(struct ieee80211_hw *hw, 11723779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct sk_buff *skb) 1173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 11743779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 11753779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek 1176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = false; 1177d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memset(priv->capture_bssid, 0, ETH_ALEN); 1178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Use GFP_ATOMIC as rxq_process is called from 1181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * the primary interrupt handler, memory allocation call 1182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * must not sleep. 1183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1184a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); 1185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 11863779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek ieee80211_queue_work(hw, &priv->finalize_join_worker); 1187a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1188a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1189d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, 1190d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 *bssid) 1191d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 1192d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif; 1193d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1194d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_for_each_entry(mwl8k_vif, 1195d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam vif_list, list) { 1196d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (memcmp(bssid, mwl8k_vif->bssid, 1197d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ETH_ALEN) == 0) 1198d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return mwl8k_vif; 1199d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1200d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1201d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return NULL; 1202d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1203d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1204a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_process(struct ieee80211_hw *hw, int index, int limit) 1205a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1207d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif = NULL; 1208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int processed; 1210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed = 0; 121245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count && limit--) { 1213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 121454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 121554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int pkt_len; 1216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_rx_status status; 1217d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct ieee80211_hdr *wh; 121820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek __le16 qos; 1219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1220788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek skb = rxq->buf[rxq->head].skb; 1221d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek if (skb == NULL) 1222d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek break; 122354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 122454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); 122554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 12260d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos, 12270d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville &priv->noise); 122854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (pkt_len < 0) 122954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek break; 123054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1231788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rxq->head].skb = NULL; 1232788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1233788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 123453b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[rxq->head], dma), 1235788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 123653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); 1237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 123854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head++; 123954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->head == MWL8K_RX_DESCS) 124054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head = 0; 124154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 124245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count--; 1243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1244d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1247c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * Check for a pending join operation. Save a 1248c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * copy of the beacon and schedule a tasklet to 1249c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * send a FINALIZE_JOIN command to the firmware. 1250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 125154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (mwl8k_capture_bssid(priv, (void *)skb->data)) 12523779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek mwl8k_save_beacon(hw, skb); 1253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1254d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (ieee80211_has_protected(wh->frame_control)) { 1255d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1256d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* Check if hw crypto has been enabled for 1257d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * this bss. If yes, set the status flags 1258d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * accordingly 1259d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1260d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, 1261d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh->addr1); 1262d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1263d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif != NULL && 1264d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled == true) { 1265d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* 1266d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * When MMIC ERROR is encountered 1267d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * by the firmware, payload is 1268d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * dropped and only 32 bytes of 1269d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * mwl8k Firmware header is sent 1270d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * to the host. 1271d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 1272d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * We need to add four bytes of 1273d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * key information. In it 1274d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * MAC80211 expects keyidx set to 1275d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 0 for triggering Counter 1276d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * Measure of MMIC failure. 1277d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1278d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (status.flag & RX_FLAG_MMIC_ERROR) { 1279d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_dma_data *tr; 1280d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam tr = (struct mwl8k_dma_data *)skb->data; 1281d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memset((void *)&(tr->data), 0, 4); 1282d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam pkt_len += 4; 1283d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1284d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1285d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (!ieee80211_is_auth(wh->frame_control)) 1286d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status.flag |= RX_FLAG_IV_STRIPPED | 1287d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_DECRYPTED | 1288d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_MMIC_STRIPPED; 1289d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1290d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1291d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1292d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam skb_put(skb, pkt_len); 1293d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_remove_dma_header(skb, qos); 1294f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 1295f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg ieee80211_rx_irqsafe(hw, skb); 1296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed++; 1298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return processed; 1301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Packet transmission. 1306a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1307a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1308a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK 0x00000001 1309a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 1310a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 1311a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 1312a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 1313a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1314e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_QLEN_UNSPEC 0xff00 1315e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_MASK 0x0060 1316e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000 1317e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060 1318e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_EOSP 0x0010 1319e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek 1320a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_desc { 1321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 status; 1322a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 data_rate; 1323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 tx_priority; 1324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 1325a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 1326a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 1327d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 dest_MAC_addr[ETH_ALEN]; 132845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_txd_phys_addr; 13298a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 timestamp; 1330a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 1331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 peer_id; 1332a1fe24b0fd8bf16b4e551ae3fb785bfc574b9ffbBrian Cavagnolo __u8 tx_frag_cnt; 1333ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1334a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TX_DESCS 128 1336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_txq_init(struct ieee80211_hw *hw, int index) 1338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1342a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1343a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 13448ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len = 0; 134545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = 0; 134645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 1347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1348a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); 1349a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 135045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); 135145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->txd == NULL) { 13525db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX descriptors\n"); 1353a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 135545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(txq->txd, 0, size); 1356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1357b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL); 135845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->skb == NULL) { 13595db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); 136045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); 1361a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_DESCS; i++) { 1365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1366a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 1367a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 136845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + i; 1369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek nexti = (i + 1) % MWL8K_TX_DESCS; 1370a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status = 0; 137245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc->next_txd_phys_addr = 137345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc)); 1374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1375a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1376a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1377a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline void mwl8k_tx_start(struct mwl8k_priv *priv) 1380a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1381a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_PPA_READY, 1382a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 1384a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ioread32(priv->regs + MWL8K_HIU_INT_CODE); 1386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 13887e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekstatic void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) 1389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 13907e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 13917e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int i; 13927e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 13937e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) { 13947e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + i; 13957e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int fw_owned = 0; 13967e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int drv_owned = 0; 13977e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int unused = 0; 13987e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int desc; 13997e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1400a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { 14017e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_desc *tx_desc = txq->txd + desc; 14027e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek u32 status; 1403a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14047e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek status = le32_to_cpu(tx_desc->status); 1405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) 14067e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek fw_owned++; 1407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek else 14087e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek drv_owned++; 1409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_desc->pkt_len == 0) 14117e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unused++; 1412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1413a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1414c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 1415c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "txq[%d] len=%d head=%d tail=%d " 1416c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "fw_owned=%d drv_owned=%d unused=%d\n", 1417c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches i, 1418c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches txq->len, txq->head, txq->tail, 1419c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches fw_owned, drv_owned, unused); 14207e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 1421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1423618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 142488de754ad59025eba797e7a8375807755577f450Lennert Buytenhek * Must be called with priv->fw_mutex held and tx queues stopped. 1425618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 142662abd3cfb2f1a0ab1963ac4c4087c477da6b1f2aLennert Buytenhek#define MWL8K_TX_WAIT_TIMEOUT_MS 5000 14277e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1428950d5b0191dc3e71017f336017f75f6189f39f08Lennert Buytenhekstatic int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 143188de754ad59025eba797e7a8375807755577f450Lennert Buytenhek DECLARE_COMPLETION_ONSTACK(tx_wait); 14327e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int retry; 14337e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int rc; 1434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek might_sleep(); 1436a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14377e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek /* 14387e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * The TX queues are stopped at this point, so this test 14397e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * doesn't need to take ->tx_lock. 14407e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek */ 14417e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (!priv->pending_tx_pkts) 14427e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return 0; 14437e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14447e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 0; 14457e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = 0; 14467e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 14487e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek priv->tx_wait = &tx_wait; 14497e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek while (!rc) { 14507e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int oldcount; 14517e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unsigned long timeout; 1452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14537e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek oldcount = priv->pending_tx_pkts; 1454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14557e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 145688de754ad59025eba797e7a8375807755577f450Lennert Buytenhek timeout = wait_for_completion_timeout(&tx_wait, 14577e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS)); 1458a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 14597e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14607e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (timeout) { 14617e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek WARN_ON(priv->pending_tx_pkts); 14627e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (retry) { 1463c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, "tx rings drained\n"); 14647e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14657e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek break; 14667e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14677e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14687e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (priv->pending_tx_pkts < oldcount) { 1469c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, 1470c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "waiting for tx rings to drain (%d -> %d pkts)\n", 1471c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches oldcount, priv->pending_tx_pkts); 14727e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 1; 14737e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek continue; 14747e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 14757e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->tx_wait = NULL; 1477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1478c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n", 1479c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_TX_WAIT_TIMEOUT_MS); 14807e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek mwl8k_dump_tx_rings(hw); 14817e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 14827e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = -ETIMEDOUT; 1483a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 14847e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 1485a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14867e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return rc; 1487a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1488a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1489c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek#define MWL8K_TXD_SUCCESS(status) \ 1490c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek ((status) & (MWL8K_TXD_STATUS_OK | \ 1491c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_RETRY | \ 1492c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_MORE_RETRY)) 1493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1494efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekstatic int 1495efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekmwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) 1496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1497a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1499efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek int processed; 1500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1501efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed = 0; 15028ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo while (txq->len > 0 && limit--) { 1503a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int tx; 1504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1505a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long addr; 1506ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek int size; 1507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1508a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *info; 1509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 1510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 151145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->head; 151245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + tx; 1513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = le32_to_cpu(tx_desc->status); 1515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) { 1517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!force) 1518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1519a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status &= 1520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); 1521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 152345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = (tx + 1) % MWL8K_TX_DESCS; 15248ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo BUG_ON(txq->len == 0); 15258ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len--; 1526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts--; 1527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek addr = le32_to_cpu(tx_desc->pkt_phys_addr); 1529ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek size = le16_to_cpu(tx_desc->pkt_len); 153045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek skb = txq->skb[tx]; 153145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[tx] = NULL; 1532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek BUG_ON(skb == NULL); 1534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); 1535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 153620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek mwl8k_remove_dma_header(skb, tx_desc->qos_control); 1537a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1538a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Mark descriptor as unused */ 1539a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_phys_addr = 0; 1540a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_len = 0; 1541a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = IEEE80211_SKB_CB(skb); 1543a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_info_clear_status(info); 15440bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 15450bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam /* Rate control is happening in the firmware. 15460bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam * Ensure no tx rate is being reported. 15470bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam */ 15480bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam info->status.rates[0].idx = -1; 15490bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam info->status.rates[0].count = 1; 15500bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 1551ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek if (MWL8K_TXD_SUCCESS(status)) 1552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->flags |= IEEE80211_TX_STAT_ACK; 1553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_status_irqsafe(hw, skb); 1555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1556efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed++; 1557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1559efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) 1560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_wake_queue(hw, index); 1561efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek 1562efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek return processed; 1563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* must be called only when the card's transmit is completely halted */ 1566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) 1567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 157173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (txq->txd == NULL) 157273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return; 157373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 1574efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, index, INT_MAX, 1); 1575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 157645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek kfree(txq->skb); 157745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb = NULL; 1578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 1580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), 158145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd, txq->txd_dma); 158245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = NULL; 1583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 15857bb4568372856688bc070917265bce0b88bb7d4dJohannes Bergstatic void 1586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) 1587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *tx_info; 159023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek struct mwl8k_vif *mwl8k_vif; 1591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 1592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq; 1593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx; 1594a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma; 159523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u32 txstatus; 159623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u8 txdatarate; 159723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u16 qos; 1598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 159923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 160023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 160123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); 160223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 160323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = 0; 1604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1605d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (priv->ap_fw) 1606d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_encapsulate_tx_frame(skb); 1607d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam else 1608d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_add_dma_header(skb, 0); 1609d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 161023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1612a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_info = IEEE80211_SKB_CB(skb); 1613a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif = MWL8K_VIF(tx_info->control.vif); 1614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 1616a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 1617657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); 1618657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek mwl8k_vif->seqno += 0x10; 1619a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 162123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek /* Setup firmware control bit fields for each frame type. */ 162223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus = 0; 162323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 162423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_mgmt(wh->frame_control) || 162523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek ieee80211_is_ctl(wh->frame_control)) { 162623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 1627e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP; 162823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } else if (ieee80211_is_data(wh->frame_control)) { 162923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 1; 163023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (is_multicast_ether_addr(wh->addr1)) 163123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; 163223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 1633e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos &= ~MWL8K_QOS_ACK_POLICY_MASK; 163423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) 1635e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK; 163623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 1637e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_NORMAL; 163823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } 1639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma = pci_map_single(priv->pdev, skb->data, 1641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb->len, PCI_DMA_TODEVICE); 1642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma)) { 1644c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 1645c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "failed to dma map skb, dropping TX frame.\n"); 164623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek dev_kfree_skb(skb); 16477bb4568372856688bc070917265bce0b88bb7d4dJohannes Berg return; 1648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 165023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek spin_lock_bh(&priv->tx_lock); 1651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 165223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txq = priv->txq + index; 1653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 165445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek BUG_ON(txq->skb[txq->tail] != NULL); 165545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[txq->tail] = skb; 1656a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 165745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->txd + txq->tail; 165823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->data_rate = txdatarate; 165923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->tx_priority = index; 1660a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->qos_control = cpu_to_le16(qos); 1661a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_phys_addr = cpu_to_le32(dma); 1662a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_len = cpu_to_le16(skb->len); 166323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->rate_info = 0; 1664a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek if (!priv->ap_fw && tx_info->control.sta != NULL) 1665a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; 1666a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek else 1667a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek tx->peer_id = 0; 1668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wmb(); 166923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); 167023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 16718ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len++; 1672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts++; 1673a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 167445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail++; 167545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->tail == MWL8K_TX_DESCS) 167645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 167723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 167845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->head == txq->tail) 1679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queue(hw, index); 1680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 168123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek mwl8k_tx_start(priv); 1682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 1684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1688618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * Firmware access. 1689618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 1690618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * We have the following requirements for issuing firmware commands: 1691618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - Some commands require that the packet transmit path is idle when 1692618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the command is issued. (For simplicity, we'll just quiesce the 1693618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * transmit path for every command.) 1694618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - There are certain sequences of commands that need to be issued to 1695618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the hardware sequentially, with no other intervening commands. 1696618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 1697618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * This leads to an implementation of a "firmware lock" as a mutex that 1698618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * can be taken recursively, and which is taken by both the low-level 1699618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * command submission function (mwl8k_post_cmd) as well as any users of 1700618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * that function that require issuing of an atomic sequence of commands, 1701618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * and quiesces the transmit path whenever it's taken. 1702618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 1703618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic int mwl8k_fw_lock(struct ieee80211_hw *hw) 1704618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 1705618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1706618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1707618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->fw_mutex_owner != current) { 1708618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int rc; 1709618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1710618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_lock(&priv->fw_mutex); 1711618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_stop_queues(hw); 1712618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1713618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek rc = mwl8k_tx_wait_empty(hw); 1714618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (rc) { 1715618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_wake_queues(hw); 1716618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 1717618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1718618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return rc; 1719618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1720618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1721618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = current; 1722618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1723618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1724618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_depth++; 1725618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1726618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return 0; 1727618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 1728618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1729618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic void mwl8k_fw_unlock(struct ieee80211_hw *hw) 1730618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 1731618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1732618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1733618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!--priv->fw_mutex_depth) { 1734618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_wake_queues(hw); 1735618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = NULL; 1736618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 1737618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 1738618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 1739618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1740618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1741618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 1742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Command processing. 1743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 17450c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek/* Timeout firmware commands after 10s */ 17460c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek#define MWL8K_CMD_TIMEOUT_MS 10000 1747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) 1749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek DECLARE_COMPLETION_ONSTACK(cmd_wait); 1751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 1753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 1754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned int dma_size; 1755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 1756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long timeout = 0; 1757a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 buf[32]; 1758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1759b603742f49c3ec922522602e18ac22e8f6835132John W. Linville cmd->result = (__force __le16) 0xffff; 1760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_size = le16_to_cpu(cmd->length); 1761a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, cmd, dma_size, 1762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek PCI_DMA_BIDIRECTIONAL); 1763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 1764a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1766618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek rc = mwl8k_fw_lock(hw); 176739a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek if (rc) { 176839a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, dma_size, 176939a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek PCI_DMA_BIDIRECTIONAL); 1770618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return rc; 177139a1e42eb4d0a2bc3f1211e9012bd23734ab86dbLennert Buytenhek } 1772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hostcmd_wait = &cmd_wait; 1774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 1775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 1776a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 1778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek timeout = wait_for_completion_timeout(&cmd_wait, 1781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); 1782a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1783618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->hostcmd_wait = NULL; 1784618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 1785618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mwl8k_fw_unlock(hw); 1786618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 178737055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, dma_size, 178837055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek PCI_DMA_BIDIRECTIONAL); 178937055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek 1790a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!timeout) { 17915db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", 1792c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 1793c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_CMD_TIMEOUT_MS); 1794a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -ETIMEDOUT; 1795a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 17960c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek int ms; 17970c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 17980c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(timeout); 17990c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 1800ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek rc = cmd->result ? -EINVAL : 0; 1801a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 18025db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s error 0x%x\n", 1803c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 1804c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches le16_to_cpu(cmd->result)); 18050c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek else if (ms > 2000) 18065db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_notice(hw->wiphy, "Command %s took %d ms\n", 1807c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, 1808c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches buf, sizeof(buf)), 1809c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches ms); 1810a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1811a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1812a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 1813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1814a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1815f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhekstatic int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, 1816f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct ieee80211_vif *vif, 1817f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct mwl8k_cmd_pkt *cmd) 1818f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek{ 1819f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek if (vif != NULL) 1820f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = MWL8K_VIF(vif)->macid; 1821f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek return mwl8k_post_cmd(hw, cmd); 1822f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek} 1823f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 1824a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 18251349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek * Setup code shared between STA and AP firmware images. 18261349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek */ 18271349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhekstatic void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) 18281349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek{ 18291349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 18301349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18311349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); 18321349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); 18331349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18341349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); 18351349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); 18361349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18371349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.band = IEEE80211_BAND_2GHZ; 18381349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.channels = priv->channels_24; 18391349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); 18401349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.bitrates = priv->rates_24; 18411349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); 18421349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18431349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; 18441349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek} 18451349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 18464eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) 18474eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek{ 18484eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 18494eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18504eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); 18514eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); 18524eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18534eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); 18544eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); 18554eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18564eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.band = IEEE80211_BAND_5GHZ; 18574eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.channels = priv->channels_50; 18584eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); 18594eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.bitrates = priv->rates_50; 18604eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); 18614eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18624eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; 18634eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek} 18644eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 18651349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek/* 186604b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek * CMD_GET_HW_SPEC (STA version). 1867a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 186804b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_sta { 1869a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 1870a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 hw_rev; 1871a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 host_interface; 1872a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 num_mcaddrs; 1873d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 1874a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 region_code; 1875a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 fw_rev; 1876a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 ps_cookie; 1877a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps; 1878a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 mcs_bitmap[16]; 1879a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 rx_queue_ptr; 1880a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_queues; 1881a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; 1882a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps2; 1883a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_desc_per_queue; 188445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 total_rxd; 1885ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1886a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1887341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MAX_AMSDU 0x20000000 1888341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_GREENFIELD 0x08000000 1889341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_AMPDU 0x04000000 1890341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_STBC 0x01000000 1891341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_STBC 0x00800000 1892341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 1893341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 1894341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 1895341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 1896341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_DELAY_BA 0x00003000 1897341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MIMO 0x00000200 1898341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_40MHZ 0x00000100 189906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_BAND_MASK 0x00000007 190006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_5GHZ 0x00000004 190106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_2GHZ4 0x00000001 1902341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 190306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 190406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_ht_caps(struct ieee80211_hw *hw, 190506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct ieee80211_supported_band *band, u32 cap) 1906341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek{ 1907341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int rx_streams; 1908341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int tx_streams; 1909341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1910777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ht_supported = 1; 1911341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1912341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_MAX_AMSDU) 1913777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; 1914341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_GREENFIELD) 1915777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; 1916341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_AMPDU) { 1917341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; 1918777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 1919777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 1920341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 1921341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_RX_STBC) 1922777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; 1923341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_TX_STBC) 1924777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; 1925341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_40MHZ) 1926777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; 1927341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_20MHZ) 1928777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; 1929341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_DELAY_BA) 1930777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; 1931341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_40MHZ) 1932777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 1933341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1934341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); 1935341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); 1936341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1937777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[0] = 0xff; 1938341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 2) 1939777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[1] = 0xff; 1940341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 3) 1941777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[2] = 0xff; 1942777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[4] = 0x01; 1943777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 1944341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 1945341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams != tx_streams) { 1946777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 1947777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= (tx_streams - 1) << 1948341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 1949341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 1950341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek} 1951341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 195206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 195306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) 195406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek{ 195506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 195606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 195706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { 195806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_2ghz_band(hw); 195906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 196006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_24, caps); 196106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 196206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 196306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_5GHZ) { 196406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_5ghz_band(hw); 196506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 196606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_50, caps); 196706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 196806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek} 196906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 197004b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) 1971a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1972a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 197304b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_sta *cmd; 1974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 1975a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1976a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1977a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 1979a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1980a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1981a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 1982a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 1983a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1984a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 1985a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 198645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 19874ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); 1988a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 198945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); 19904ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 199145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 1992a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1993a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 1994a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1995a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 1996a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 1997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 19984ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 1999a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hw_rev = cmd->hw_rev; 200006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); 2001ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x00000000; 2002ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->sta_macids_supported = 0x00000001; 2003a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2004a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2005a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2006a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2007a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2008a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2009a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 201042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_GET_HW_SPEC (AP version). 201142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 201242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_ap { 201342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 201442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 201542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 201642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_wcb; 201742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 201842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 201942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 202042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_antenna; 202142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 202242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase0; 202342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxwrptr; 202442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxrdptr; 202542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 202642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase1; 202742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase2; 202842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase3; 2029952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo __le32 fw_api_version; 20308a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 caps; 20318a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 num_of_ampdu_queues; 20328a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; 2033ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 203442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 203542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) 203642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 203742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 203842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_ap *cmd; 20398a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo int rc, i; 2040952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 api_version; 204142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 204242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 204342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 204442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 204542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 204642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 204742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 204842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 204942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 205042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 205142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 205242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 205342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 205442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) { 205542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int off; 205642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2057952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version = le32_to_cpu(cmd->fw_api_version); 2058952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo if (priv->device_info->fw_api_ap != api_version) { 2059952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo printk(KERN_ERR "%s: Unsupported fw API version for %s." 2060952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo " Expected %d got %d.\n", MWL8K_NAME, 2061952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->part_name, 2062952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->fw_api_ap, 2063952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version); 2064952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo rc = -EINVAL; 2065952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo goto done; 2066952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo } 206742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 206842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 206942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 207042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->hw_rev = cmd->hw_rev; 20718a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); 2072ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x000000ff; 2073ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->sta_macids_supported = 0x00000000; 20748a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); 20758a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { 20768a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" 20778a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo " but we only support %d.\n", 20788a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues, 20798a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo MWL8K_MAX_AMPDU_QUEUES); 20808a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; 20818a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo } 208242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxwrptr) & 0xffff; 2083b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 208442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 208542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxrdptr) & 0xffff; 2086b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 208742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 208873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; 208973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; 209073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; 209173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; 20928a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo 20938a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo for (i = 0; i < priv->num_ampdu_queues; i++) 20948a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->txq_offset[i + MWL8K_TX_QUEUES] = 20958a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; 209642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 209742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2098952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolodone: 209942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 210042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 210142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 210242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 210342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 210442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_SET_HW_SPEC. 210542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 210642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_set_hw_spec { 210742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 210842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 210942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 211042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 211142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 211242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 211342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 211442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 211542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 caps; 211642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rx_queue_ptr; 211742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_queues; 211842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; 211942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 flags; 212042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_desc_per_queue; 212142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 total_rxd; 2122ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 212342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 21248a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause 21258a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * packets to expire 500 ms after the timestamp in the tx descriptor. That is, 21268a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * the packets that are queued for more than 500ms, will be dropped in the 21278a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * hardware. This helps minimizing the issues caused due to head-of-line 21288a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * blocking where a slow client can hog the bandwidth and affect traffic to a 21298a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * faster client. 21308a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo */ 21318a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 2132b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 2133b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 2134b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 213542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 213642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) 213742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 213842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 213942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_set_hw_spec *cmd; 214042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int rc; 214142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int i; 214242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 214342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 214442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 214542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 214642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 214742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC); 214842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 214942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 215042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 215142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 215242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); 215385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam 215485c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam /* 215585c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * Mac80211 stack has Q0 as highest priority and Q3 as lowest in 215685c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * that order. Firmware has Q3 as highest priority and Q0 as lowest 215785c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * in that order. Map Q3 of mac80211 to Q0 of firmware so that the 215885c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * priority is interpreted the right way in firmware. 215985c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam */ 216085c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam for (i = 0; i < MWL8K_TX_QUEUES; i++) { 216185c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam int j = MWL8K_TX_QUEUES - 1 - i; 216285c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); 216385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam } 216485c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam 2165b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | 2166b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | 2167b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); 216842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 216942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 217042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 217142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 217242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 217342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 217442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 217542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 217642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 217742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 2178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_MAC_MULTICAST_ADR. 2179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_mac_multicast_adr { 2181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 numaddr; 2184ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek __u8 addr[0][ETH_ALEN]; 2185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 2186a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2187d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_DIRECTED 0x0001 2188d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_MULTICAST 0x0002 2189d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 2190d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_BROADCAST 0x0008 2191ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2192e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic struct mwl8k_cmd_pkt * 2193447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, 219422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 2195a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2196e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2197a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_mac_multicast_adr *cmd; 2198e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek int size; 219922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int mc_count = 0; 220022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko 220122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko if (mc_list) 220222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko mc_count = netdev_hw_addr_list_count(mc_list); 2203e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2204447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (allmulti || mc_count > priv->num_mcaddrs) { 2205d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek allmulti = 1; 2206d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek mc_count = 0; 2207d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } 2208e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2209e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek size = sizeof(*cmd) + mc_count * ETH_ALEN; 2210ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2211e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek cmd = kzalloc(size, GFP_ATOMIC); 2212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2213e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return NULL; 2214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); 2216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(size); 2217d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED | 2218d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek MWL8K_ENABLE_RX_BROADCAST); 2219d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2220d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek if (allmulti) { 2221d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST); 2222d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } else if (mc_count) { 222322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 222422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int i = 0; 2225d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2226d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); 2227d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->numaddr = cpu_to_le16(mc_count); 222822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_hw_addr_list_for_each(ha, mc_list) { 222922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko memcpy(cmd->addr[i], ha->addr, ETH_ALEN); 2230a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2231a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2233e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return &cmd->header; 2234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2235a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2236a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 223755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_GET_STAT. 2238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 223955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_get_stat { 2240a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2241a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 stats[64]; 2242ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_ACK_FAILURE 9 2245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_FAILURE 12 2246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_FCS_ERROR 24 2247a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_SUCCESS 11 2248a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 224955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, 225055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_low_level_stats *stats) 2251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 225255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_get_stat *cmd; 2253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2257a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2258a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); 2260a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 2264a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11ACKFailureCount = 2265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]); 2266a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSFailureCount = 2267a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]); 2268a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11FCSErrorCount = 2269a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]); 2270a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSSuccessCount = 2271a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]); 2272a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2275a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2276a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2277a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2278a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 227955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RADIO_CONTROL. 2280a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 228155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_radio_control { 2282a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2283a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2284a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 control; 2285a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 radio_on; 2286ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2287a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2288c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhekstatic int 228955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) 2290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 229255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_radio_control *cmd; 2293a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2295c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek if (enable == priv->radio_on && !force) 2296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 2297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); 2303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 230568ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); 2306a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); 2307a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2308a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2309a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2310a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2311a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) 2312c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek priv->radio_on = enable; 2313a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2314a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2315a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2316a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 231755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw) 2318c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 231955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 0, 0); 2320c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2321c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 232255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) 2323c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 232455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 0); 2325c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2326c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 2327a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 2328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) 2329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 233099200a992e365a73dc67a6570524e5f3af4386ddLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 233268ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek priv->radio_short_preamble = short_preamble; 2333a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 233455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 1); 2335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 233855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RF_TX_POWER. 2339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 234041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 2341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 234255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_rf_tx_power { 2343a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2344a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 support_level; 2346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 current_level; 2347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 reserved; 234841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL]; 2349ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2350a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 235155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) 2352a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 235355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_rf_tx_power *cmd; 2354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2355a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2357a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2358a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2359a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER); 2361a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->support_level = cpu_to_le16(dBm); 2364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2366a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2367a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2368a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2370a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 237241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam * CMD_TX_POWER. 237341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam */ 237441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_TX_POWER_LEVEL_TOTAL 12 237541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 237641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstruct mwl8k_cmd_tx_power { 237741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_pkt header; 237841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 action; 237941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 band; 238041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 channel; 238141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 bw; 238241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 sub_ch; 238341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; 238441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam} __attribute__((packed)); 238541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 238641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstatic int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, 238741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_conf *conf, 238841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam unsigned short pwr) 238941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam{ 239041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_channel *channel = conf->channel; 239141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_tx_power *cmd; 239241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int rc; 239341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int i; 239441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 239541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 239641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (cmd == NULL) 239741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return -ENOMEM; 239841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 239941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER); 240041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 240141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST); 240241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 240341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (channel->band == IEEE80211_BAND_2GHZ) 240441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x1); 240541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (channel->band == IEEE80211_BAND_5GHZ) 240641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x4); 240741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 240841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->channel = channel->hw_value; 240941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 241041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_NO_HT || 241141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam conf->channel_type == NL80211_CHAN_HT20) { 241241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x2); 241341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } else { 241441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x4); 241541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_HT40MINUS) 241641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x3); 241741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 241841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x1); 241941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } 242041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 242141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++) 242241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->power_level_list[i] = cpu_to_le16(pwr); 242341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 242441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_post_cmd(hw, &cmd->header); 242541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam kfree(cmd); 242641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 242741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return rc; 242841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam} 242941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 243041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam/* 243108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek * CMD_RF_ANTENNA. 243208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek */ 243308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstruct mwl8k_cmd_rf_antenna { 243408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_pkt header; 243508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 antenna; 243608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 mode; 2437ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 243808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 243908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_RX 1 244008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_TX 2 244108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 244208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstatic int 244308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekmwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) 244408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek{ 244508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_rf_antenna *cmd; 244608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek int rc; 244708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 244808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 244908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (cmd == NULL) 245008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return -ENOMEM; 245108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 245208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA); 245308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 245408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->antenna = cpu_to_le16(antenna); 245508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->mode = cpu_to_le16(mask); 245608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 245708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 245808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek kfree(cmd); 245908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 246008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return rc; 246108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek} 246208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 246308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek/* 2464b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_SET_BEACON. 2465b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 2466b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_set_beacon { 2467b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 2468b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le16 beacon_len; 2469b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __u8 beacon[0]; 2470b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek}; 2471b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2472aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, 2473aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, u8 *beacon, int len) 2474b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 2475b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_beacon *cmd; 2476b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 2477b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2478b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); 2479b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 2480b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 2481b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2482b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); 2483b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); 2484b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->beacon_len = cpu_to_le16(len); 2485b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->beacon, beacon, len); 2486b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2487aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 2488b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 2489b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2490b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 2491b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 2492b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2493b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 2494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_PRE_SCAN. 2495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_pre_scan { 2497a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2498ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) 2501a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2502a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_pre_scan *cmd; 2503a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2504a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2505a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2506a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2508a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2509a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN); 2510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2512a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2513a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2519a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_POST_SCAN. 2520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_post_scan { 2522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2523a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 isibss; 2524d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 bssid[ETH_ALEN]; 2525ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 25280a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhekmwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) 2529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2530a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_post_scan *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_POST_SCAN); 2538a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2539a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->isibss = 0; 2540d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memcpy(cmd->bssid, mac, ETH_ALEN); 2541a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2543a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2544a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2545a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2549a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_RF_CHANNEL. 2550a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2551a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_rf_channel { 2552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2554a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 current_channel; 2555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 channel_flags; 2556ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2558a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, 2559610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_conf *conf) 2560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2561610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_channel *channel = conf->channel; 2562a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_rf_channel *cmd; 2563a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL); 2570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->current_channel = channel->hw_value; 2573610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 2574a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (channel->band == IEEE80211_BAND_2GHZ) 2575610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000001); 257642574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek else if (channel->band == IEEE80211_BAND_5GHZ) 257742574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000004); 2578610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 2579610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek if (conf->channel_type == NL80211_CHAN_NO_HT || 2580610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek conf->channel_type == NL80211_CHAN_HT20) 2581610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000080); 2582610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40MINUS) 2583610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000001900); 2584610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 2585610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000000900); 2586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 259455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_AID. 2595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 259655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_DISABLED 0x00 259755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11G 0x07 259855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 259955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 2600a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 260155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_set_aid { 260255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 260355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 aid; 2604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 260555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* AP's MAC address (BSSID) */ 260655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 bssid[ETH_ALEN]; 260755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 protection_mode; 260855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 supp_rates[14]; 2609ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2610a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2611c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekstatic void legacy_rate_mask_to_array(u8 *rates, u32 mask) 2612c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek{ 2613c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int i; 2614c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int j; 2615c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 2616c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek /* 2617c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek * Clear nonstandard rates 4 and 13. 2618c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek */ 2619c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek mask &= 0x1fef; 2620c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 2621c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek for (i = 0, j = 0; i < 14; i++) { 2622c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek if (mask & (1 << i)) 2623777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek rates[j++] = mwl8k_rates_24[i].hw_value; 2624c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek } 2625c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek} 2626c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 262755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 2628c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_aid(struct ieee80211_hw *hw, 2629c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, u32 legacy_rate_mask) 2630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 263155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_set_aid *cmd; 263255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek u16 prot_mode; 2633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 263955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); 2640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 26417dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek cmd->aid = cpu_to_le16(vif->bss_conf.aid); 26420a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); 2643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 26447dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.use_cts_prot) { 264555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11G; 264655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 26477dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek switch (vif->bss_conf.ht_operation_mode & 264855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek IEEE80211_HT_OP_MODE_PROTECTION) { 264955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: 265055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; 265155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 265255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: 265355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; 265455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 265555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek default: 265655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_DISABLED; 265755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 265855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 265955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 266055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->protection_mode = cpu_to_le16(prot_mode); 2661a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2662c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); 2663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 267155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATE. 267232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek */ 267355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate { 267455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 267555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 legacy_rates[14]; 267655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 267755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Bitmap for supported MCS codes. */ 267855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mcs_set[16]; 267955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 reserved[16]; 2680ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 268132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 268255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 2683c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 268413935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u32 legacy_rate_mask, u8 *mcs_rates) 268532060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek{ 268655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate *cmd; 268732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek int rc; 268832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 268932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 269032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (cmd == NULL) 269132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return -ENOMEM; 269232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 269355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); 269432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2695c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); 269613935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->mcs_set, mcs_rates, 16); 269732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 269832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 269932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek kfree(cmd); 270032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 270132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return rc; 270232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek} 270332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 270432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek/* 270555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_FINALIZE_JOIN. 2706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 270755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FJ_BEACON_MAXLEN 128 270855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 270955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_finalize_join { 2710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 271155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 sleep_interval; /* Number of beacon periods to sleep */ 271255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; 2713ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 271555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, 271655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int framelen, int dtim) 2717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 271855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_finalize_join *cmd; 271955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_mgmt *payload = frame; 272055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int payload_len; 2721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2722a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2723a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2724a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2725a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2726a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 272755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); 2728a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 272955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); 273055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 273155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = framelen - ieee80211_hdrlen(payload->frame_control); 273255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (payload_len < 0) 273355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = 0; 273455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) 273555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = MWL8K_FJ_BEACON_MAXLEN; 273655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 273755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); 2738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 274655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RTS_THRESHOLD. 2747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 274855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rts_threshold { 2749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 275155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 threshold; 2752ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2754c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekstatic int 2755c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekmwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) 2756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 275755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rts_threshold *cmd; 2758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2759a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2761a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 276455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); 2765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2766c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2767c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->threshold = cpu_to_le16(rts_thresh); 2768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2770a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 277655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_SLOT. 2777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 277855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_slot { 2779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 278155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 short_slot; 2782ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2783a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 278455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) 2785a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 278655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_slot *cmd; 2787a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2788a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2789a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2790a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2791a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2792a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 279355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); 2794a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 279555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 279655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->short_slot = short_slot_time; 2797a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2798a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2799a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2800a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2801a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2802a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2803a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_EDCA_PARAMS. 2806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2807a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_edca_params { 2808a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2809a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2810a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* See MWL8K_SET_EDCA_XXX below */ 2811a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2812a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* TX opportunity in units of 32 us */ 2814a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 txop; 2815a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28162e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek union { 28172e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 28182e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 28192e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_max; 28202e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 28212e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 28222e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_min; 28232e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 28242e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 28252e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 28262e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 28272e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 28282e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 28292e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } ap; 28302e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 28312e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 28322e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_max; 2833a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28342e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 28352e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_min; 2836a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28372e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 28382e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 2839a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 28402e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 28412e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 28422e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } sta; 28432e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek }; 2844ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2845a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2846a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_CW 0x01 2847a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_TXOP 0x02 2848a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_AIFS 0x04 2849a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2850a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_ALL (MWL8K_SET_EDCA_CW | \ 2851a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_TXOP | \ 2852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_AIFS) 2853a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2854a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 285555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, 285655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u16 cw_min, __u16 cw_max, 285755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 aifs, __u16 txop) 2858a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 28592e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2860a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_edca_params *cmd; 2861a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2862a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2863a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2864a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2865a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2866a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2867a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); 2868a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2869a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); 2870a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->txop = cpu_to_le16(txop); 28712e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek if (priv->ap_fw) { 28722e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1)); 28732e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1)); 28742e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.aifs = aifs; 28752e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.txq = qnum; 28762e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } else { 28772e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1); 28782e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1); 28792e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.aifs = aifs; 28802e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.txq = qnum; 28812e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } 2882a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2883a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2884a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2885a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2886a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2887a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2888a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2889a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 289055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_WMM_MODE. 2891a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 289255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_wmm_mode { 2893a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 289455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 2895ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2896a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 289755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) 2898a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 289955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 290055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_wmm_mode *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_SET_WMM_MODE); 2908a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 290955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(!!enable); 2910a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2911a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2912a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 291316cec43da50c4b4702653ca710549fd3457a4e6cLennert Buytenhek 291455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (!rc) 291555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek priv->wmm_enabled = enable; 2916a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2917a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2918a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2919a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2920a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 292155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_MIMO_CONFIG. 2922a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 292355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_mimo_config { 292455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 292555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 292655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 rx_antenna_map; 292755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 tx_antenna_map; 2928ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2929a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 293055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) 2931a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 293255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_mimo_config *cmd; 2933a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2934a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2935a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2937a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2938a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 293955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); 2940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 294155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); 294255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->rx_antenna_map = rx; 294355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->tx_antenna_map = tx; 2944a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2945a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2946a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2950a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2952b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek * CMD_USE_FIXED_RATE (STA version). 2953a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2954b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_sta { 2955b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_pkt header; 2956b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 action; 2957b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 allow_rate_drop; 2958b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 num_rates; 2959b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct { 2960b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 is_ht_rate; 2961b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 enable_retry; 2962b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate; 2963b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 retry_count; 2964b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek } rate_entry[8]; 2965b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate_type; 2966b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved1; 2967b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved2; 2968ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2969a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2970b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_USE_AUTO_RATE 0x0002 2971b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_UCAST_RATE 0 2972a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2973b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstatic int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) 2974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2975b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_sta *cmd; 2976a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2977a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2979a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2980a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2981a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2982a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 2983a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2984b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 2985b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); 2986a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2987a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2988a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2989a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2990a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2991a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2992a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 299355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 2994088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek * CMD_USE_FIXED_RATE (AP version). 2995088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek */ 2996088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_ap { 2997088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_pkt header; 2998088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 action; 2999088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 allow_rate_drop; 3000088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 num_rates; 3001088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_rate_entry_ap { 3002088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 is_ht_rate; 3003088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 enable_retry; 3004088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 rate; 3005088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 retry_count; 3006088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek } rate_entry[4]; 3007088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate; 3008088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate_type; 3009088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 management_rate; 3010ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3011088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3012088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstatic int 3013088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekmwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) 3014088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek{ 3015088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_ap *cmd; 3016088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek int rc; 3017088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3018088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3019088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek if (cmd == NULL) 3020088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return -ENOMEM; 3021088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3022088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 3023088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3024088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 3025088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->multicast_rate = mcast; 3026088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->management_rate = mgmt; 3027088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3028088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3029088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek kfree(cmd); 3030088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3031088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return rc; 3032088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek} 3033088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3034088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek/* 303555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_ENABLE_SNIFFER. 303655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 303755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_enable_sniffer { 303855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 303955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 3040ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 304155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 304255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) 304355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 304455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_enable_sniffer *cmd; 304555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 304655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 304755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 304855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 304955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 305055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 305155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); 305255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 305355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32(!!enable); 305455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 305555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 305655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 305755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 305855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 305955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 306055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 306155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 306255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_MAC_ADDR. 306355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 306455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_mac_addr { 306555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 306655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek union { 306755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct { 306855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mac_type; 306955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 307055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } mbss; 307155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 307255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek }; 3073ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 307455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3075ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 3076ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 3077ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_AP 2 3078ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_AP 3 3079a9e00b151ec2121b7ae09d84a2b5a68b6461e98aLennert Buytenhek 3080aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, 3081aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, u8 *mac) 308255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 308355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3084ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 308555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_mac_addr *cmd; 3086ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek int mac_type; 308755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 308855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3089ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3090ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { 3091ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) 3092ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; 3093ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3094ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; 3095ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { 3096ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) 3097ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3098ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3099ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; 3100ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 3101ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 310255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 310355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 310455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 310555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 310655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); 310755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 310855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (priv->ap_fw) { 3109ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek cmd->mbss.mac_type = cpu_to_le16(mac_type); 311055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); 311155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 311255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mac_addr, mac, ETH_ALEN); 311355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 311455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3115aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 311655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 311755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 311855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 311955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 312055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 312155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 312255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATEADAPT_MODE. 312355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 312455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate_adapt_mode { 312555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 312655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 312755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mode; 3128ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 312955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 313055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) 313155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 313255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate_adapt_mode *cmd; 313355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 313455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 313555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 313655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 313755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 313855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 313955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); 314055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 314155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 314255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->mode = cpu_to_le16(mode); 314355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 314455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 314555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 314655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 314755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 314855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 314955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 315055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 3151b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_BSS_START. 3152b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 3153b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_bss_start { 3154b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 3155b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le32 enable; 3156ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3157b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3158aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, 3159aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, int enable) 3160b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3161b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_bss_start *cmd; 3162b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3163b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3164b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3165b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3166b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3167b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3168b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); 3169b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3170b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->enable = cpu_to_le32(enable); 3171b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3172aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3173b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3174b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3175b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3176b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3177b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3178b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 31793f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek * CMD_SET_NEW_STN. 31803f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek */ 31813f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstruct mwl8k_cmd_set_new_stn { 31823f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_pkt header; 31833f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 aid; 31843f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_addr[6]; 31853f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stn_id; 31863f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 action; 31873f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 rsvd; 31883f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 legacy_rates; 31893f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 ht_rates[4]; 31903f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 cap_info; 31913f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 ht_capabilities_info; 31923f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_ht_param_info; 31933f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 rev; 31943f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 control_channel; 31953f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_channel; 31963f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 op_mode; 31973f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stbc; 31983f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_qos_info; 31993f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 is_qos_sta; 32003f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 fw_sta_ptr; 3201ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 32023f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32033f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_ADD 0 32043f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_REMOVE 2 32053f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32063f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, 32073f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, 32083f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_sta *sta) 32093f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 32103f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 32118707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 32123f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek int rc; 32133f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32143f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 32153f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 32163f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 32173f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32183f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 32193f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 32203f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->aid = cpu_to_le16(sta->aid); 32213f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); 32223f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->stn_id = cpu_to_le16(sta->aid); 32233f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); 32248707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 32258707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 32268707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 32278707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 32288707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek cmd->legacy_rates = cpu_to_le32(rates); 32293f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (sta->ht_cap.ht_supported) { 32303f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; 32313f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; 32323f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; 32333f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; 32343f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); 32353f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | 32363f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 32373f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->is_qos_sta = 1; 32383f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek } 32393f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3240aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 32413f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 32423f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32433f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 32443f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 32453f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3246b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, 3247b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_vif *vif) 3248b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3249b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 3250b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3251b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3252b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3253b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3254b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3255b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3256b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 3257b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3258b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); 3259b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3260aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3261b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3262b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3263b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3264b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3265b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 32663f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, 32673f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 32683f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 32693f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 32703f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek int rc; 32713f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32723f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 32733f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 32743f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 32753f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32763f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 32773f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 32783f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, addr, ETH_ALEN); 32793f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); 32803f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3281aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 32823f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 32833f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32843f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 32853f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 32863f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 32873f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek/* 3288fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam * CMD_UPDATE_ENCRYPTION. 3289fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam */ 3290fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3291fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MAX_ENCR_KEY_LENGTH 16 3292fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MIC_KEY_LENGTH 8 3293fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3294fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_update_encryption { 3295fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 3296fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3297fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 3298fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 3299fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 3300fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 encr_type; 3301fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3302fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} __attribute__((packed)); 3303fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3304fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_set_key { 3305fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 3306fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3307fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 3308fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 3309fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 length; 3310fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_type_id; 3311fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_info; 3312fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_id; 3313fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_len; 3314fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 key_material[MAX_ENCR_KEY_LENGTH]; 3315fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; 3316fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; 3317fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_rsc_low; 3318fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_rsc_high; 3319fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_tsc_low; 3320fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_tsc_high; 3321fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 3322fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} __attribute__((packed)); 3323fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3324fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 3325fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_ENABLE, 3326fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_KEY, 3327fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_REMOVE_KEY, 3328fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_GROUP_KEY, 3329fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 3330fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3331fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 3332fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 3333fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 3334fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 3335fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 3336fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3337fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 3338fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_WEP, 3339fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_TKIP, 3340fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_CCMP, 3341fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 3342fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3343fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 3344fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 3345fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 3346fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 3347fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 3348fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3349fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, 3350fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3351fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3352fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type) 3353fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3354fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_update_encryption *cmd; 3355fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3356fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3357fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3358fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3359fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3360fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3361fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3362fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3363fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); 3364fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 3365fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->encr_type = encr_type; 3366fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3367fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3368fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3369fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3370fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3371fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3372fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3373fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, 3374fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3375fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3376fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3377fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3378fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3379fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->length = cpu_to_le16(sizeof(*cmd) - 3380fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam offsetof(struct mwl8k_cmd_set_key, length)); 3381fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_id = cpu_to_le32(key->keyidx); 3382fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_len = cpu_to_le16(key->keylen); 3383fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 3384fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3385fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 3386fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 3387fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 3388fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); 3389fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->keyidx == 0) 3390fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); 3391fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3392fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3393fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 3394fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); 3395fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3396fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3397fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3398fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID 3399fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam | MWL8K_KEY_FLAG_TSC_VALID); 3400fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3401fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 3402fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); 3403fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3404fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3405fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3406fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3407fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 3408fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOTSUPP; 3409fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3410fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3411fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return 0; 3412fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3413fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3414fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, 3415fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3416fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3417fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3418fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3419fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 3420fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3421fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int keymlen; 3422fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u32 action; 3423fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 idx; 3424fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3425fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3426fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3427fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3428fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3429fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3430fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3431fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 3432fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3433fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3434fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam idx = key->keyidx; 3435fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3436fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3437fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 3438fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3439fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_GROUP_KEY; 3440fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3441fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 3442fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 3443fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 3444fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (!mwl8k_vif->wep_key_conf[idx].enabled) { 3445fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(mwl8k_vif->wep_key_conf[idx].key, key, 3446fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam sizeof(*key) + key->keylen); 3447fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[idx].enabled = 1; 3448fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3449fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3450fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = 0; 3451fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 3452fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3453fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 3454fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; 3455fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3456fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 3457fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = key->keylen; 3458fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 3459fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 3460fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = -ENOTSUPP; 3461fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3462fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3463fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3464fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->key_material, key->key, keymlen); 3465fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(action); 3466fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3467fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3468fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 3469fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3470fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3471fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3472fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3473fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3474fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, 3475fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3476fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 3477fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3478fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3479fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 3480fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 3481fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3482fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3483fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3484fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 3485fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 3486fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3487fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3488fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 3489fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 3490fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3491fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || 3492fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam WLAN_CIPHER_SUITE_WEP104) 3493fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; 3494fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3495fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); 3496fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3497fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3498fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 3499fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 3500fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3501fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3502fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3503fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3504fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_set_key(struct ieee80211_hw *hw, 3505fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam enum set_key_cmd cmd_param, 3506fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 3507fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_sta *sta, 3508fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 3509fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 3510fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc = 0; 3511fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type; 3512fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr; 3513fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3514fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3515fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (vif->type == NL80211_IFTYPE_STATION) 3516fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -EOPNOTSUPP; 3517fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3518fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (sta == NULL) 3519fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam addr = hw->wiphy->perm_addr; 3520fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3521fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam addr = sta->addr; 3522fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3523fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd_param == SET_KEY) { 3524fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 3525fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); 3526fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3527fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3528fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3529fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) 3530fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) 3531fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; 3532fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 3533fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; 3534fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3535fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, 3536fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type); 3537fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3538fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3539fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3540fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = true; 3541fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3542fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } else { 3543fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); 3544fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3545fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 3546fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 3547fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3548fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = false; 3549fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3550fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 3551fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamout: 3552fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 3553fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 3554fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 3555fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam/* 355655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_UPDATE_STADB. 355755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 355825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct ewc_ht_info { 355925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control1; 356025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control2; 356125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control3; 3562ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 356325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 356425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct peer_capability_info { 356525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Peer type - AP vs. STA. */ 356625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 peer_type; 356725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 356825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Basic 802.11 capabilities from assoc resp. */ 356925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 basic_caps; 357025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 357125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Set if peer supports 802.11n high throughput (HT). */ 357225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_support; 357325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 357425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Valid if HT is supported. */ 357525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 ht_caps; 357625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 extended_ht_caps; 357725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek struct ewc_ht_info ewc_info; 357825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 357925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Legacy rate table. Intersection of our rates and peer rates. */ 358025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 legacy_rates[12]; 358125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 358225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* HT rate table. Intersection of our rates and peer rates. */ 358325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_rates[16]; 358425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad[16]; 358525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 358625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* If set, interoperability mode, no proprietary extensions. */ 358725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 interop; 358825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad2; 358925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 station_id; 359025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 amsdu_enabled; 3591ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 359225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 359355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_stadb { 359455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 359555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 359655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* See STADB_ACTION_TYPE */ 359755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 359855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 359955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer MAC address */ 360055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 peer_addr[ETH_ALEN]; 360155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 360255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 reserved; 360355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 360455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer info - valid during add/update. */ 360555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct peer_capability_info peer_info; 3606ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 360755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3608a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_MODIFY_ENTRY 1 3609a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_DEL_ENTRY 2 3610a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3611a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek/* Peer Entry flags - used to define the type of the peer node */ 3612a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_PEER_TYPE_ACCESSPOINT 2 3613a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3614a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, 3615c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, 361613935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek struct ieee80211_sta *sta) 361755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 361855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 3619a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct peer_capability_info *p; 36208707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 362155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 362255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 362355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 362455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 362555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 362655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 362755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 362855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3629a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); 363013935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); 363155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3632a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p = &cmd->peer_info; 3633a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; 3634a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); 363513935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->ht_support = sta->ht_cap.ht_supported; 3636b603742f49c3ec922522602e18ac22e8f6835132John W. Linville p->ht_caps = cpu_to_le16(sta->ht_cap.cap); 363713935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | 363813935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 36398707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 36408707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 36418707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 36428707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 36438707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek legacy_rate_mask_to_array(p->legacy_rates, rates); 364413935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); 3645a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->interop = 1; 3646a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->amsdu_enabled = 0; 3647a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3648a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3649a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek kfree(cmd); 3650a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3651a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek return rc ? rc : p->station_id; 3652a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek} 3653a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3654a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, 3655a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 3656a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek{ 3657a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 3658a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek int rc; 3659a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3660a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3661a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek if (cmd == NULL) 3662a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek return -ENOMEM; 3663a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 3664a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 3665a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3666a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); 3667bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek memcpy(cmd->peer_addr, addr, ETH_ALEN); 366855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3669a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 367055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 367155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 367255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 367355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 367455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Interrupt handling. 3678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic irqreturn_t mwl8k_interrupt(int irq, void *dev_id) 3680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = dev_id; 3682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 3684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 3686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!status) 3687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_NONE; 3688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 36891e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (status & MWL8K_A2H_INT_TX_DONE) { 36901e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek status &= ~MWL8K_A2H_INT_TX_DONE; 36911e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 36921e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 36931e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 3694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_RX_READY) { 369567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek status &= ~MWL8K_A2H_INT_RX_READY; 369667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 3697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 369967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (status) 370067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 370167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 3702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_OPC_DONE) { 3703618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->hostcmd_wait != NULL) 3704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek complete(priv->hostcmd_wait); 3705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { 3708618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!mutex_is_locked(&priv->fw_mutex) && 370988de754ad59025eba797e7a8375807755577f450Lennert Buytenhek priv->radio_on && priv->pending_tx_pkts) 3710618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mwl8k_tx_start(priv); 3711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_HANDLED; 3714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37161e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhekstatic void mwl8k_tx_poll(unsigned long data) 37171e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek{ 37181e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 37191e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 37201e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int limit; 37211e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int i; 37221e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37231e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit = 32; 37241e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37251e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_lock_bh(&priv->tx_lock); 37261e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37271e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 37281e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit -= mwl8k_txq_reclaim(hw, i, limit, 0); 37291e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37301e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { 37311e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek complete(priv->tx_wait); 37321e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->tx_wait = NULL; 37331e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 37341e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37351e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 37361e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 37371e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (limit) { 37381e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek writel(~MWL8K_A2H_INT_TX_DONE, 37391e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 37401e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } else { 37411e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 37421e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 37431e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek} 37441e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 374567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhekstatic void mwl8k_rx_poll(unsigned long data) 374667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek{ 374767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 374867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 374967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek int limit; 375067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 375167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit = 32; 375267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_process(hw, 0, limit); 375367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_refill(hw, 0, limit); 375467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 375567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (limit) { 375667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek writel(~MWL8K_A2H_INT_RX_READY, 375767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 375867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } else { 375967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 376067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } 376167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek} 376267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 3763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3764a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Core driver operations. 3766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 37677bb4568372856688bc070917265bce0b88bb7d4dJohannes Bergstatic void mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 3768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3769a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3770a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int index = skb_get_queue_mapping(skb); 3771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37729189c10087a738c764046fa27651d332594cd8e6Lennert Buytenhek if (!priv->radio_on) { 3773c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 3774c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "dropped TX frame since radio disabled\n"); 3775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(skb); 37767bb4568372856688bc070917265bce0b88bb7d4dJohannes Berg return; 3777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 37797bb4568372856688bc070917265bce0b88bb7d4dJohannes Berg mwl8k_txq_xmit(hw, index, skb); 3780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3782a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_start(struct ieee80211_hw *hw) 3783a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3784a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3785a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3786a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3787a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 3788a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 3789a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 37905db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 37912ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek return -EIO; 3792a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 3793a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 379467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Enable TX reclaim and RX tasklets. */ 37951e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_enable(&priv->poll_tx_task); 379667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_enable(&priv->poll_rx_task); 37972ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 3798a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Enable interrupts */ 3799c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3800a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38012ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek rc = mwl8k_fw_lock(hw); 38022ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) { 380355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 3804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38055e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!priv->ap_fw) { 38065e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 380755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_enable_sniffer(hw, 0); 3808a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38095e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 38105e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_pre_scan(hw); 38115e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek 38125e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 38135e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_post_scan(hw, 38145e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek "\x00\x00\x00\x00\x00\x00"); 38155e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek } 38162ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 38172ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 381855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_rateadapt_mode(hw, 0); 3819a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38202ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 382155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 0); 3822a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38232ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek mwl8k_fw_unlock(hw); 38242ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 38252ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 38262ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (rc) { 38272ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 38282ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek free_irq(priv->pdev->irq, hw); 38291e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 383067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 38312ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 3832a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3833a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3834a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3835a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3836a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_stop(struct ieee80211_hw *hw) 3837a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3838a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3839a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 3840a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 384155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_radio_disable(hw); 3842a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3843a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 3844a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3845a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 3846a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 3847a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 3848a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3849a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop finalize join worker */ 3850a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cancel_work_sync(&priv->finalize_join_worker); 3851a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 3852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(priv->beacon_skb); 3853a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 385467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Stop TX reclaim and RX tasklets. */ 38551e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 385667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 3857a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3858a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 3859a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 3860efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 3861a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3862a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 38630863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image); 38640863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 3865a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_add_interface(struct ieee80211_hw *hw, 3866f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif) 3867a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3868a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3869a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 3870ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_supported; 38710863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo int macid, rc; 38720863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 3873a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3874a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 3875a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Reject interface creation if sniffer mode is active, as 3876a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * STA operation is mutually exclusive with hardware sniffer 3877b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * mode. (Sniffer mode is only used on STA firmware.) 3878a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 3879a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 3880c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 3881c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "unable to create STA interface because sniffer mode is enabled\n"); 3882a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return -EINVAL; 3883a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 3884a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 38850863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 3886ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek switch (vif->type) { 3887ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_AP: 38880863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!priv->ap_fw && di->fw_image_ap) { 38890863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* we must load the ap fw to meet this request */ 38900863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!list_empty(&priv->vif_list)) 38910863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return -EBUSY; 38920863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo rc = mwl8k_reload_firmware(hw, di->fw_image_ap); 38930863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (rc) 38940863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return rc; 38950863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 3896ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->ap_macids_supported; 3897ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 3898ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_STATION: 38990863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (priv->ap_fw && di->fw_image_sta) { 39000863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* we must load the sta fw to meet this request */ 39010863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!list_empty(&priv->vif_list)) 39020863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return -EBUSY; 39030863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo rc = mwl8k_reload_firmware(hw, di->fw_image_sta); 39040863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (rc) 39050863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return rc; 39060863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 3907ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->sta_macids_supported; 3908ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 3909ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek default: 3910ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EINVAL; 3911ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 3912ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 3913ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macid = ffs(macids_supported & ~priv->macids_used); 3914ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (!macid--) 3915ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EBUSY; 3916ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 3917f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* Setup driver private area. */ 39181ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg mwl8k_vif = MWL8K_VIF(vif); 3919a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); 3920f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif->vif = vif; 3921ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mwl8k_vif->macid = macid; 3922a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif->seqno = 0; 3923d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); 3924d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = false; 3925a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3926aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek /* Set the mac address. */ 3927aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); 3928aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 3929aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek if (priv->ap_fw) 3930aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_new_stn_add_self(hw, vif); 3931aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 3932ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->macids_used |= 1 << mwl8k_vif->macid; 3933f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek list_add_tail(&mwl8k_vif->list, &priv->vif_list); 3934a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3935a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 3936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3937a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3938a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_remove_interface(struct ieee80211_hw *hw, 39391ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg struct ieee80211_vif *vif) 3940a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3941a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3942f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3943a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3944b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (priv->ap_fw) 3945b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); 3946b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3947aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); 394832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 3949ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->macids_used &= ~(1 << mwl8k_vif->macid); 3950f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek list_del(&mwl8k_vif->list); 3951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3952a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3953ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekstatic int mwl8k_config(struct ieee80211_hw *hw, u32 changed) 3954a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3955a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_conf *conf = &hw->conf; 3956a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3957ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek int rc; 3958a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 39597595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek if (conf->flags & IEEE80211_CONF_IDLE) { 396055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_radio_disable(hw); 3961ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return 0; 39627595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek } 39637595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek 3964ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek rc = mwl8k_fw_lock(hw); 3965ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3966ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 3967a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 396855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 3969ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3970ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek goto out; 3971a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3972610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek rc = mwl8k_cmd_set_rf_channel(hw, conf); 3973ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 3974ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek goto out; 3975ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek 3976a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (conf->power_level > 18) 3977a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek conf->power_level = 18; 3978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 397908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (priv->ap_fw) { 398041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); 398141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (rc) 398241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto out; 398341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 3984da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); 3985da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam if (rc) 3986da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); 3987da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); 3988da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam if (rc) 3989da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); 3990da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam 399108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } else { 399241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); 399341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (rc) 399441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto out; 399508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); 399608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } 3997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3998ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekout: 3999ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek mwl8k_fw_unlock(hw); 4000a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4001ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 4002a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4003a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4004b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4005b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4006b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4007a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4008a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4009c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek u32 ap_legacy_rates; 401013935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u8 ap_mcs_rates[16]; 40113a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek int rc; 40123a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 4013c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (mwl8k_fw_lock(hw)) 40143a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek return; 4015a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4016c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 4017c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek * No need to capture a beacon if we're no longer associated. 4018c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 4019c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) 4020c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek priv->capture_beacon = false; 40213a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 4022c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 402313935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek * Get the AP's legacy and MCS rates. 4024c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 40257dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.assoc) { 4026c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_sta *ap; 4027c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek 4028c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek rcu_read_lock(); 4029c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4030c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); 4031c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (ap == NULL) { 4032c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4033c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek goto out; 4034c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4035c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 40368707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { 40378707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; 40388707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } else { 40398707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = 40408707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; 40418707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } 404213935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); 4043c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 4044c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4045c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4046c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4047c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { 404813935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); 40493a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40503a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4051a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4052b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek rc = mwl8k_cmd_use_fixed_rate_sta(hw); 40533a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40543a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4055c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4057c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 40587dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 40597dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek vif->bss_conf.use_short_preamble); 40603a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40613a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4062c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4063a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4064c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_SLOT) { 40657dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); 40663a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40673a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4068c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4069a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4070c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek if (vif->bss_conf.assoc && 4071c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | 4072c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek BSS_CHANGED_HT))) { 4073c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); 40743a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 40753a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4076c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4077a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4078c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (vif->bss_conf.assoc && 4079c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { 4080a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4081a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Finalize the join. Tell rx handler to process 4082a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * next beacon from our BSSID. 4083a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 40840a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); 4085a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = true; 4086a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 40883a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhekout: 40893a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek mwl8k_fw_unlock(hw); 4090a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4091a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4092b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4093b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4094b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4095b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4096b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 4097b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4098b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (mwl8k_fw_lock(hw)) 4099b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return; 4100b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4101b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 4102b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 4103b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek vif->bss_conf.use_short_preamble); 4104b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (rc) 4105b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek goto out; 4106b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4107b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4108b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BASIC_RATES) { 4109b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int idx; 4110b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rate; 4111b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4112b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek /* 4113b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * Use lowest supported basic rate for multicasts 4114b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * and management frames (such as probe responses -- 4115b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * beacons will always go out at 1 Mb/s). 4116b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 4117b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek idx = ffs(vif->bss_conf.basic_rates); 41188707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (idx) 41198707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek idx--; 41208707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek 41218707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 41228707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_24[idx].hw_value; 41238707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 41248707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_50[idx].hw_value; 4125b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4126b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); 4127b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4128b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4129b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { 4130b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct sk_buff *skb; 4131b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4132b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek skb = ieee80211_beacon_get(hw, vif); 4133b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (skb != NULL) { 4134aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); 4135b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree_skb(skb); 4136b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4137b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4138b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4139b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BEACON_ENABLED) 4140aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); 4141b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4142b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekout: 4143b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_fw_unlock(hw); 4144b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4145b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4146b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4147b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4148b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4149b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4150b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4151b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4152b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (!priv->ap_fw) 4153b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_sta(hw, vif, info, changed); 4154b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek else 4155b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_ap(hw, vif, info, changed); 4156b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4157b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4158e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, 415922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 4160e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek{ 4161e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_cmd_pkt *cmd; 4162e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4163447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 4164447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * Synthesize and return a command packet that programs the 4165447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * hardware multicast address filter. At this point we don't 4166447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * know whether FIF_ALLMULTI is being requested, but if it is, 4167447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * we'll end up throwing this packet away and creating a new 4168447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * one in mwl8k_configure_filter(). 4169447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 417022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_list); 4171e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4172e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return (unsigned long)cmd; 4173e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek} 4174e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 4175a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekstatic int 4176a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekmwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, 4177a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int changed_flags, 4178a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int *total_flags) 4179a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek{ 4180a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4181a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4182a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 4183a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Hardware sniffer mode is mutually exclusive with STA 4184a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * operation, so refuse to enable sniffer mode if a STA 4185a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * interface is active. 4186a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 4187f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) { 4188a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (net_ratelimit()) 4189c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 4190c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "not enabling sniffer mode because STA interface is active\n"); 4191a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 4192a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4193a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4194a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (!priv->sniffer_enabled) { 419555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (mwl8k_cmd_enable_sniffer(hw, 1)) 4196a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 4197a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = true; 4198a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4199a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4200a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | 4201a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | 4202a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_OTHER_BSS; 4203a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4204a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 1; 4205a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek} 4206a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4207f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhekstatic struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) 4208f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek{ 4209f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) 4210f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return list_entry(priv->vif_list.next, struct mwl8k_vif, list); 4211f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 4212f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return NULL; 4213f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek} 4214f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 4215e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhekstatic void mwl8k_configure_filter(struct ieee80211_hw *hw, 4216e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int changed_flags, 4217e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int *total_flags, 4218e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek u64 multicast) 4219e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek{ 4220e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4221a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; 4222a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4223a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 4224c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * AP firmware doesn't allow fine-grained control over 4225c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * the receive filter. 4226c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek */ 4227c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek if (priv->ap_fw) { 4228c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 4229c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek kfree(cmd); 4230c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek return; 4231c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek } 4232c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek 4233c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek /* 4234a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Enable hardware sniffer mode if FIF_CONTROL or 4235a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * FIF_OTHER_BSS is requested. 4236a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 4237a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (*total_flags & (FIF_CONTROL | FIF_OTHER_BSS) && 4238a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek mwl8k_configure_filter_sniffer(hw, changed_flags, total_flags)) { 4239a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek kfree(cmd); 4240a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return; 4241a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4243e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek /* Clear unsupported feature flags */ 4244447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 4245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 424690852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek if (mwl8k_fw_lock(hw)) { 424790852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek kfree(cmd); 4248e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek return; 424990852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek } 4250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4251a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 425255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_enable_sniffer(hw, 0); 4253a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = false; 4254a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4255a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 4256e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 425777165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { 425877165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 425977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Disable the BSS filter. 426077165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 4261e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_pre_scan(hw); 426277165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek } else { 4263f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 42640a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek const u8 *bssid; 4265a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 426677165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 426777165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Enable the BSS filter. 426877165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * 426977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * If there is an active STA interface, use that 427077165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * interface's BSSID, otherwise use a dummy one 427177165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * (where the OUI part needs to be nonzero for 427277165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * the BSSID to be accepted by POST_SCAN). 427377165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 4274f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif = mwl8k_first_vif(priv); 4275f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (mwl8k_vif != NULL) 4276f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = mwl8k_vif->vif->bss_conf.bssid; 4277f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek else 4278f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = "\x01\x00\x00\x00\x00\x00"; 4279a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 4280e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_post_scan(hw, bssid); 4281a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4282a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4283a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4284447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 4285447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * If FIF_ALLMULTI is being requested, throw away the command 4286447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packet that ->prepare_multicast() built and replace it with 4287447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * a command packet that enables reception of all multicast 4288447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packets. 4289447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 4290447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (*total_flags & FIF_ALLMULTI) { 4291447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 429222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, NULL); 4293447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek } 4294447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek 4295447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (cmd != NULL) { 4296447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek mwl8k_post_cmd(hw, cmd); 4297447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 4298e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek } 4299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4300e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_fw_unlock(hw); 4301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 4304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4305c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek return mwl8k_cmd_set_rts_threshold(hw, value); 4306a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4307a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43084a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_remove(struct ieee80211_hw *hw, 43094a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 43104a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 43113f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 43123f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 43133f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 43144a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (priv->ap_fw) 43154a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr); 43164a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg else 43174a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr); 4318bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 4319bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 43204a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_add(struct ieee80211_hw *hw, 43214a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 43224a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 4323bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek{ 4324bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 43254a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg int ret; 4326fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int i; 4327fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4328fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key; 4329bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 43304a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (!priv->ap_fw) { 43314a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); 43324a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (ret >= 0) { 43334a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg MWL8K_STA(sta)->peer_id = ret; 4334fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ret = 0; 43354a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg } 4336bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 4337d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } else { 4338d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); 4339bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek } 43404a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg 4341d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam for (i = 0; i < NUM_WEP_KEYS; i++) { 4342d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); 4343d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif->wep_key_conf[i].enabled) 4344d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_set_key(hw, SET_KEY, vif, sta, key); 4345d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 4346fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return ret; 4347bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 4348bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 4349a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, 4350a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const struct ieee80211_tx_queue_params *params) 4351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 43523e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4353a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 4354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43553e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek rc = mwl8k_fw_lock(hw); 43563e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!rc) { 43570863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo BUG_ON(queue > MWL8K_TX_QUEUES - 1); 43580863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo memcpy(&priv->wmm_params[queue], params, sizeof(*params)); 43590863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 43603e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!priv->wmm_enabled) 436155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 1); 4362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 436385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam if (!rc) { 436485c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam int q = MWL8K_TX_QUEUES - 1 - queue; 436585c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam rc = mwl8k_cmd_set_edca_params(hw, q, 436655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_min, 436755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_max, 436855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->aifs, 436955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->txop); 437085c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam } 43713e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 43723e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek mwl8k_fw_unlock(hw); 4373a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 43743e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 4375a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 4376a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4377a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_get_stats(struct ieee80211_hw *hw, 4379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_low_level_stats *stats) 4380a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 438155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_get_stat(hw, stats); 4382a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 43840d462bbb0e20863b6c796abd779bfdb534d60278John W. Linvillestatic int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, 43850d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct survey_info *survey) 43860d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville{ 43870d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct mwl8k_priv *priv = hw->priv; 43880d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct ieee80211_conf *conf = &hw->conf; 43890d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43900d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville if (idx != 0) 43910d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return -ENOENT; 43920d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43930d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->channel = conf->channel; 43940d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->filled = SURVEY_INFO_NOISE_DBM; 43950d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->noise = priv->noise; 43960d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 43970d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return 0; 43980d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville} 43990d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 4400a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekstatic int 4401a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekmwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4402a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek enum ieee80211_ampdu_mlme_action action, 44030b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg struct ieee80211_sta *sta, u16 tid, u16 *ssn, 44040b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg u8 buf_size) 4405a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek{ 4406a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek switch (action) { 4407a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_START: 4408a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_STOP: 4409a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) 4410a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return -ENOTSUPP; 4411a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return 0; 4412a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek default: 4413a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek return -ENOTSUPP; 4414a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek } 4415a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek} 4416a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek 4417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic const struct ieee80211_ops mwl8k_ops = { 4418a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .tx = mwl8k_tx, 4419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .start = mwl8k_start, 4420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .stop = mwl8k_stop, 4421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .add_interface = mwl8k_add_interface, 4422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .remove_interface = mwl8k_remove_interface, 4423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .config = mwl8k_config, 4424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .bss_info_changed = mwl8k_bss_info_changed, 44253ac64beecd27400d12cc7afb4108eef26c499f6aJohannes Berg .prepare_multicast = mwl8k_prepare_multicast, 4426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .configure_filter = mwl8k_configure_filter, 4427fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam .set_key = mwl8k_set_key, 4428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .set_rts_threshold = mwl8k_set_rts_threshold, 44294a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_add = mwl8k_sta_add, 44304a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_remove = mwl8k_sta_remove, 4431a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .conf_tx = mwl8k_conf_tx, 4432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .get_stats = mwl8k_get_stats, 44330d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville .get_survey = mwl8k_get_survey, 4434a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek .ampdu_action = mwl8k_ampdu_action, 4435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 4436a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4437a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_finalize_join_worker(struct work_struct *work) 4438a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = 4440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek container_of(work, struct mwl8k_priv, finalize_join_worker); 4441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb = priv->beacon_skb; 444256007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 444356007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable); 444456007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM, 444556007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mgmt->u.beacon.variable, len); 444656007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int dtim_period = 1; 444756007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg 444856007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg if (tim && tim[1] >= 2) 444956007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg dtim_period = tim[3]; 4450a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 445156007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period); 4452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4453f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek dev_kfree_skb(skb); 4454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = NULL; 4455a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4456a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4457bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linvilleenum { 44589e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8363 = 0, 44599e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8687, 4460bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville MWL8366, 44616f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 44626f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 44638a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define MWL8K_8366_AP_FW_API 2 4464952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" 4465952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) 4466952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo 4467bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linvillestatic struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { 44689e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek [MWL8363] = { 44699e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .part_name = "88w8363", 44709e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .helper_image = "mwl8k/helper_8363.fw", 44710863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8363.fw", 44729e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek }, 447349eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8687] = { 4474bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8687", 4475bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8687.fw", 44760863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8687.fw", 4477bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 447849eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8366] = { 4479bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8366", 4480bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8366.fw", 44810863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8366.fw", 4482952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API), 4483952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_api_ap = MWL8K_8366_AP_FW_API, 448489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .ap_rxd_ops = &rxd_8366_ap_ops, 4485bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 448645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 448745a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 4488c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8363.fw"); 4489c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); 4490c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8687.fw"); 4491c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); 4492c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8366.fw"); 4493c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); 4494952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian CavagnoloMODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); 4495c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert Buytenhek 449645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstatic DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { 4497e5868ba10c3c5d8a56c06bbafe098103356ac03fBenjamin Larsson { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, 44989e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, 44999e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, 4500bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, 4501bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, 4502bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, 4503ca66527c60385dcec878ebd90749d1fdc43bc870Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, 4504bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { }, 450545a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 450645a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert BuytenhekMODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); 450745a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 450899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_alt_fw(struct mwl8k_priv *priv) 450999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 451099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 451199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting preferred fw %s.\n" 451299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo "Trying alternative firmware %s\n", pci_name(priv->pdev), 451399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref, priv->fw_alt); 451499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true); 451599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 451699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 451799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), priv->fw_alt); 451899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 451999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 452099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return 0; 452199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 452299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 452399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv); 452499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context) 452599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 452699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_priv *priv = context; 452799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_device_info *di = priv->device_info; 452899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 452999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 453099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo switch (priv->fw_state) { 453199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_INIT: 453299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 453399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 453499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 453599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 453699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 453799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_helper = fw; 453899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode, 453999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 454099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc && priv->fw_alt) { 454199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 454299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 454399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 454499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 454599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (rc) 454699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 454799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 454899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 454999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 455099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 455199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_PREF: 455299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 455399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_alt) { 455499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 455599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 455699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 455799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 455899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 455999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 456099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else { 456199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 456299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 456399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 456499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 456599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 456699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 456799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 456899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 456999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 457099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_ALT: 457199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 457299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 457399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 457499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 457599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 457699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 457799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 457899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 457999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 458099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 458199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 458299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 458399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 458499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo default: 458599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n", 458699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo MWL8K_NAME, priv->fw_state); 458799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo BUG_ON(1); 458899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 458999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 459099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return; 459199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 459299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolofail: 459399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_ERROR; 459499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 459599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo device_release_driver(&priv->pdev->dev); 459699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 459799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 459899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 459999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, 460099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 4601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 46023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 4603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 4604be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4605be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reset firmware and hardware */ 4606be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 4607be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4608be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Ask userland hotplug daemon for the device firmware */ 460999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_firmware(priv, fw_image, nowait); 4610be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek if (rc) { 46115db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Firmware files not found\n"); 46123cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 4613be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek } 4614be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 461599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 461699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 461799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 4618be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Load firmware into hardware */ 4619be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek rc = mwl8k_load_firmware(hw); 46203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 46215db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot start firmware\n"); 4622be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4623be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reclaim memory once firmware is successfully loaded */ 4624be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_release_firmware(priv); 4625be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 46263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 46273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 46283cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 462973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolostatic int mwl8k_init_txqs(struct ieee80211_hw *hw) 463073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo{ 463173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 463273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo int rc = 0; 463373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo int i; 463473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 463573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) { 463673b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_txq_init(hw, i); 463773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (rc) 463873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo break; 463973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (priv->ap_fw) 464073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo iowrite32(priv->txq[i].txd_dma, 464173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->sram + priv->txq_offset[i]); 464273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo } 464373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return rc; 464473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo} 464573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 46463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* initialize hw after successfully loading a firmware image */ 46473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_probe_hw(struct ieee80211_hw *hw) 46483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 46493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 46503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc = 0; 46513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i; 4652be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 465391942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->ap_fw) { 465489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = priv->device_info->ap_rxd_ops; 465591942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->rxd_ops == NULL) { 4656c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 4657c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "Driver does not have AP firmware image support for this hardware\n"); 465891942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek goto err_stop_firmware; 465991942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 466091942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } else { 466189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = &rxd_sta_ops; 466291942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 4663be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4664be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->sniffer_enabled = false; 4665be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->wmm_enabled = false; 4666be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->pending_tx_pkts = 0; 4667be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_rxq_init(hw, 0); 4669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 46703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 4671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rxq_refill(hw, 0, INT_MAX); 4672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 467373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo /* For the sta firmware, we need to know the dma addresses of tx queues 467473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them 467573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * prior to issuing this command. But for the AP case, we learn the 467673b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * total number of queues from the result CMD_GET_HW_SPEC, so for this 467773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * case we must initialize the tx queues after. 467873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo */ 46798a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = 0; 468073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (!priv->ap_fw) { 468173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_init_txqs(hw); 4682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 4683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 4684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 4687c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 468867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, 46891e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); 4690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 4691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4692a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 4693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 4694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 46955db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 4696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 4697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4699a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Temporarily enable interrupts. Initial firmware host 4701c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek * commands use interrupts and avoid polling. Disable 4702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * interrupts when done. 4703a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 4704c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Get config data, mac addrs etc */ 470742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (priv->ap_fw) { 470842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_ap(hw); 470942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) 471073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_init_txqs(hw); 471173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (!rc) 471242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_set_hw_spec(hw); 471342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } else { 471442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_sta(hw); 471542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 4716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 47175db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot initialise firmware\n"); 4718be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 4719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4720a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Turn radio off */ 472255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_disable(hw); 4723a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 47245db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot disable\n"); 4725be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 4726a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4727a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 472832060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek /* Clear MAC address */ 4729aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); 473032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (rc) { 47315db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot clear MAC address\n"); 4732be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 473332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek } 473432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 4735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 4736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 4738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4739c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", 4740c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->device_info->part_name, 4741c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->hw_rev, hw->wiphy->perm_addr, 4742c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->ap_fw ? "AP" : "STA", 4743c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, 4744c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); 4745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4746a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 4747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_irq: 4749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 4751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_queues: 4753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 4754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 4755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 4756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 47573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_stop_firmware: 47583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_hw_reset(priv); 47593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 47613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 47623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* 47643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * invoke mwl8k_reload_firmware to change the firmware image after the device 47653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * has already been registered 47663cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 47673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) 47683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 47693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc = 0; 47703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 47713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47723cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_stop(hw); 47733cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 47743cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) 47763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 47773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 477899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, fw_image, false); 47793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 47833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_start(hw); 47873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47883cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_config(hw, ~0); 47913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 47943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) { 47953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); 47963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 47973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 47983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 47993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 48013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolofail: 48033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); 48043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 48053cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 48063cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48073cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv) 48083cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 48093cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw = priv->hw; 48103cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc; 48113cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 481299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_load_firmware(hw); 481399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 481499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 481599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wiphy_err(hw->wiphy, "Cannot start firmware\n"); 481699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 481799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 481899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 48193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 48203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * Extra headroom is the size of the required DMA header 48213cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * minus the size of the smallest 802.11 frame (CTS frame). 48223cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 48233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->extra_tx_headroom = 48243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); 48253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->channel_change_time = 10; 48273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48283cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->queues = MWL8K_TX_QUEUES; 48293cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48303cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set rssi values to dBm */ 48310bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; 48323cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->vif_data_size = sizeof(struct mwl8k_vif); 48333cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->sta_data_size = sizeof(struct mwl8k_sta); 48343cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48353cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->macids_used = 0; 48363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_LIST_HEAD(&priv->vif_list); 48373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set default radio state and preamble */ 48393cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->radio_on = 0; 48403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->radio_short_preamble = 0; 48413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48423cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Finalize join worker */ 48433cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); 48443cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* TX reclaim and RX tasklets. */ 48463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); 48473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_tx_task); 48483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); 48493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_rx_task); 48503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Power management cookie */ 48523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); 48533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->cookie == NULL) 48543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return -ENOMEM; 48553cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48563cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mutex_init(&priv->fw_mutex); 48573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_owner = NULL; 48583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_depth = 0; 48593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hostcmd_wait = NULL; 48603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo spin_lock_init(&priv->tx_lock); 48623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->tx_wait = NULL; 48643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 48663cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 48673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_cookie; 48683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes = 0; 48703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->ap_macids_supported || priv->device_info->fw_image_ap) 48713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); 48723cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sta_macids_supported || priv->device_info->fw_image_sta) 48733cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); 48743cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = ieee80211_register_hw(hw); 48763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 48773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot register device\n"); 48783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_unprobe_hw; 48793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 48803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return 0; 48823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 48833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_unprobe_hw: 48843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo for (i = 0; i < MWL8K_TX_QUEUES; i++) 48853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 48863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 48873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 4888be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_free_cookie: 4889a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->cookie != NULL) 4890a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 4, 4891a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->cookie, priv->cookie_dma); 4892a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 48933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 48943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 48953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int __devinit mwl8k_probe(struct pci_dev *pdev, 48963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo const struct pci_device_id *id) 48973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 48983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo static int printed_version; 48993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw; 49003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv; 49010863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 49023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc; 49033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (!printed_version) { 49053cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); 49063cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printed_version = 1; 49073cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49083cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49093cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49103cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_enable_device(pdev); 49113cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 49123cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot enable new PCI device\n", 49133cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 49143cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 49153cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49163cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49173cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_request_regions(pdev, MWL8K_NAME); 49183cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 49193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot obtain PCI resources\n", 49203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 49213cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_disable_device; 49223cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_master(pdev); 49253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); 49283cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (hw == NULL) { 49293cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); 49303cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = -ENOMEM; 49313cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_reg; 49323cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49333cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49343cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo SET_IEEE80211_DEV(hw, &pdev->dev); 49353cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_drvdata(pdev, hw); 49363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv = hw->priv; 49383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hw = hw; 49393cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->pdev = pdev; 49403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->device_info = &mwl8k_info_tbl[id->driver_data]; 49413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49423cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49433cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->sram = pci_iomap(pdev, 0, 0x10000); 49443cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sram == NULL) { 49453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); 49463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 49473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 49503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. 49513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. 49523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 49533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 1, 0x10000); 49543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 49553cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 2, 0x10000); 49563cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 49573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device registers\n"); 49583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 49593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 49613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 49620863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 496399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * Choose the initial fw image depending on user input. If a second 496499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * image is available, make it the alternative image that will be 496599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * loaded if the first one fails. 49660863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 496799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo init_completion(&priv->firmware_loading_complete); 49680863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 496999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (ap_mode_default && di->fw_image_ap) { 497099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 497199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_sta; 497299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (!ap_mode_default && di->fw_image_sta) { 497399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 497499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_ap; 497599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { 49760863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); 497799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 49780863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { 49790863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); 498099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 498199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 498299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, priv->fw_pref, true); 49833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 49843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 498599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 49863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 4987be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_stop_firmware: 4988be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 4989be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 4990be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_iounmap: 4991a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->regs != NULL) 4992a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 4993a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 49945b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek if (priv->sram != NULL) 49955b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 49965b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek 4997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 4998a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 4999a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5000a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_reg: 5001a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 50023db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhek 50033db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhekerr_disable_device: 5004a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 5005a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5006a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 5007a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5008a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5009230f7af0d8f6f2019e64920378b3b66e7d3e99a5Joerg Albertstatic void __devexit mwl8k_shutdown(struct pci_dev *pdev) 5010a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5011a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__); 5012a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5013a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5014230f7af0d8f6f2019e64920378b3b66e7d3e99a5Joerg Albertstatic void __devexit mwl8k_remove(struct pci_dev *pdev) 5015a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5016a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = pci_get_drvdata(pdev); 5017a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv; 5018a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 5019a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5020a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (hw == NULL) 5021a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 5022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv = hw->priv; 5023a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 502499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wait_for_completion(&priv->firmware_loading_complete); 502599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 502699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_state == FW_STATE_ERROR) { 502799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_hw_reset(priv); 502899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto unmap; 502999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 503099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 5031a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 5032a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 503360aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek ieee80211_unregister_hw(hw); 503460aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek 503567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Remove TX reclaim and RX tasklets. */ 50361e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_kill(&priv->poll_tx_task); 503767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_kill(&priv->poll_rx_task); 5038a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5039a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop hardware */ 5040a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_hw_reset(priv); 5041a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5042a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 5043a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 5044efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 5045a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5046a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_QUEUES; i++) 5047a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 5048a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5049a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 5050a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5051c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); 5052a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 505399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolounmap: 5054a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 50555b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 5056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 5057a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 5058a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 5059a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 5060a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5061a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5062a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic struct pci_driver mwl8k_driver = { 5063a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .name = MWL8K_NAME, 506445a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .id_table = mwl8k_pci_id_table, 5065a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .probe = mwl8k_probe, 5066a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .remove = __devexit_p(mwl8k_remove), 5067a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .shutdown = __devexit_p(mwl8k_shutdown), 5068a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 5069a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5070a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int __init mwl8k_init(void) 5071a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5072a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return pci_register_driver(&mwl8k_driver); 5073a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5074a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5075a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void __exit mwl8k_exit(void) 5076a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5077a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unregister_driver(&mwl8k_driver); 5078a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5079a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5080a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmodule_init(mwl8k_init); 5081a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmodule_exit(mwl8k_exit); 5082c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 5083c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_DESCRIPTION(MWL8K_DESC); 5084c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_VERSION(MWL8K_VERSION); 5085c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>"); 5086c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_LICENSE("GPL"); 5087