mwl8k.c revision 751930cb1d6da7b7891d8ffe84877cbf21915e0d
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> 13a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 14a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/module.h> 15a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/kernel.h> 163d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek#include <linux/sched.h> 17a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/spinlock.h> 18a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/list.h> 19a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/pci.h> 20a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/delay.h> 21a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/completion.h> 22a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/etherdevice.h> 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 24a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <net/mac80211.h> 25a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/moduleparam.h> 26a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/firmware.h> 27a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#include <linux/workqueue.h> 28a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 29a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" 30a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_NAME KBUILD_MODNAME 3100e8e69270cc8d5b9db98dcb73d26f21c2539010Yogesh Ashok Powar#define MWL8K_VERSION "0.13" 32a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 330863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo/* Module parameters */ 34eb93992207dadb946a3b5cf4544957dc924a6f58Rusty Russellstatic bool ap_mode_default; 350863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolomodule_param(ap_mode_default, bool, 0); 360863ade8d6bde1d151f75720d999ff27f9fe3533Brian CavagnoloMODULE_PARM_DESC(ap_mode_default, 370863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo "Set to 1 to make ap mode the default instead of sta mode"); 380863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 39a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Register definitions */ 40a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_GEN_PTR 0x00000c10 41ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_MODE_STA 0x0000005a 42ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_MODE_AP 0x000000a5 43a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_INT_CODE 0x00000c14 44ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_FWSTA_READY 0xf0f1f2f4 45ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_FWAP_READY 0xf1f2f4a5 46ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 47a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_SCRATCH 0x00000c40 48a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 49a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Host->device communications */ 50a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_EVENTS 0x00000c18 51a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_STATUS 0x00000c1c 52a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20 53a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24 54a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 55ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_DUMMY (1 << 20) 56ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_RESET (1 << 15) 57ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_DOORBELL (1 << 1) 58ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_H2A_INT_PPA_READY (1 << 0) 59a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 60a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Device->host communications */ 61a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c 62a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_STATUS 0x00000c30 63a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34 64a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 65a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c 66ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_DUMMY (1 << 20) 673aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) 68ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) 69ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) 70ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) 71ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADIO_ON (1 << 6) 72ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) 73ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) 74ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_OPC_DONE (1 << 2) 75ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_RX_READY (1 << 1) 76ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek#define MWL8K_A2H_INT_TX_DONE (1 << 0) 77a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 78566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat/* HW micro second timer register 79566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat * located at offset 0xA600. This 80566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat * will be used to timestamp tx 81566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat * packets. 82566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat */ 83566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat 84566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat#define MWL8K_HW_TIMER_REGISTER 0x0000a600 85566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat 86a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ 87a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_CHNL_SWITCHED | \ 88a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_QUEUE_EMPTY | \ 89a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADAR_DETECT | \ 90a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADIO_ON | \ 91a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RADIO_OFF | \ 92a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_MAC_EVENT | \ 93a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_OPC_DONE | \ 94a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_A2H_INT_RX_READY | \ 953aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam MWL8K_A2H_INT_TX_DONE | \ 963aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam MWL8K_A2H_INT_BA_WATCHDOG) 97a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 98a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_QUEUES 1 99e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo#define MWL8K_TX_WMM_QUEUES 4 1008a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define MWL8K_MAX_AMPDU_QUEUES 8 101e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) 102e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) 103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1047fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar/* txpriorities are mapped with hw queues. 1057fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * Each hw queue has a txpriority. 1067fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar */ 1077fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar#define TOTAL_HW_TX_QUEUES 8 1087fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar 1097fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar/* Each HW queue can have one AMPDU stream. 1107fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * But, because one of the hw queue is reserved, 1117fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * maximum AMPDU queues that can be created are 1127fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * one short of total tx queues. 1137fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar */ 1147fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar#define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1) 1157fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar 11654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstruct rxd_ops { 11754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int rxd_size; 11854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); 11954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); 12020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status, 1210d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise); 12254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 12354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 12445a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstruct mwl8k_device_info { 125a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *part_name; 126a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek char *helper_image; 1270863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_sta; 1280863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo char *fw_image_ap; 12989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct rxd_ops *ap_rxd_ops; 130952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 fw_api_ap; 13145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 13245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 133a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_rx_queue { 13445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int rxd_count; 135a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw receives here */ 13745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 138a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* refill descs here */ 14045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 141a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 14345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t rxd_dma; 144788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct { 145788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek struct sk_buff *skb; 14653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori DEFINE_DMA_UNMAP_ADDR(dma); 147788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek } *buf; 148a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 150a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_queue { 151a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* hw transmits here */ 15245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int head; 153a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* sw appends here */ 15545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek int tail; 156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1578ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo unsigned int len; 15845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct mwl8k_tx_desc *txd; 15945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek dma_addr_t txd_dma; 16045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek struct sk_buff **skb; 161a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 162a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 163ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnoloenum { 164ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo AMPDU_NO_STREAM, 165ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo AMPDU_STREAM_NEW, 166ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo AMPDU_STREAM_IN_PROGRESS, 167ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo AMPDU_STREAM_ACTIVE, 168ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo}; 169ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1705faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstruct mwl8k_ampdu_stream { 1715faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct ieee80211_sta *sta; 1725faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 tid; 1735faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 state; 1745faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 idx; 1755faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam}; 1765faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_priv { 178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw; 179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct pci_dev *pdev; 180bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo int irq; 181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 18245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek struct mwl8k_device_info *device_info; 18345a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 184be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *sram; 185be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek void __iomem *regs; 186be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 187be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* firmware */ 188d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_helper; 189d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw_ucode; 190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 191be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* hardware/firmware parameters */ 192be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek bool ap_fw; 193be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek struct rxd_ops *rxd_ops; 194777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_supported_band band_24; 195777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_channel channels_24[14]; 196777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek struct ieee80211_rate rates_24[14]; 1974eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_supported_band band_50; 1984eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_channel channels_50[4]; 1994eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct ieee80211_rate rates_50[9]; 200ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 ap_macids_supported; 201ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 sta_macids_supported; 202be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 2038a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo /* Ampdu stream information */ 2048a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo u8 num_ampdu_queues; 205ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo spinlock_t stream_lock; 206ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; 2073aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam struct work_struct watchdog_ba_handle; 2088a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo 209618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek /* firmware access */ 210618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mutex fw_mutex; 211618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct task_struct *fw_mutex_owner; 2126b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct task_struct *hw_restart_owner; 213618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int fw_mutex_depth; 214618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct completion *hostcmd_wait; 215618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 216c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar atomic_t watchdog_event_pending; 217c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* lock held over TX and TX reap */ 219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spinlock_t tx_lock; 220a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 22188de754ad59025eba797e7a8375807755577f450Lennert Buytenhek /* TX quiesce completion, protected by fw_mutex and tx_lock */ 22288de754ad59025eba797e7a8375807755577f450Lennert Buytenhek struct completion *tx_wait; 22388de754ad59025eba797e7a8375807755577f450Lennert Buytenhek 224f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* List of interfaces. */ 225ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_used; 226f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head vif_list; 227a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 228a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* power management status cookie from firmware */ 229a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 *cookie; 230a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t cookie_dma; 231a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u16 num_mcaddrs; 233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 hw_rev; 2342aa7b01fe4f2d0978115bfd40364f52d86003606Lennert Buytenhek u32 fw_rev; 235a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 236a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Running count of TX packets in flight, to avoid 238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * iterating over the transmit rings each time. 239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 240a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int pending_tx_pkts; 241a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; 243e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; 244e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo u32 txq_offset[MWL8K_MAX_TX_QUEUES]; 245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 246c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek bool radio_on; 24768ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek bool radio_short_preamble; 248a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek bool sniffer_enabled; 2490439b1f55646ea944b0d58337f5065b79a1c1be0Lennert Buytenhek bool wmm_enabled; 250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* XXX need to convert this to handle multiple interfaces */ 252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek bool capture_beacon; 253d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek u8 capture_bssid[ETH_ALEN]; 254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *beacon_skb; 255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 257a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This FJ worker has to be global as it is scheduled from the 258a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * RX handler. At this point we don't know which interface it 259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * belongs to until the list of bssids waiting to complete join 260a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * is checked. 261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct work_struct finalize_join_worker; 263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2641e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek /* Tasklet to perform TX reclaim. */ 2651e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct tasklet_struct poll_tx_task; 26667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 26767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Tasklet to perform RX. */ 26867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct tasklet_struct poll_rx_task; 2690d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 2700d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville /* Most recently reported noise in dBm */ 2710d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville s8 noise; 2720863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 2730863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 2740863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * preserve the queue configurations so they can be restored if/when 2750863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo * the firmware image is swapped. 2760863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 277e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; 27899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 2796b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* To perform the task of reloading the firmware */ 2806b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct work_struct fw_reload; 2816b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar bool hw_restart_in_progress; 2826b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 28399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* async firmware loading state */ 28499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo unsigned fw_state; 28599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_pref; 28699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo char *fw_alt; 28799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct completion firmware_loading_complete; 288e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 289e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar /* bitmap of running BSSes */ 290e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar u32 running_bsses; 291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 292a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 293e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define MAX_WEP_KEY_LEN 13 294e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam#define NUM_WEP_KEYS 4 295e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Per interface specific private data */ 297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_vif { 298f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct list_head list; 299f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif; 300f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 301f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek /* Firmware macid for this vif. */ 302f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek int macid; 303f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 304c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek /* Non AMPDU sequence number assigned by driver. */ 305a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u16 seqno; 306e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 307e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* Saved WEP keys */ 308e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct { 309e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 enabled; 310e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; 311e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } wep_key_conf[NUM_WEP_KEYS]; 312d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 313d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* BSSID */ 314d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 bssid[ETH_ALEN]; 315d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 316d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* A flag to indicate is HW crypto is enabled for this bssid */ 317d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam bool is_hw_crypto_enabled; 318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 319a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) 320fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) 321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 322d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolostruct tx_traffic_info { 323d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo u32 start_time; 324d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo u32 pkts; 325d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo}; 326d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 327d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo#define MWL8K_MAX_TID 8 328a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstruct mwl8k_sta { 329a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek /* Index into station database. Returned by UPDATE_STADB. */ 330a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek u8 peer_id; 331170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam u8 is_ampdu_allowed; 332d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; 333a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek}; 334a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) 335a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 336777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_24[] = { 337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2412, .hw_value = 1, }, 338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2417, .hw_value = 2, }, 339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2422, .hw_value = 3, }, 340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2427, .hw_value = 4, }, 341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2432, .hw_value = 5, }, 342a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2437, .hw_value = 6, }, 343a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2442, .hw_value = 7, }, 344a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2447, .hw_value = 8, }, 345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2452, .hw_value = 9, }, 346a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2457, .hw_value = 10, }, 347a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .center_freq = 2462, .hw_value = 11, }, 348647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2467, .hw_value = 12, }, 349647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2472, .hw_value = 13, }, 350647ca6b01a5289948e970ea7c1f656f9d90b0a27Lennert Buytenhek { .center_freq = 2484, .hw_value = 14, }, 351a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 352a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 353777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_24[] = { 354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 10, .hw_value = 2, }, 355a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 20, .hw_value = 4, }, 356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 55, .hw_value = 11, }, 3575dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 110, .hw_value = 22, }, 3585dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0Lennert Buytenhek { .bitrate = 220, .hw_value = 44, }, 359a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 361a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 365a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 366a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 367140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 368140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek}; 369140eb5e2c1978622d7cd979d59a1c0586fe3bbdbLennert Buytenhek 3704eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_channel mwl8k_channels_50[] = { 3714eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5180, .hw_value = 36, }, 3724eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5200, .hw_value = 40, }, 3734eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5220, .hw_value = 44, }, 3744eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .center_freq = 5240, .hw_value = 48, }, 3754eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3764eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 3774eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic const struct ieee80211_rate mwl8k_rates_50[] = { 3784eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 60, .hw_value = 12, }, 3794eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 90, .hw_value = 18, }, 3804eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 120, .hw_value = 24, }, 3814eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 180, .hw_value = 36, }, 3824eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 240, .hw_value = 48, }, 3834eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 360, .hw_value = 72, }, 3844eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 480, .hw_value = 96, }, 3854eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 540, .hw_value = 108, }, 3864eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek { .bitrate = 720, .hw_value = 144, }, 3874eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek}; 3884eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Set or get info from Firmware */ 390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET 0x0000 39141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET 0x0001 39241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_SET_LIST 0x0002 393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Firmware command codes */ 395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_CODE_DNLD 0x0001 396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_HW_SPEC 0x0003 39742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek#define MWL8K_CMD_SET_HW_SPEC 0x0004 398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_GET_STAT 0x0014 400ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RADIO_CONTROL 0x001c 401ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RF_TX_POWER 0x001e 40241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_CMD_TX_POWER 0x001f 40308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_CMD_RF_ANTENNA 0x0020 404aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ 405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_PRE_SCAN 0x0107 406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_POST_SCAN 0x0108 407ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RF_CHANNEL 0x010a 408ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_AID 0x010d 409ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_RATE 0x0110 410ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 411ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_RTS_THRESHOLD 0x0113 412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_SLOT 0x0114 413ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 414ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_SET_WMM_MODE 0x0123 415a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_MIMO_CONFIG 0x0125 416ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_USE_FIXED_RATE 0x0126 417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 418aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ 419a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 4203aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 421197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar#define MWL8K_CMD_DEL_MAC_ADDR 0x0206 /* per-vif */ 422aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ 423aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ 424fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ 425ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek#define MWL8K_CMD_UPDATE_STADB 0x1123 4265faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam#define MWL8K_CMD_BASTREAM 0x1125 427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 428b603742f49c3ec922522602e18ac22e8f6835132John W. Linvillestatic const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) 429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 430b603742f49c3ec922522602e18ac22e8f6835132John W. Linville u16 command = le16_to_cpu(cmd); 431b603742f49c3ec922522602e18ac22e8f6835132John W. Linville 432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_CMDNAME(x) case MWL8K_CMD_##x: do {\ 433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "%s", #x);\ 434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf;\ 435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (0) 436b603742f49c3ec922522602e18ac22e8f6835132John W. Linville switch (command & ~0x8000) { 437a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(CODE_DNLD); 438a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_HW_SPEC); 43942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek MWL8K_CMDNAME(SET_HW_SPEC); 440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MAC_MULTICAST_ADR); 441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(GET_STAT); 442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RADIO_CONTROL); 443a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(RF_TX_POWER); 44441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam MWL8K_CMDNAME(TX_POWER); 44508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek MWL8K_CMDNAME(RF_ANTENNA); 446b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(SET_BEACON); 447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_PRE_SCAN); 448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_POST_SCAN); 449a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RF_CHANNEL); 450ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_AID); 451ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_RATE); 452ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_FINALIZE_JOIN); 453ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(RTS_THRESHOLD); 454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_SLOT); 455ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_EDCA_PARAMS); 456ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(SET_WMM_MODE); 457a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(MIMO_CONFIG); 458ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(USE_FIXED_RATE); 459a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(ENABLE_SNIFFER); 46032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek MWL8K_CMDNAME(SET_MAC_ADDR); 461a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_CMDNAME(SET_RATEADAPT_MODE); 462b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_CMDNAME(BSS_START); 4633f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek MWL8K_CMDNAME(SET_NEW_STN); 464fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_CMDNAME(UPDATE_ENCRYPTION); 465ff45fc60ad583f45ecf10a41f7dbecf78519bcc1Lennert Buytenhek MWL8K_CMDNAME(UPDATE_STADB); 4665faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_CMDNAME(BASTREAM); 4673aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); 468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek default: 469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek snprintf(buf, bufsize, "0x%x", cmd); 470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#undef MWL8K_CMDNAME 472a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return buf; 474a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Hardware and firmware reset */ 477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_hw_reset(struct mwl8k_priv *priv) 478a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 479a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 480a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 481a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_RESET, 482a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 483a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msleep(20); 484a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 485a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 486a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Release fw image */ 487d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolostatic void mwl8k_release_fw(const struct firmware **fw) 488a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw == NULL) 490a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek release_firmware(*fw); 492a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek *fw = NULL; 493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 494a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_release_firmware(struct mwl8k_priv *priv) 496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 49722be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_ucode); 49822be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 500a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 50199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo/* states for asynchronous f/w loading */ 50299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context); 50399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnoloenum { 50499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_INIT = 0, 50599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_PREF, 50699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_LOADING_ALT, 50799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo FW_STATE_ERROR, 50899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo}; 50999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 510a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Request fw image */ 511a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_request_fw(struct mwl8k_priv *priv, 512d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const char *fname, const struct firmware **fw, 51399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 514a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* release current image */ 516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (*fw != NULL) 517a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_release_fw(fw); 518a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 51999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 52099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return request_firmware_nowait(THIS_MODULE, 1, fname, 52199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->pdev->dev, GFP_KERNEL, 52299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv, mwl8k_fw_state_machine); 52399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 524d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo return request_firmware(fw, fname, &priv->pdev->dev); 525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 52799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, 52899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 529a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 530a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek struct mwl8k_device_info *di = priv->device_info; 531a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 533a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek if (di->helper_image != NULL) { 53499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 53599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 53699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, true); 53799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 53899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, di->helper_image, 53999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_helper, false); 54099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 54199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 54299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 54399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 54499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc || nowait) 545a74b295edb3e2b39d6c03255b24dca862a843c59Lennert Buytenhek return rc; 546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 54899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) { 54999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo /* 55099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * if we get here, no helper image is needed. Skip the 55199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * FW_STATE_INIT state. 55299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo */ 55399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 55499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 55599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, 55699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 55799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 55899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, fw_image, 55999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo &priv->fw_ucode, false); 560a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 561c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: Error requesting firmware file %s\n", 5620863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo pci_name(priv->pdev), fw_image); 56322be40d9c53faa10d03a679160e0854ad115b610Lennert Buytenhek mwl8k_release_fw(&priv->fw_helper); 564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 565a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 566a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 569a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 570a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_pkt { 571a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 code; 572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 length; 573f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 seq_num; 574f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek __u8 macid; 575a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 result; 576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek char payload[0]; 577ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 578a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 579a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 580a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware loading. 581a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 582a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 583a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) 584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 586a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int loops; 588a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 589a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); 590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 591a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 592a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 594a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 595a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 596a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 597a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 599a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 600a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek loops = 1000; 601a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 602a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 int_code; 603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int_code = ioread32(regs + MWL8K_HIU_INT_CODE); 605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { 606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, regs + MWL8K_HIU_INT_CODE); 607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 609a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6103d76e82c9538d8104e578ca460d35f214bfddfd3Lennert Buytenhek cond_resched(); 611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 612a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 613a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); 615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 616d4b7057052236e81ab0788cc8df306dc02b0e7beLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 617a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 618a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 619a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_load_fw_image(struct mwl8k_priv *priv, 620a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 621a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 622a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt *cmd; 623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int done; 624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc = 0; 625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 626a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kmalloc(sizeof(*cmd) + 256, GFP_KERNEL); 627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); 631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->seq_num = 0; 632f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = 0; 633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->result = 0; 634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 636a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (length) { 637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int block_size = length > 256 ? 256 : length; 638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(cmd->payload, data + done, block_size); 640a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = cpu_to_le16(block_size); 641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, 643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek sizeof(*cmd) + block_size); 644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += block_size; 648a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= block_size; 649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->length = 0; 653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, cmd, sizeof(*cmd)); 654a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 656a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 657a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 658a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 659a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 660a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 661a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_feed_fw_image(struct mwl8k_priv *priv, 662a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const u8 *data, size_t length) 663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned char *buffer; 665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int may_continue, rc = 0; 666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 done, prev_block_size; 667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek buffer = kmalloc(1024, GFP_KERNEL); 669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (buffer == NULL) 670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done = 0; 673a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = 0; 674a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue = 1000; 675a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek while (may_continue > 0) { 676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 block_size; 677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size = ioread32(priv->regs + MWL8K_HIU_SCRATCH); 679a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size & 1) { 680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek block_size &= ~1; 681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek done += prev_block_size; 684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek length -= prev_block_size; 685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size > 1024 || block_size > length) { 688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EOVERFLOW; 689a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (length == 0) { 693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = 0; 694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 695a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (block_size == 0) { 698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EPROTO; 699a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek may_continue--; 700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek continue; 702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 703a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek prev_block_size = block_size; 705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memcpy(buffer, data + done, block_size); 706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_send_fw_load_cmd(priv, buffer, block_size); 708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc && length != 0) 713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -EREMOTEIO; 714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(buffer); 716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 720c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhekstatic int mwl8k_load_firmware(struct ieee80211_hw *hw) 721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 722c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 723d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *fw = priv->fw_ucode; 724c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int rc; 725c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek int loops; 726c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 727c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { 728d1f9e41d1d739cd4393840d35e7554f4a439a4f1Brian Cavagnolo const struct firmware *helper = priv->fw_helper; 729a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 730c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek if (helper == NULL) { 731c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: helper image needed but none " 732c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "given\n", pci_name(priv->pdev)); 733c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek return -EINVAL; 734c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek } 735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 736c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, helper->data, helper->size); 737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware " 739c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek "helper image\n", pci_name(priv->pdev)); 740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 742ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar msleep(20); 743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 744c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); 745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 746c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek rc = mwl8k_load_fw_image(priv, fw->data, fw->size); 747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 750c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek printk(KERN_ERR "%s: unable to load firmware image\n", 751c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_name(priv->pdev)); 752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 75589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); 756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 75789b872e2e476833cde8aaac658c75817f67e8f81Lennert Buytenhek loops = 500000; 758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek do { 759eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek u32 ready_code; 760eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 761eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); 762eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek if (ready_code == MWL8K_FWAP_READY) { 7633db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell priv->ap_fw = true; 764eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek break; 765eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } else if (ready_code == MWL8K_FWSTA_READY) { 7663db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell priv->ap_fw = false; 767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 768eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek } 769eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek 770eae74e6545d995ab0baa8fb07309f714d9616293Lennert Buytenhek cond_resched(); 771a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek udelay(1); 772a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } while (--loops); 773a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 774a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return loops ? 0 : -ETIMEDOUT; 775a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 776a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 777a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 778a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* DMA header used by firmware and hardware. */ 779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_dma_data { 780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 fwlen; 781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr wh; 78220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek char data[0]; 783ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 784a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 785a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Routines to add/remove DMA header from skb. */ 78620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhekstatic inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) 787a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 78820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek struct mwl8k_dma_data *tr; 78920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek int hdrlen; 79020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 79120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 79220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek hdrlen = ieee80211_hdrlen(tr->wh.frame_control); 79320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 79420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(tr->wh)) { 79520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (ieee80211_is_data_qos(tr->wh.frame_control)) { 79620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen - 2); 79720f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *((__le16 *)(tr->data - 2)) = qos; 79820f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } else { 79920f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek memmove(tr->data - hdrlen, &tr->wh, hdrlen); 80020f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek } 801a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 80220f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 80320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek if (hdrlen != sizeof(*tr)) 80420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek skb_pull(skb, sizeof(*tr) - hdrlen); 805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 807ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar#define REDUCED_TX_HEADROOM 8 808ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 809252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadamstatic void 810e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powarmwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, 811e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar int head_pad, int tail_pad) 812a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 814ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek int hdrlen; 815252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam int reqd_hdrlen; 816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_dma_data *tr; 817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 818ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek /* 819ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * Add a firmware DMA header; the firmware requires that we 820ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * present a 2-byte payload length followed by a 4-address 821ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * header (without QoS field), followed (optionally) by any 822ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek * WEP/ExtIV header (but only filled in for CCMP). 823ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek */ 824a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 825ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek 826a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek hdrlen = ieee80211_hdrlen(wh->frame_control); 827ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 828ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar /* 829ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar * Check if skb_resize is required because of 830ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar * tx_headroom adjustment. 831ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar */ 832ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) 833ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar + REDUCED_TX_HEADROOM))) { 834ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { 835ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 836ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar wiphy_err(priv->hw->wiphy, 837ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar "Failed to reallocate TX buffer\n"); 838ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar return; 839ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar } 840ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar skb->truesize += REDUCED_TX_HEADROOM; 841ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar } 842ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 843e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar reqd_hdrlen = sizeof(*tr) + head_pad; 844252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam 845252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam if (hdrlen != reqd_hdrlen) 846252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam skb_push(skb, reqd_hdrlen - hdrlen); 847a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 848ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 849252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam hdrlen -= IEEE80211_QOS_CTL_LEN; 850a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 851a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tr = (struct mwl8k_dma_data *)skb->data; 852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (wh != &tr->wh) 853a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memmove(&tr->wh, wh, hdrlen); 854ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek if (hdrlen != sizeof(tr->wh)) 855ca00930153c14b323c31b97623ac5c4f7855ed6aLennert Buytenhek memset(((void *)&tr->wh) + hdrlen, 0, sizeof(tr->wh) - hdrlen); 856a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 857a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 858a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Firmware length is the length of the fully formed "802.11 859a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * payload". That is, everything except for the 802.11 header. 860a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * This includes all crypto material including the MIC. 861a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 862252486a13a36e2846ff046c18aae67658692ecedNishant Sarmukadam tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); 863a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 864a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 865ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powarstatic void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, 866ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar struct sk_buff *skb) 867e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam{ 868e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_hdr *wh; 869e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_tx_info *tx_info; 870e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam struct ieee80211_key_conf *key_conf; 871e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam int data_pad; 872e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar int head_pad = 0; 873e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 874e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam wh = (struct ieee80211_hdr *)skb->data; 875e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 876e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam tx_info = IEEE80211_SKB_CB(skb); 877e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 878e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = NULL; 879e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (ieee80211_is_data(wh->frame_control)) 880e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam key_conf = tx_info->control.hw_key; 881e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam 882e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam /* 883e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * Make sure the packet header is in the DMA header format (4-address 884e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar * without QoS), and add head & tail padding when HW crypto is enabled. 885e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * 886e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * We have the following trailer padding requirements: 887e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - WEP: 4 trailer bytes (ICV) 888e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - TKIP: 12 trailer bytes (8 MIC + 4 ICV) 889e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam * - CCMP: 8 trailer bytes (MIC) 890e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam */ 891e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 0; 892e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam if (key_conf != NULL) { 893e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar head_pad = key_conf->iv_len; 894e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam switch (key_conf->cipher) { 895e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 896e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 897e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 4; 898e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 899e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 900e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 12; 901e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 902e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 903e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam data_pad = 8; 904e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam break; 905e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 906e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam } 907e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar mwl8k_add_dma_header(priv, skb, head_pad, data_pad); 908e53d9b964e2568172149d41b3157af9cde9accafNishant Sarmukadam} 909a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 910a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 91189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for 88w8366 AP firmware. 9126f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek */ 91389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_8366_ap { 9146f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 pkt_len; 9156f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 sq2; 9166f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rate; 9176f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 pkt_phys_addr; 9186f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 next_rxd_phys_addr; 9196f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 qos_control; 9206f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le16 htsig2; 9216f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_rssi_info; 9226f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __le32 hw_noise_floor_info; 9236f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 noise_floor; 9246f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 pad0[3]; 9256f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rssi; 9266f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_status; 9276f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 channel; 9286f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek __u8 rx_ctrl; 929ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 9306f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 93189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80 93289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40 93389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f) 9348e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek 93589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 9366f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 937d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* 8366 AP rx_status bits */ 938d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 939d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF 940d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 941d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 942d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 943d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 94489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) 9456f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 94689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 9476f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9486f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 94989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST; 9506f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9516f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 95289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len) 9536f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 95489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 9556f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9566f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 9576f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 9586f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek wmb(); 9596f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rxd->rx_ctrl = 0; 9606f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 9616f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9626f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhekstatic int 96389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, 9640d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 9656f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek{ 96689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_8366_ap *rxd = _rxd; 9676f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 96889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST)) 9696f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return -1; 9706f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek rmb(); 9716f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9726f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 9736f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 9746f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->signal = -rxd->rssi; 9750d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_floor; 9766f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 97789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) { 9786f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 97989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ) 9808e9f33f0ced82a797d285b233e1c956cbd5c7de3Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 98189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate); 9826f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } else { 9836f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek int i; 9846f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 985777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { 986777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek if (mwl8k_rates_24[i].hw_value == rxd->rate) { 9876f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek status->rate_idx = i; 9886f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek break; 9896f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9906f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9916f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek } 9926f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 993854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 994854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 995854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 996854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 997854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 998854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 999854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 100059eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 100159eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 10026f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 100320f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 100420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 1005d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && 1006d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && 1007d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) 1008d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 1009d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 10106f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 10116f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek} 10126f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 101389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_8366_ap_ops = { 101489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_8366_ap), 101589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_8366_ap_init, 101689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_8366_ap_refill, 101789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_8366_ap_process, 10186f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 10196f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 10206f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek/* 102189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek * Packet reception for STA firmware. 1022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 102389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstruct mwl8k_rxd_sta { 1024a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 1025a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 link_quality; 1026a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 noise_level; 1027a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 102845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_rxd_phys_addr; 1029a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 1030a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 1031a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pad0[4]; 1032a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rssi; 1033a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 channel; 1034a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pad1; 1035a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_ctrl; 1036a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 rx_status; 1037a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 pad2[2]; 1038ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1039a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 104089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000 104189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) 104289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) 104389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_40MHZ 0x0004 104489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_SHORTGI 0x0002 104589a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 104654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 104789a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 1048d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 1049d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* ICV=0 or MIC=1 */ 1050d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 1051d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam/* Key is uploaded only in failure case */ 1052d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam#define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 105354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 105489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) 105554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 105689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 105754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 105854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); 105989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST; 106054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 106154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 106289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len) 106354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 106489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 106554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 106654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_len = cpu_to_le16(len); 106754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->pkt_phys_addr = cpu_to_le32(addr); 106854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek wmb(); 106954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd->rx_ctrl = 0; 107054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 107154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 107254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhekstatic int 107389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekmwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, 10740d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville __le16 *qos, s8 *noise) 107554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek{ 107689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek struct mwl8k_rxd_sta *rxd = _rxd; 107754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek u16 rate_info; 107854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 107989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST)) 108054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return -1; 108154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rmb(); 108254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 108354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rate_info = le16_to_cpu(rxd->rate_info); 108454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 108554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek memset(status, 0, sizeof(*status)); 108654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 108754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->signal = -rxd->rssi; 10880d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville *noise = -rxd->noise_level; 108989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info); 109089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); 109154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 109289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) 109354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORTPRE; 109489a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) 109554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_40MHZ; 109689a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) 109754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_SHORT_GI; 109889a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) 109954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek status->flag |= RX_FLAG_HT; 110054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1101854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (rxd->channel > 14) { 1102854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_5GHZ; 1103854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek if (!(status->flag & RX_FLAG_HT)) 1104854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->rate_idx -= 5; 1105854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } else { 1106854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek status->band = IEEE80211_BAND_2GHZ; 1107854783444bab0024556c0aefdb0a860f2f1da286Lennert Buytenhek } 110859eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->freq = ieee80211_channel_to_frequency(rxd->channel, 110959eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf status->band); 111054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 111120f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek *qos = rxd->qos_control; 1112d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && 1113d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) 1114d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status->flag |= RX_FLAG_MMIC_ERROR; 111520f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek 111654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek return le16_to_cpu(rxd->pkt_len); 111754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek} 111854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 111989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhekstatic struct rxd_ops rxd_sta_ops = { 112089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_size = sizeof(struct mwl8k_rxd_sta), 112189a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_init = mwl8k_rxd_sta_init, 112289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_refill = mwl8k_rxd_sta_refill, 112389a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .rxd_process = mwl8k_rxd_sta_process, 112454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek}; 112554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 112654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1127a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_DESCS 256 1128a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_RX_MAXSZ 3800 1129a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1130a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) 1131a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1132a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1133a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1134a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1135a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 113745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count = 0; 113845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->head = 0; 113945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->tail = 0; 1140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 114154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size; 1142a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 114345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); 114445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (rxq->rxd == NULL) { 11455db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX descriptors\n"); 1146a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1147a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 114845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(rxq->rxd, 0, size); 1149a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1150b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL); 1151788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf == NULL) { 11525db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); 115345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); 1154a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1155a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1156a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1157a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 115854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int desc_size; 115954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1160a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 116154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek dma_addr_t next_dma_addr; 116254bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 116354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek desc_size = priv->rxd_ops->rxd_size; 116454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size); 1165a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 116654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = i + 1; 116754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (nexti == MWL8K_RX_DESCS) 116854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek nexti = 0; 116954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek next_dma_addr = rxq->rxd_dma + (nexti * desc_size); 1170a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 117154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_init(rxd, next_dma_addr); 1172a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1175a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_refill(struct ieee80211_hw *hw, int index, int limit) 1178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int refilled; 1182a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1183a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled = 0; 118445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { 1185a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1186788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek dma_addr_t addr; 1187a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rx; 118854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 1189a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb = dev_alloc_skb(MWL8K_RX_MAXSZ); 1191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (skb == NULL) 1192a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1194788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek addr = pci_map_single(priv->pdev, skb->data, 1195788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); 1196a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 119754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->rxd_count++; 119854bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rx = rxq->tail++; 119954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->tail == MWL8K_RX_DESCS) 120054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->tail = 0; 1201788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rx].skb = skb; 120253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rx], dma, addr); 120354bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 120454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size); 120554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ); 1206a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1207a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek refilled++; 1208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1209a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return refilled; 1211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* Must be called only when the card's reception is completely halted */ 1214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) 1215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 122073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (rxq->rxd == NULL) 122173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return; 122273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 1223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_RX_DESCS; i++) { 1224788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek if (rxq->buf[i].skb != NULL) { 1225788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 122653b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[i], dma), 1227788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 122853b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[i], dma, 0); 1229788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1230788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree_skb(rxq->buf[i].skb); 1231788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[i].skb = NULL; 1232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1233a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1235788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek kfree(rxq->buf); 1236788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf = NULL; 1237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 123954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek MWL8K_RX_DESCS * priv->rxd_ops->rxd_size, 124045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd, rxq->rxd_dma); 124145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd = NULL; 1242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Scan a list of BSSIDs to process for finalize join. 1247a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Allows for extension to process multiple BSSIDs. 1248a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1249a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline int 1250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) 1251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return priv->capture_beacon && 1253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_is_beacon(wh->frame_control) && 12542e42e4747ea72943c21551d8a206b51a9893b1e0Joe Perches ether_addr_equal(wh->addr3, priv->capture_bssid); 1255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 12573779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhekstatic inline void mwl8k_save_beacon(struct ieee80211_hw *hw, 12583779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct sk_buff *skb) 1259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 12603779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 12613779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek 1262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = false; 1263d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memset(priv->capture_bssid, 0, ETH_ALEN); 1264a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1266a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Use GFP_ATOMIC as rxq_process is called from 1267a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * the primary interrupt handler, memory allocation call 1268a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * must not sleep. 1269a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1270a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); 1271a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 12723779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek ieee80211_queue_work(hw, &priv->finalize_join_worker); 1273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1274a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1275d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadamstatic inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, 1276d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam u8 *bssid) 1277d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam{ 1278d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif; 1279d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1280d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam list_for_each_entry(mwl8k_vif, 1281d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam vif_list, list) { 1282d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (memcmp(bssid, mwl8k_vif->bssid, 1283d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ETH_ALEN) == 0) 1284d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return mwl8k_vif; 1285d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1286d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1287d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam return NULL; 1288d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam} 1289d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1290a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int rxq_process(struct ieee80211_hw *hw, int index, int limit) 1291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1292a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1293d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_vif *mwl8k_vif = NULL; 1294a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_rx_queue *rxq = priv->rxq + index; 1295a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int processed; 1296a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed = 0; 129845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek while (rxq->rxd_count && limit--) { 1299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 130054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek void *rxd; 130154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek int pkt_len; 1302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_rx_status status; 1303d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct ieee80211_hdr *wh; 130420f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek __le16 qos; 1305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1306788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek skb = rxq->buf[rxq->head].skb; 1307d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek if (skb == NULL) 1308d25f9f1357139bbdc79bc960ea84909a7c22ec2bLennert Buytenhek break; 130954bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 131054bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); 131154bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 13120d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos, 13130d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville &priv->noise); 131454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (pkt_len < 0) 131554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek break; 131654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 1317788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek rxq->buf[rxq->head].skb = NULL; 1318788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek 1319788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek pci_unmap_single(priv->pdev, 132053b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr(&rxq->buf[rxq->head], dma), 1321788838ebe8a4caca93a91982c7bbf393edf24c08Lennert Buytenhek MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 132253b1b3e1f0feaa57b82d3dc344d887fe3eecc90bFUJITA Tomonori dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); 1323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 132454bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head++; 132554bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (rxq->head == MWL8K_RX_DESCS) 132654bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek rxq->head = 0; 132754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek 132845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek rxq->rxd_count--; 1329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1330d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 1333c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * Check for a pending join operation. Save a 1334c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * copy of the beacon and schedule a tasklet to 1335c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek * send a FINALIZE_JOIN command to the firmware. 1336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 133754bc3a0d7a0c9a13da31183609c42cf7786138e1Lennert Buytenhek if (mwl8k_capture_bssid(priv, (void *)skb->data)) 13383779752d764b86077375510b1fd13d8fb2c7c3a5Lennert Buytenhek mwl8k_save_beacon(hw, skb); 1339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1340d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (ieee80211_has_protected(wh->frame_control)) { 1341d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1342d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* Check if hw crypto has been enabled for 1343d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * this bss. If yes, set the status flags 1344d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * accordingly 1345d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1346d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, 1347d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam wh->addr1); 1348d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1349d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif != NULL && 135023677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches mwl8k_vif->is_hw_crypto_enabled) { 1351d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam /* 1352d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * When MMIC ERROR is encountered 1353d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * by the firmware, payload is 1354d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * dropped and only 32 bytes of 1355d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * mwl8k Firmware header is sent 1356d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * to the host. 1357d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 1358d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * We need to add four bytes of 1359d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * key information. In it 1360d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * MAC80211 expects keyidx set to 1361d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * 0 for triggering Counter 1362d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam * Measure of MMIC failure. 1363d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam */ 1364d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (status.flag & RX_FLAG_MMIC_ERROR) { 1365d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam struct mwl8k_dma_data *tr; 1366d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam tr = (struct mwl8k_dma_data *)skb->data; 1367d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memset((void *)&(tr->data), 0, 4); 1368d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam pkt_len += 4; 1369d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1370d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1371d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (!ieee80211_is_auth(wh->frame_control)) 1372d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam status.flag |= RX_FLAG_IV_STRIPPED | 1373d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_DECRYPTED | 1374d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam RX_FLAG_MMIC_STRIPPED; 1375d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1376d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 1377d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 1378d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam skb_put(skb, pkt_len); 1379d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_remove_dma_header(skb, qos); 1380f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); 1381f1d58c2521eb160178b2151d6326d8dc5d7c8560Johannes Berg ieee80211_rx_irqsafe(hw, skb); 1382a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek processed++; 1384a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return processed; 1387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1388a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 1391a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Packet transmission. 1392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 1393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK 0x00000001 1395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 1396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 1397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 1398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 1399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1400e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_QLEN_UNSPEC 0xff00 1401e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_MASK 0x0060 1402e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_NORMAL 0x0000 1403e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_ACK_POLICY_BLOCKACK 0x0060 1404e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek#define MWL8K_QOS_EOSP 0x0010 1405e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek 1406a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_tx_desc { 1407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 status; 1408a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 data_rate; 1409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 tx_priority; 1410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 qos_control; 1411a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 pkt_phys_addr; 1412a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 pkt_len; 1413d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 dest_MAC_addr[ETH_ALEN]; 141445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 next_txd_phys_addr; 14158a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 timestamp; 1416a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 rate_info; 1417a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 peer_id; 1418a1fe24b0fd8bf16b4e551ae3fb785bfc574b9ffbBrian Cavagnolo __u8 tx_frag_cnt; 1419ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_TX_DESCS 128 1422a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_txq_init(struct ieee80211_hw *hw, int index) 1424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int size; 1428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 1429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14308ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len = 0; 143145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = 0; 143245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 1433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); 1435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 143645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); 143745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->txd == NULL) { 14385db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX descriptors\n"); 1439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 144145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek memset(txq->txd, 0, size); 1442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1443b9ede5f1dc03f96949dcaa8f8b3483766c047260Shan Wei txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL); 144445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->skb == NULL) { 14455db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); 144645eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); 1447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 1448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1449a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1450a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (i = 0; i < MWL8K_TX_DESCS; i++) { 1451a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int nexti; 1453a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 145445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + i; 1455a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek nexti = (i + 1) % MWL8K_TX_DESCS; 1456a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1457a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status = 0; 145845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc->next_txd_phys_addr = 145945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc)); 1460a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1461a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1462a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 1463a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1464a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1465a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic inline void mwl8k_tx_start(struct mwl8k_priv *priv) 1466a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1467a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_PPA_READY, 1468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 1470a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 1471a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ioread32(priv->regs + MWL8K_HIU_INT_CODE); 1472a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14747e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhekstatic void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) 1475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 14767e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 14777e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int i; 14787e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1479e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) { 14807e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + i; 14817e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int fw_owned = 0; 14827e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int drv_owned = 0; 14837e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int unused = 0; 14847e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int desc; 14857e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1486a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { 14877e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek struct mwl8k_tx_desc *tx_desc = txq->txd + desc; 14887e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek u32 status; 1489a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 14907e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek status = le32_to_cpu(tx_desc->status); 1491a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) 14927e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek fw_owned++; 1493a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek else 14947e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek drv_owned++; 1495a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1496a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_desc->pkt_len == 0) 14977e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unused++; 1498a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1499a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1500c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 1501c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "txq[%d] len=%d head=%d tail=%d " 1502c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "fw_owned=%d drv_owned=%d unused=%d\n", 1503c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches i, 1504c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches txq->len, txq->head, txq->tail, 1505c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches fw_owned, drv_owned, unused); 15067e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 1507a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1508a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1509618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 151088de754ad59025eba797e7a8375807755577f450Lennert Buytenhek * Must be called with priv->fw_mutex held and tx queues stopped. 1511618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 151262abd3cfb2f1a0ab1963ac4c4087c477da6b1f2aLennert Buytenhek#define MWL8K_TX_WAIT_TIMEOUT_MS 5000 15137e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1514950d5b0191dc3e71017f336017f75f6189f39f08Lennert Buytenhekstatic int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) 1515a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1516a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 151788de754ad59025eba797e7a8375807755577f450Lennert Buytenhek DECLARE_COMPLETION_ONSTACK(tx_wait); 15187e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int retry; 15197e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int rc; 1520a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1521a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek might_sleep(); 1522a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 15236b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* Since fw restart is in progress, allow only the firmware 15246b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * commands from the restart code and block the other 15256b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * commands since they are going to fail in any case since 15266b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * the firmware has crashed 15276b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 15286b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->hw_restart_in_progress) { 15296b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->hw_restart_owner == current) 15306b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar return 0; 15316b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar else 15326b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar return -EBUSY; 15336b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar } 15346b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 1535c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar if (atomic_read(&priv->watchdog_event_pending)) 1536c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar return 0; 1537c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 15387e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek /* 15397e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * The TX queues are stopped at this point, so this test 15407e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek * doesn't need to take ->tx_lock. 15417e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek */ 15427e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (!priv->pending_tx_pkts) 15437e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return 0; 15447e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 15457e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 0; 15467e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = 0; 15477e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 15497e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek priv->tx_wait = &tx_wait; 15507e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek while (!rc) { 15517e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek int oldcount; 15527e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek unsigned long timeout; 1553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 15547e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek oldcount = priv->pending_tx_pkts; 1555a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 15567e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 155788de754ad59025eba797e7a8375807755577f450Lennert Buytenhek timeout = wait_for_completion_timeout(&tx_wait, 15587e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS)); 1559c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 1560c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar if (atomic_read(&priv->watchdog_event_pending)) { 1561c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar spin_lock_bh(&priv->tx_lock); 1562c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar priv->tx_wait = NULL; 1563c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar spin_unlock_bh(&priv->tx_lock); 1564c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar return 0; 1565c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar } 1566c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 1567a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_lock_bh(&priv->tx_lock); 15687e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 15697e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (timeout) { 15707e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek WARN_ON(priv->pending_tx_pkts); 1571ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar if (retry) 1572c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, "tx rings drained\n"); 15737e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek break; 15747e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 15757e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 15767e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek if (priv->pending_tx_pkts < oldcount) { 1577c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_notice(hw->wiphy, 1578c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "waiting for tx rings to drain (%d -> %d pkts)\n", 1579c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches oldcount, priv->pending_tx_pkts); 15807e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek retry = 1; 15817e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek continue; 15827e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek } 15837e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 1584a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->tx_wait = NULL; 1585a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1586c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n", 1587c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_TX_WAIT_TIMEOUT_MS); 15887e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek mwl8k_dump_tx_rings(hw); 15896b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hw_restart_in_progress = true; 15906b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar ieee80211_queue_work(hw, &priv->fw_reload); 15917e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek 15927e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek rc = -ETIMEDOUT; 1593a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 15949b0b11fb1e286e03ce911b94844952edd05f554eNishant Sarmukadam priv->tx_wait = NULL; 15957e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek spin_unlock_bh(&priv->tx_lock); 1596a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 15977e1112d34aea10fdd689422e6bdc918309043bf3Lennert Buytenhek return rc; 1598a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1599a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1600c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek#define MWL8K_TXD_SUCCESS(status) \ 1601c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek ((status) & (MWL8K_TXD_STATUS_OK | \ 1602c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_RETRY | \ 1603c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek MWL8K_TXD_STATUS_OK_MORE_RETRY)) 1604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1605a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadamstatic int mwl8k_tid_queue_mapping(u8 tid) 1606a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam{ 1607a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam BUG_ON(tid > 7); 1608a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam 1609a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam switch (tid) { 1610a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 0: 1611a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 3: 1612a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam return IEEE80211_AC_BE; 1613a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam break; 1614a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 1: 1615a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 2: 1616a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam return IEEE80211_AC_BK; 1617a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam break; 1618a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 4: 1619a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 5: 1620a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam return IEEE80211_AC_VI; 1621a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam break; 1622a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 6: 1623a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam case 7: 1624a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam return IEEE80211_AC_VO; 1625a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam break; 1626a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam default: 1627a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam return -1; 1628a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam break; 1629a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam } 1630a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam} 1631a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam 1632170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam/* The firmware will fill in the rate information 1633170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam * for each packet that gets queued in the hardware 163449adc5ceb2b95e517baf625e0c8e06e91073009bJohn W. Linville * and these macros will interpret that info. 1635170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam */ 1636170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam 163749adc5ceb2b95e517baf625e0c8e06e91073009bJohn W. Linville#define RI_FORMAT(a) (a & 0x0001) 163849adc5ceb2b95e517baf625e0c8e06e91073009bJohn W. Linville#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) 1639170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam 1640efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekstatic int 1641efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhekmwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) 1642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1645efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek int processed; 1646a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1647efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed = 0; 16488ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo while (txq->len > 0 && limit--) { 1649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int tx; 1650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx_desc; 1651a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long addr; 1652ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek int size; 1653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb; 1654a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *info; 1655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 1656170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam struct ieee80211_sta *sta; 1657170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam struct mwl8k_sta *sta_info = NULL; 1658170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam u16 rate_info; 1659170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam struct ieee80211_hdr *wh; 1660a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 166145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->head; 166245eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx_desc = txq->txd + tx; 1663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = le32_to_cpu(tx_desc->status); 1665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_TXD_STATUS_FW_OWNED) { 1667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!force) 1668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek break; 1669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->status &= 1670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); 1671a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1672a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 167345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->head = (tx + 1) % MWL8K_TX_DESCS; 16748ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo BUG_ON(txq->len == 0); 16758ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len--; 1676a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts--; 1677a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1678a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek addr = le32_to_cpu(tx_desc->pkt_phys_addr); 1679ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek size = le16_to_cpu(tx_desc->pkt_len); 168045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek skb = txq->skb[tx]; 168145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[tx] = NULL; 1682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek BUG_ON(skb == NULL); 1684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); 1685a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 168620f09c3df7a8a623c290f62596c1a6b0da088030Lennert Buytenhek mwl8k_remove_dma_header(skb, tx_desc->qos_control); 1687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1688170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam wh = (struct ieee80211_hdr *) skb->data; 1689170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam 1690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Mark descriptor as unused */ 1691a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_phys_addr = 0; 1692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_desc->pkt_len = 0; 1693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1694a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info = IEEE80211_SKB_CB(skb); 1695170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam if (ieee80211_is_data(wh->frame_control)) { 169689e1180121f281af16855d4954b9fe3d7354fe73Thomas Huehn rcu_read_lock(); 169789e1180121f281af16855d4954b9fe3d7354fe73Thomas Huehn sta = ieee80211_find_sta_by_ifaddr(hw, wh->addr1, 169889e1180121f281af16855d4954b9fe3d7354fe73Thomas Huehn wh->addr2); 1699170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam if (sta) { 1700170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam sta_info = MWL8K_STA(sta); 1701170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam BUG_ON(sta_info == NULL); 1702170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam rate_info = le16_to_cpu(tx_desc->rate_info); 1703170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam /* If rate is < 6.5 Mpbs for an ht station 1704170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam * do not form an ampdu. If the station is a 1705170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam * legacy station (format = 0), do not form an 1706170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam * ampdu 1707170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam */ 170849adc5ceb2b95e517baf625e0c8e06e91073009bJohn W. Linville if (RI_RATE_ID_MCS(rate_info) < 1 || 170949adc5ceb2b95e517baf625e0c8e06e91073009bJohn W. Linville RI_FORMAT(rate_info) == 0) { 1710170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam sta_info->is_ampdu_allowed = false; 1711170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam } else { 1712170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam sta_info->is_ampdu_allowed = true; 1713170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam } 1714170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam } 171589e1180121f281af16855d4954b9fe3d7354fe73Thomas Huehn rcu_read_unlock(); 1716170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam } 1717170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam 1718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_info_clear_status(info); 17190bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 17200bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam /* Rate control is happening in the firmware. 17210bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam * Ensure no tx rate is being reported. 17220bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam */ 1723ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar info->status.rates[0].idx = -1; 1724ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar info->status.rates[0].count = 1; 17250bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam 1726ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek if (MWL8K_TXD_SUCCESS(status)) 1727a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek info->flags |= IEEE80211_TX_STAT_ACK; 1728a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1729a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_tx_status_irqsafe(hw, skb); 1730a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1731efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek processed++; 1732a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1733a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1734efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek return processed; 1735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* must be called only when the card's transmit is completely halted */ 1738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) 1739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq = priv->txq + index; 1742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 174373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (txq->txd == NULL) 174473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return; 174573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 1746efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, index, INT_MAX, 1); 1747a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 174845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek kfree(txq->skb); 174945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb = NULL; 1750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 1752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), 175345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd, txq->txd_dma); 175445eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->txd = NULL; 1755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 1756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1757ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo/* caller must hold priv->stream_lock when calling the stream functions */ 1758ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powarstatic struct mwl8k_ampdu_stream * 1759ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolomwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) 1760ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo{ 1761ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo struct mwl8k_ampdu_stream *stream; 1762ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo struct mwl8k_priv *priv = hw->priv; 1763ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo int i; 1764ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 17657fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { 1766ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream = &priv->ampdu[i]; 1767ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo if (stream->state == AMPDU_NO_STREAM) { 1768ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->sta = sta; 1769ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->state = AMPDU_STREAM_NEW; 1770ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->tid = tid; 1771ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->idx = i; 1772ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", 1773ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo sta->addr, tid); 1774ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return stream; 1775ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo } 1776ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo } 1777ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return NULL; 1778ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo} 1779ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1780ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolostatic int 1781ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolomwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) 1782ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo{ 1783ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo int ret; 1784ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1785ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo /* if the stream has already been started, don't start it again */ 1786ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo if (stream->state != AMPDU_STREAM_NEW) 1787ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return 0; 1788ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); 1789ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo if (ret) 1790ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " 1791ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo "%d\n", stream->sta->addr, stream->tid, ret); 1792ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo else 1793ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", 1794ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->sta->addr, stream->tid); 1795ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return ret; 1796ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo} 1797ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1798ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolostatic void 1799ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolomwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) 1800ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo{ 1801ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, 1802ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->tid); 1803ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo memset(stream, 0, sizeof(*stream)); 1804ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo} 1805ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1806ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolostatic struct mwl8k_ampdu_stream * 1807ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolomwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) 1808ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo{ 1809ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo struct mwl8k_priv *priv = hw->priv; 1810ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo int i; 1811ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 18127fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { 1813ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo struct mwl8k_ampdu_stream *stream; 1814ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream = &priv->ampdu[i]; 1815ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo if (stream->state == AMPDU_NO_STREAM) 1816ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo continue; 1817ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && 1818ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo stream->tid == tid) 1819ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return stream; 1820ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo } 1821ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo return NULL; 1822ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo} 1823ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 1824d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo#define MWL8K_AMPDU_PACKET_THRESHOLD 64 1825d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolostatic inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) 1826d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo{ 1827d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo struct mwl8k_sta *sta_info = MWL8K_STA(sta); 1828d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo struct tx_traffic_info *tx_stats; 1829d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1830d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo BUG_ON(tid >= MWL8K_MAX_TID); 1831d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats = &sta_info->tx_stats[tid]; 1832d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1833d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo return sta_info->is_ampdu_allowed && 1834d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; 1835d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo} 1836d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1837d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolostatic inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) 1838d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo{ 1839d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo struct mwl8k_sta *sta_info = MWL8K_STA(sta); 1840d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo struct tx_traffic_info *tx_stats; 1841d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1842d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo BUG_ON(tid >= MWL8K_MAX_TID); 1843d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats = &sta_info->tx_stats[tid]; 1844d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1845d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo if (tx_stats->start_time == 0) 1846d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats->start_time = jiffies; 1847d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 1848d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo /* reset the packet count after each second elapses. If the number of 1849d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo * packets ever exceeds the ampdu_min_traffic threshold, we will allow 1850d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo * an ampdu stream to be started. 1851d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo */ 1852d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo if (jiffies - tx_stats->start_time > HZ) { 1853d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats->pkts = 0; 1854d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats->start_time = 0; 1855d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo } else 1856d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo tx_stats->pkts++; 1857d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo} 1858d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo 18597fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar/* The hardware ampdu queues start from 5. 18607fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * txpriorities for ampdu queues are 18617fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * 5 6 7 0 1 2 3 4 ie., queue 5 is highest 18627fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar * and queue 3 is lowest (queue 4 is reserved) 18637fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar */ 18647fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar#define BA_QUEUE 5 18657fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar 18667bb4568372856688bc070917265bce0b88bb7d4dJohannes Bergstatic void 186736323f817af0376c78612cfdab714b0feb05fea5Thomas Huehnmwl8k_txq_xmit(struct ieee80211_hw *hw, 186836323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn int index, 186936323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn struct ieee80211_sta *sta, 187036323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn struct sk_buff *skb) 1871a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 1872a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 1873a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_tx_info *tx_info; 187423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek struct mwl8k_vif *mwl8k_vif; 1875a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hdr *wh; 1876a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_queue *txq; 1877a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_tx_desc *tx; 1878a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma; 187923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u32 txstatus; 188023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u8 txdatarate; 188123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek u16 qos; 188265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam int txpriority; 188365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam u8 tid = 0; 188465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam struct mwl8k_ampdu_stream *stream = NULL; 188565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam bool start_ba_session = false; 18863a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam bool mgmtframe = false; 1887a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 1888e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam bool eapol_frame = false; 1889a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 189023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = (struct ieee80211_hdr *)skb->data; 189123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_data_qos(wh->frame_control)) 189223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); 189323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 189423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek qos = 0; 1895a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1896e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam if (skb->protocol == cpu_to_be16(ETH_P_PAE)) 1897e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam eapol_frame = true; 1898e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam 18993a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam if (ieee80211_is_mgmt(wh->frame_control)) 19003a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam mgmtframe = true; 19013a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam 1902d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (priv->ap_fw) 1903ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar mwl8k_encapsulate_tx_frame(priv, skb); 1904d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam else 1905e4eefec73ea0a740bfe8736e3ac30dfe92fe392bYogesh Ashok Powar mwl8k_add_dma_header(priv, skb, 0, 0); 1906d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam 190723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek wh = &((struct mwl8k_dma_data *)skb->data)->wh; 1908a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1909a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx_info = IEEE80211_SKB_CB(skb); 1910a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif = MWL8K_VIF(tx_info->control.vif); 1911a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1912a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 1913a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 1914657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); 1915657232b625890f202867ede0ed67ecf15827ff80Lennert Buytenhek mwl8k_vif->seqno += 0x10; 1916a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 1917a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 191823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek /* Setup firmware control bit fields for each frame type. */ 191923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus = 0; 192023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 192123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (ieee80211_is_mgmt(wh->frame_control) || 192223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek ieee80211_is_ctl(wh->frame_control)) { 192323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 0; 1924e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP; 192523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } else if (ieee80211_is_data(wh->frame_control)) { 192623b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txdatarate = 1; 192723b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (is_multicast_ether_addr(wh->addr1)) 192823b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; 192923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 1930e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos &= ~MWL8K_QOS_ACK_POLICY_MASK; 193123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) 1932e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK; 193323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek else 1934e0493a8dd6351a114b53790dda6bd855ae73a85cLennert Buytenhek qos |= MWL8K_QOS_ACK_POLICY_NORMAL; 193523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek } 1936a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 1937a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam /* Queue ADDBA request in the respective data queue. While setting up 1938a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * the ampdu stream, mac80211 queues further packets for that 1939a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * particular ra/tid pair. However, packets piled up in the hardware 1940a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * for that ra/tid pair will still go out. ADDBA request and the 1941a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * related data packets going out from different queues asynchronously 1942a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * will cause a shift in the receiver window which might result in 1943a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * ampdu packets getting dropped at the receiver after the stream has 1944a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam * been setup. 1945a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam */ 1946a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam if (unlikely(ieee80211_is_action(wh->frame_control) && 1947a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam mgmt->u.action.category == WLAN_CATEGORY_BACK && 1948a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && 1949a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam priv->ap_fw)) { 1950a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); 1951a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; 1952a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam index = mwl8k_tid_queue_mapping(tid); 1953a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam } 1954a0e7c6cfe2a04af450274638845802b5c384e8dfNishant Sarmukadam 195565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam txpriority = index; 195665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 1957e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam if (priv->ap_fw && sta && sta->ht_cap.ht_supported && !eapol_frame && 1958e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam ieee80211_is_data_qos(wh->frame_control)) { 195965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam tid = qos & 0xf; 1960d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo mwl8k_tx_count_packet(sta, tid); 196165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 196265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam stream = mwl8k_lookup_stream(hw, sta->addr, tid); 196365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (stream != NULL) { 196465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (stream->state == AMPDU_STREAM_ACTIVE) { 19655f2a14940db23350612071a3c906c8960e3ceb9aYogesh Ashok Powar WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK)); 19667fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar txpriority = (BA_QUEUE + stream->idx) % 19677fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar TOTAL_HW_TX_QUEUES; 19687fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar if (stream->idx <= 1) 19697fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar index = stream->idx + 19707fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar MWL8K_TX_WMM_QUEUES; 19717fb978b7e93b5c4a378eba5767c7513540b56642Yogesh Ashok Powar 197265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } else if (stream->state == AMPDU_STREAM_NEW) { 197365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* We get here if the driver sends us packets 197465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * after we've initiated a stream, but before 197565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * our ampdu_action routine has been called 197665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * with IEEE80211_AMPDU_TX_START to get the SSN 197765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * for the ADDBA request. So this packet can 197865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * go out with no risk of sequence number 197965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * mismatch. No special handling is required. 198065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 198165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } else { 198265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* Drop packets that would go out after the 198365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * ADDBA request was sent but before the ADDBA 198465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * response is received. If we don't do this, 198565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * the recipient would probably receive it 198665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * after the ADDBA request with SSN 0. This 198765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * will cause the recipient's BA receive window 198865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * to shift, which would cause the subsequent 198965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * packets in the BA stream to be discarded. 199065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * mac80211 queues our packets for us in this 199165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * case, so this is really just a safety check. 199265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 199365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam wiphy_warn(hw->wiphy, 199465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam "Cannot send packet while ADDBA " 199565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam "dialog is underway.\n"); 199665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 199765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam dev_kfree_skb(skb); 199865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam return; 199965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 200065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } else { 200165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* Defer calling mwl8k_start_stream so that the current 200265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * skb can go out before the ADDBA request. This 200365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * prevents sequence number mismatch at the recepient 200465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * as described above. 200565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 2006d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1Brian Cavagnolo if (mwl8k_ampdu_allowed(sta, tid)) { 2007170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam stream = mwl8k_add_stream(hw, sta, tid); 2008170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam if (stream != NULL) 2009170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam start_ba_session = true; 2010170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam } 201165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 201265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 20135f2a14940db23350612071a3c906c8960e3ceb9aYogesh Ashok Powar } else { 20145f2a14940db23350612071a3c906c8960e3ceb9aYogesh Ashok Powar qos &= ~MWL8K_QOS_ACK_POLICY_MASK; 20155f2a14940db23350612071a3c906c8960e3ceb9aYogesh Ashok Powar qos |= MWL8K_QOS_ACK_POLICY_NORMAL; 201665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 201765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 2018a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma = pci_map_single(priv->pdev, skb->data, 2019a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek skb->len, PCI_DMA_TODEVICE); 2020a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2021a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma)) { 2022c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 2023c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "failed to dma map skb, dropping TX frame.\n"); 202465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (start_ba_session) { 202565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 202665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam mwl8k_remove_stream(hw, stream); 202765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 202865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 202923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek dev_kfree_skb(skb); 20307bb4568372856688bc070917265bce0b88bb7d4dJohannes Berg return; 2031a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2032a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 203323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek spin_lock_bh(&priv->tx_lock); 2034a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 203523b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek txq = priv->txq + index; 2036a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 20373a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam /* Mgmt frames that go out frequently are probe 20383a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam * responses. Other mgmt frames got out relatively 20393a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam * infrequently. Hence reserve 2 buffers so that 20403a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam * other mgmt frames do not get dropped due to an 20413a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam * already queued probe response in one of the 20423a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam * reserved buffers. 20433a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam */ 20443a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam 20453a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam if (txq->len >= MWL8K_TX_DESCS - 2) { 204623677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (!mgmtframe || txq->len == MWL8K_TX_DESCS) { 20473a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam if (start_ba_session) { 20483a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam spin_lock(&priv->stream_lock); 20493a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam mwl8k_remove_stream(hw, stream); 20503a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam spin_unlock(&priv->stream_lock); 20513a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam } 20523a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam spin_unlock_bh(&priv->tx_lock); 2053ff7aa96f669d81b51339f7a0faf7ca37ed841ef1Nishant Sarmukadam pci_unmap_single(priv->pdev, dma, skb->len, 2054ff7aa96f669d81b51339f7a0faf7ca37ed841ef1Nishant Sarmukadam PCI_DMA_TODEVICE); 20553a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam dev_kfree_skb(skb); 20563a769888797b7117005e9c60d4cd73a2efc92f8dNishant Sarmukadam return; 20573a7dbc3b2ac545efac75d4145839eaa7b59d9741Pradeep Nemavat } 205865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 205965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 206045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek BUG_ON(txq->skb[txq->tail] != NULL); 206145eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->skb[txq->tail] = skb; 2062a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 206345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek tx = txq->txd + txq->tail; 206423b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->data_rate = txdatarate; 206565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam tx->tx_priority = txpriority; 2066a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->qos_control = cpu_to_le16(qos); 2067a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_phys_addr = cpu_to_le32(dma); 2068a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek tx->pkt_len = cpu_to_le16(skb->len); 206923b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->rate_info = 0; 207036323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn if (!priv->ap_fw && sta != NULL) 207136323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn tx->peer_id = MWL8K_STA(sta)->peer_id; 2072a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek else 2073a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek tx->peer_id = 0; 2074566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat 2075e1f4d69b631468d915a9ed4a0a64dba77705492dNishant Sarmukadam if (priv->ap_fw && ieee80211_is_data(wh->frame_control) && !eapol_frame) 2076566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat tx->timestamp = cpu_to_le32(ioread32(priv->regs + 2077566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat MWL8K_HW_TIMER_REGISTER)); 2078b8d9e572cb8794335fb4ba63ff962acaa3c4473bNishant Sarmukadam else 2079b8d9e572cb8794335fb4ba63ff962acaa3c4473bNishant Sarmukadam tx->timestamp = 0; 2080566875db5058f582ea56da891f9c3cabc01efff5Pradeep Nemavat 2081a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek wmb(); 208223b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); 208323b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 20848ccbc3b8b0c919e8609560ca56cd777ece8d2c41Kalle Valo txq->len++; 2085a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->pending_tx_pkts++; 2086a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 208745eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail++; 208845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek if (txq->tail == MWL8K_TX_DESCS) 208945eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek txq->tail = 0; 209023b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek 209123b339062f247e0be84eaabb15e17b403c4388b6Lennert Buytenhek mwl8k_tx_start(priv); 2092a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2093a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 209465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 209565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* Initiate the ampdu session here */ 209665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (start_ba_session) { 209765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 209865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (mwl8k_start_stream(hw, stream)) 209965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam mwl8k_remove_stream(hw, stream); 210065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 210165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 2102a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2104a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2105a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2106618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * Firmware access. 2107618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 2108618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * We have the following requirements for issuing firmware commands: 2109618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - Some commands require that the packet transmit path is idle when 2110618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the command is issued. (For simplicity, we'll just quiesce the 2111618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * transmit path for every command.) 2112618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * - There are certain sequences of commands that need to be issued to 2113618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * the hardware sequentially, with no other intervening commands. 2114618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * 2115618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * This leads to an implementation of a "firmware lock" as a mutex that 2116618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * can be taken recursively, and which is taken by both the low-level 2117618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * command submission function (mwl8k_post_cmd) as well as any users of 2118618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * that function that require issuing of an atomic sequence of commands, 2119618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek * and quiesces the transmit path whenever it's taken. 2120618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek */ 2121618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic int mwl8k_fw_lock(struct ieee80211_hw *hw) 2122618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 2123618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2124618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2125618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->fw_mutex_owner != current) { 2126618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek int rc; 2127618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2128618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_lock(&priv->fw_mutex); 2129618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek ieee80211_stop_queues(hw); 2130618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2131618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek rc = mwl8k_tx_wait_empty(hw); 2132618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (rc) { 21336b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!priv->hw_restart_in_progress) 21346b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar ieee80211_wake_queues(hw); 21356b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 2136618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 2137618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2138618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return rc; 2139618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 2140618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2141618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = current; 2142618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 2143618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2144618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_depth++; 2145618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2146618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek return 0; 2147618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 2148618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2149618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhekstatic void mwl8k_fw_unlock(struct ieee80211_hw *hw) 2150618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek{ 2151618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2152618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2153618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!--priv->fw_mutex_depth) { 21546b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!priv->hw_restart_in_progress) 21556b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar ieee80211_wake_queues(hw); 21566b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 2157618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->fw_mutex_owner = NULL; 2158618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mutex_unlock(&priv->fw_mutex); 2159618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek } 2160618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek} 2161618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2162e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powarstatic void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, 2163e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar u32 bitmap); 2164618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2165618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek/* 2166a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Command processing. 2167a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2168a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 21690c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek/* Timeout firmware commands after 10s */ 21700c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek#define MWL8K_CMD_TIMEOUT_MS 10000 2171a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2172a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) 2173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek DECLARE_COMPLETION_ONSTACK(cmd_wait); 2175a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek void __iomem *regs = priv->regs; 2177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr_t dma_addr; 2178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned int dma_size; 2179a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek unsigned long timeout = 0; 2181a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u8 buf[32]; 2182e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar u32 bitmap = 0; 2183e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2184e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar wiphy_dbg(hw->wiphy, "Posting %s [%d]\n", 2185e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid); 2186e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2187e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar /* Before posting firmware commands that could change the hardware 2188e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar * characteristics, make sure that all BSSes are stopped temporary. 2189e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar * Enable these stopped BSSes after completion of the commands 2190e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar */ 2191e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2192e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar rc = mwl8k_fw_lock(hw); 2193e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (rc) 2194e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar return rc; 2195e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2196e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (priv->ap_fw && priv->running_bsses) { 2197e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar switch (le16_to_cpu(cmd->code)) { 2198e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_SET_RF_CHANNEL: 2199e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_RADIO_CONTROL: 2200e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_RF_TX_POWER: 2201e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_TX_POWER: 2202e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_RF_ANTENNA: 2203e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_RTS_THRESHOLD: 2204e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar case MWL8K_CMD_MIMO_CONFIG: 2205e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar bitmap = priv->running_bsses; 2206e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar mwl8k_enable_bsses(hw, false, bitmap); 2207e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar break; 2208e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar } 2209e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar } 2210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2211b603742f49c3ec922522602e18ac22e8f6835132John W. Linville cmd->result = (__force __le16) 0xffff; 2212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_size = le16_to_cpu(cmd->length); 2213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dma_addr = pci_map_single(priv->pdev, cmd, dma_size, 2214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek PCI_DMA_BIDIRECTIONAL); 2215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (pci_dma_mapping_error(priv->pdev, dma_addr)) 2216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hostcmd_wait = &cmd_wait; 2219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); 2220a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DOORBELL, 2221a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 2222a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(MWL8K_H2A_INT_DUMMY, 2223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); 2224a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2225a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek timeout = wait_for_completion_timeout(&cmd_wait, 2226a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); 2227a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2228618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek priv->hostcmd_wait = NULL; 2229618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 2230618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek 223137055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek pci_unmap_single(priv->pdev, dma_addr, dma_size, 223237055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek PCI_DMA_BIDIRECTIONAL); 223337055bd455b31b8220c35a1ede9c6aceb791cc88Lennert Buytenhek 2234a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!timeout) { 22355db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", 2236c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 2237c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches MWL8K_CMD_TIMEOUT_MS); 2238a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = -ETIMEDOUT; 2239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } else { 22400c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek int ms; 22410c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 22420c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(timeout); 22430c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek 2244ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek rc = cmd->result ? -EINVAL : 0; 2245a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 22465db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Command %s error 0x%x\n", 2247c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), 2248c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches le16_to_cpu(cmd->result)); 22490c9cc640225f4bd7c9aad87b1431bd8d9a29b338Lennert Buytenhek else if (ms > 2000) 22505db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_notice(hw->wiphy, "Command %s took %d ms\n", 2251c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches mwl8k_cmd_name(cmd->code, 2252c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches buf, sizeof(buf)), 2253c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches ms); 2254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2256e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (bitmap) 2257e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar mwl8k_enable_bsses(hw, true, bitmap); 2258e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2259e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar mwl8k_fw_unlock(hw); 2260e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 2261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2264f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhekstatic int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, 2265f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct ieee80211_vif *vif, 2266f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek struct mwl8k_cmd_pkt *cmd) 2267f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek{ 2268f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek if (vif != NULL) 2269f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek cmd->macid = MWL8K_VIF(vif)->macid; 2270f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek return mwl8k_post_cmd(hw, cmd); 2271f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek} 2272f57ca9c1af3c1e30a40ad99d75940176d8c3ff3aLennert Buytenhek 2273a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 22741349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek * Setup code shared between STA and AP firmware images. 22751349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek */ 22761349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhekstatic void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) 22771349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek{ 22781349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 22791349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 22801349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); 22811349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); 22821349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 22831349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); 22841349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); 22851349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 22861349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.band = IEEE80211_BAND_2GHZ; 22871349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.channels = priv->channels_24; 22881349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); 22891349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.bitrates = priv->rates_24; 22901349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); 22911349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 22921349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; 22931349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek} 22941349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek 22954eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhekstatic void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) 22964eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek{ 22974eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 22984eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 22994eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); 23004eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); 23014eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 23024eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); 23034eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); 23044eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 23054eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.band = IEEE80211_BAND_5GHZ; 23064eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.channels = priv->channels_50; 23074eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); 23084eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.bitrates = priv->rates_50; 23094eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); 23104eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 23114eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; 23124eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek} 23134eae9edd38c0a9ce34e39100ccc69ff520bc1224Lennert Buytenhek 23141349ad2f06f86f41415cf7ffa9e068fd4f89be87Lennert Buytenhek/* 231504b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek * CMD_GET_HW_SPEC (STA version). 2316a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 231704b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_sta { 2318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2319a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 hw_rev; 2320a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 host_interface; 2321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 num_mcaddrs; 2322d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 2323a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 region_code; 2324a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 fw_rev; 2325a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 ps_cookie; 2326a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps; 2327a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 mcs_bitmap[16]; 2328a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 rx_queue_ptr; 2329a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_queues; 2330e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; 2331a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 caps2; 2332a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 num_tx_desc_per_queue; 233345eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek __le32 total_rxd; 2334ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2336341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MAX_AMSDU 0x20000000 2337341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_GREENFIELD 0x08000000 2338341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_AMPDU 0x04000000 2339341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_STBC 0x01000000 2340341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_STBC 0x00800000 2341341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 2342341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 2343341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 2344341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 2345341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_DELAY_BA 0x00003000 2346341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_MIMO 0x00000200 2347341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek#define MWL8K_CAP_40MHZ 0x00000100 234806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_BAND_MASK 0x00000007 234906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_5GHZ 0x00000004 235006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek#define MWL8K_CAP_2GHZ4 0x00000001 2351341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 235206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 235306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_ht_caps(struct ieee80211_hw *hw, 235406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct ieee80211_supported_band *band, u32 cap) 2355341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek{ 2356341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int rx_streams; 2357341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek int tx_streams; 2358341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 2359777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ht_supported = 1; 2360341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 2361341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_MAX_AMSDU) 2362777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; 2363341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_GREENFIELD) 2364777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; 2365341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_AMPDU) { 2366341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; 2367777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 2368777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 2369341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 2370341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_RX_STBC) 2371777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; 2372341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_TX_STBC) 2373777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; 2374341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_40MHZ) 2375777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; 2376341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_SHORTGI_20MHZ) 2377777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; 2378341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_DELAY_BA) 2379777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; 2380341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (cap & MWL8K_CAP_40MHZ) 2381777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 2382341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 2383341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); 2384341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); 2385341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 2386777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[0] = 0xff; 2387341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 2) 2388777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[1] = 0xff; 2389341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams >= 3) 2390777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[2] = 0xff; 2391777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.rx_mask[4] = 0x01; 2392777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 2393341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 2394341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek if (rx_streams != tx_streams) { 2395777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 2396777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek band->ht_cap.mcs.tx_params |= (tx_streams - 1) << 2397341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 2398341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek } 2399341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek} 2400341c97918ab7e84a155ea8b18759425304d213b6Lennert Buytenhek 240106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekstatic void 240206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhekmwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) 240306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek{ 240406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 240506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 240606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { 240706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_2ghz_band(hw); 240806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 240906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_24, caps); 241006953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 241106953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 241206953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_5GHZ) { 241306953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_setup_5ghz_band(hw); 241406953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek if (caps & MWL8K_CAP_MIMO) 241506953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_ht_caps(hw, &priv->band_50, caps); 241606953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek } 241706953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek} 241806953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek 241904b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) 2420a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 242204b147b19303724aac5ee8e56f113f1935a5c255Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_sta *cmd; 2423a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 2425a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2427a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 2431a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 2434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 243545eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 2436e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); 2437e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 243845eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); 24394ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 244045eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 2441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2443a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2444a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 2445a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 2446a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 24474ff6432ea620ba467e50ec04b8271ea0eb94e62eLennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 2448a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->hw_rev = cmd->hw_rev; 244906953235f48c696b22c5ed45570680fb070f7277Lennert Buytenhek mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); 2450ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x00000000; 2451ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->sta_macids_supported = 0x00000001; 2452a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2453a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2454a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2455a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2456a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2457a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2458a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 245942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_GET_HW_SPEC (AP version). 246042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 246142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_get_hw_spec_ap { 246242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 246342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 246442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 246542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_wcb; 246642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 246742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 246842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 246942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_antenna; 247042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 247142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase0; 247242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxwrptr; 247342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rxrdptr; 247442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 247542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase1; 247642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase2; 247742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 wcbbase3; 2478952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo __le32 fw_api_version; 24798a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 caps; 24808a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 num_of_ampdu_queues; 24818a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; 2482ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 248342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 248442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) 248542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 248642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 248742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_get_hw_spec_ap *cmd; 24888a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo int rc, i; 2489952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo u32 api_version; 249042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 249142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 249242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 249342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 249442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 249542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); 249642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 249742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 249842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); 249942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 250042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 250142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 250242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 250342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) { 250442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int off; 250542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2506952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version = le32_to_cpu(cmd->fw_api_version); 2507952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo if (priv->device_info->fw_api_ap != api_version) { 2508952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo printk(KERN_ERR "%s: Unsupported fw API version for %s." 2509952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo " Expected %d got %d.\n", MWL8K_NAME, 2510952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->part_name, 2511952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo priv->device_info->fw_api_ap, 2512952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo api_version); 2513952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo rc = -EINVAL; 2514952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo goto done; 2515952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo } 251642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); 251742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); 251842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->fw_rev = le32_to_cpu(cmd->fw_rev); 251942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek priv->hw_rev = cmd->hw_rev; 25208a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); 2521ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->ap_macids_supported = 0x000000ff; 2522d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar priv->sta_macids_supported = 0x00000100; 25238a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); 25248a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { 25258a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" 25268a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo " but we only support %d.\n", 25278a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues, 25288a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo MWL8K_MAX_AMPDU_QUEUES); 25298a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; 25308a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo } 253142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxwrptr) & 0xffff; 2532b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 253342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 253442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek off = le32_to_cpu(cmd->rxrdptr) & 0xffff; 2535b603742f49c3ec922522602e18ac22e8f6835132John W. Linville iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); 253642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 253773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; 253873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; 253973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; 254073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; 25418a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo 25428a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo for (i = 0; i < priv->num_ampdu_queues; i++) 2543e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = 25448a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; 254542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 254642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 2547952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolodone: 254842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 254942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 255042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 255142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 255242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 255342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek * CMD_SET_HW_SPEC. 255442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek */ 255542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstruct mwl8k_cmd_set_hw_spec { 255642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_pkt header; 255742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 hw_rev; 255842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 host_interface; 255942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 num_mcaddrs; 256042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __u8 perm_addr[ETH_ALEN]; 256142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le16 region_code; 256242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 fw_rev; 256342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 ps_cookie; 256442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 caps; 256542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 rx_queue_ptr; 256642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_queues; 2567e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; 256842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 flags; 256942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 num_tx_desc_per_queue; 257042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek __le32 total_rxd; 2571ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 257242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 25738a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause 25748a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * packets to expire 500 ms after the timestamp in the tx descriptor. That is, 25758a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * the packets that are queued for more than 500ms, will be dropped in the 25768a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * hardware. This helps minimizing the issues caused due to head-of-line 25778a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * blocking where a slow client can hog the bandwidth and affect traffic to a 25788a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo * faster client. 25798a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo */ 25808a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 25813373b28e5af4a0b3c6cb39372581dcc1e41322ffNishant Sarmukadam#define MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR 0x00000200 2582b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 2583b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 2584b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 258542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 258642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhekstatic int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) 258742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek{ 258842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 258942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek struct mwl8k_cmd_set_hw_spec *cmd; 259042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int rc; 259142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek int i; 259242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 259342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 259442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (cmd == NULL) 259542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return -ENOMEM; 259642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 259742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC); 259842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 259942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 260042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); 260142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); 2602e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); 260385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam 260485c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam /* 260585c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * Mac80211 stack has Q0 as highest priority and Q3 as lowest in 260685c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * that order. Firmware has Q3 as highest priority and Q0 as lowest 260785c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * in that order. Map Q3 of mac80211 to Q0 of firmware so that the 260885c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam * priority is interpreted the right way in firmware. 260985c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam */ 2610e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) { 2611e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo int j = mwl8k_tx_queues(priv) - 1 - i; 261285c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); 261385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam } 261485c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam 2615b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | 2616b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | 261731d291a769b4318cbf7943ca149e04d201e2c931Nishant Sarmukadam MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | 26183373b28e5af4a0b3c6cb39372581dcc1e41322ffNishant Sarmukadam MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY | 26193373b28e5af4a0b3c6cb39372581dcc1e41322ffNishant Sarmukadam MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR); 262042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 262142fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 262242fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 262342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 262442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek kfree(cmd); 262542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 262642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek return rc; 262742fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek} 262842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek 262942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek/* 2630a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_MAC_MULTICAST_ADR. 2631a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2632a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_mac_multicast_adr { 2633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2635a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 numaddr; 2636ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek __u8 addr[0][ETH_ALEN]; 2637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 2638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2639d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_DIRECTED 0x0001 2640d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_MULTICAST 0x0002 2641d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 2642d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek#define MWL8K_ENABLE_RX_BROADCAST 0x0008 2643ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2644e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic struct mwl8k_cmd_pkt * 2645447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, 264622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 2647a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2648e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_mac_multicast_adr *cmd; 2650e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek int size; 265122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int mc_count = 0; 265222bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko 265322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko if (mc_list) 265422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko mc_count = netdev_hw_addr_list_count(mc_list); 2655e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2656447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (allmulti || mc_count > priv->num_mcaddrs) { 2657d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek allmulti = 1; 2658d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek mc_count = 0; 2659d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } 2660e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 2661e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek size = sizeof(*cmd) + mc_count * ETH_ALEN; 2662ce9e2e1b8433c8795459a259ee87bc4e424e7c50Lennert Buytenhek 2663e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek cmd = kzalloc(size, GFP_ATOMIC); 2664a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2665e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return NULL; 2666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2667a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); 2668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(size); 2669d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED | 2670d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek MWL8K_ENABLE_RX_BROADCAST); 2671d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2672d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek if (allmulti) { 2673d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST); 2674d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek } else if (mc_count) { 267522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 267622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko int i = 0; 2677d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek 2678d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); 2679d5e308457e8e9b4988fbd69d38c30782125b3f65Lennert Buytenhek cmd->numaddr = cpu_to_le16(mc_count); 268022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_hw_addr_list_for_each(ha, mc_list) { 268122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko memcpy(cmd->addr[i], ha->addr, ETH_ALEN); 2682a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2685e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return &cmd->header; 2686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2688a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 268955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_GET_STAT. 2690a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 269155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_get_stat { 2692a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2693a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 stats[64]; 2694ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2695a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2696a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_ACK_FAILURE 9 2697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_FAILURE 12 2698a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_FCS_ERROR 24 2699a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_STAT_RTS_SUCCESS 11 2700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 270155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, 270255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_low_level_stats *stats) 2703a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 270455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_get_stat *cmd; 2705a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2706a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2709a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2710a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2711a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); 2712a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2713a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2714a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2715a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) { 2716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11ACKFailureCount = 2717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]); 2718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSFailureCount = 2719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]); 2720a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11FCSErrorCount = 2721a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]); 2722a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek stats->dot11RTSSuccessCount = 2723a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]); 2724a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 2725a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2726a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2727a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2728a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2729a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2730a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 273155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RADIO_CONTROL. 2732a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 273355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_radio_control { 2734a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 control; 2737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 radio_on; 2738ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2740c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhekstatic int 274155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force) 2742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2743a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 274455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_radio_control *cmd; 2745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2746a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2747c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek if (enable == priv->radio_on && !force) 2748a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 2749a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2750a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2751a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2752a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2753a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2754a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); 2755a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2756a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 275768ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); 2758a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); 2759a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2760a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2761a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2762a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2763a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!rc) 2764c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek priv->radio_on = enable; 2765a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2766a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2767a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2768a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 276955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw) 2770c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 277155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 0, 0); 2772c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2773c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 277455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw) 2775c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek{ 277655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 0); 2777c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek} 2778c46563b714b09d44eec4d1fd8a0f53e79ddaa3aaLennert Buytenhek 2779a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 2780a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekmwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) 2781a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 278299200a992e365a73dc67a6570524e5f3af4386ddLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 2783a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 278468ce38845c23443b15e374fb7362916c1231278eLennert Buytenhek priv->radio_short_preamble = short_preamble; 2785a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 278655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_radio_control(hw, 1, 1); 2787a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2788a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2789a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 279055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_RF_TX_POWER. 2791a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 279241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 2793a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 279455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_rf_tx_power { 2795a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2796a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 2797a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 support_level; 2798a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 current_level; 2799a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 reserved; 280041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_RF_TX_POWER_LEVEL_TOTAL]; 2801ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2802a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 280355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) 2804a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 280555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_rf_tx_power *cmd; 2806a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2807a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2808a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2809a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2810a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2811a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2812a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER); 2813a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2814a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 2815a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->support_level = cpu_to_le16(dBm); 2816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2818a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2819a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2820a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2821a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2822a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2823a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 282441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam * CMD_TX_POWER. 282541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam */ 282641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam#define MWL8K_TX_POWER_LEVEL_TOTAL 12 282741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 282841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstruct mwl8k_cmd_tx_power { 282941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_pkt header; 283041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 action; 283141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 band; 283241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 channel; 283341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 bw; 283441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 sub_ch; 283541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; 2836ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar} __packed; 283741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 283841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadamstatic int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, 283941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_conf *conf, 284041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam unsigned short pwr) 284141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam{ 284241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct ieee80211_channel *channel = conf->channel; 284341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam struct mwl8k_cmd_tx_power *cmd; 284441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int rc; 284541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam int i; 284641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 284741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 284841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (cmd == NULL) 284941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return -ENOMEM; 285041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 285141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_TX_POWER); 285241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 285341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->action = cpu_to_le16(MWL8K_CMD_SET_LIST); 285441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 285541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (channel->band == IEEE80211_BAND_2GHZ) 285641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x1); 285741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (channel->band == IEEE80211_BAND_5GHZ) 285841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->band = cpu_to_le16(0x4); 285941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 2860604c4ef1c453a1b2ea2cdf04d2b49afec421ebfaYogesh Ashok Powar cmd->channel = cpu_to_le16(channel->hw_value); 286141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 286241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_NO_HT || 286341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam conf->channel_type == NL80211_CHAN_HT20) { 286441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x2); 286541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } else { 286641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->bw = cpu_to_le16(0x4); 286741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (conf->channel_type == NL80211_CHAN_HT40MINUS) 286841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x3); 286941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 287041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->sub_ch = cpu_to_le16(0x1); 287141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam } 287241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 287341fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam for (i = 0; i < MWL8K_TX_POWER_LEVEL_TOTAL; i++) 287441fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam cmd->power_level_list[i] = cpu_to_le16(pwr); 287541fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 287641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_post_cmd(hw, &cmd->header); 287741fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam kfree(cmd); 287841fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 287941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam return rc; 288041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam} 288141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 288241fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam/* 288308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek * CMD_RF_ANTENNA. 288408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek */ 288508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstruct mwl8k_cmd_rf_antenna { 288608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_pkt header; 288708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 antenna; 288808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek __le16 mode; 2889ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 289008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 289108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_RX 1 289208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek#define MWL8K_RF_ANTENNA_TX 2 289308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 289408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekstatic int 289508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhekmwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) 289608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek{ 289708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek struct mwl8k_cmd_rf_antenna *cmd; 289808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek int rc; 289908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 290008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 290108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (cmd == NULL) 290208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return -ENOMEM; 290308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 290408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA); 290508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 290608b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->antenna = cpu_to_le16(antenna); 290708b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek cmd->mode = cpu_to_le16(mask); 290808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 290908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 291008b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek kfree(cmd); 291108b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 291208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek return rc; 291308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek} 291408b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek 291508b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek/* 2916b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_SET_BEACON. 2917b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 2918b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_set_beacon { 2919b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 2920b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le16 beacon_len; 2921b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __u8 beacon[0]; 2922b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek}; 2923b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2924aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, 2925aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, u8 *beacon, int len) 2926b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 2927b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_beacon *cmd; 2928b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 2929b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2930b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); 2931b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 2932b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 2933b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2934b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); 2935b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); 2936b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->beacon_len = cpu_to_le16(len); 2937b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->beacon, beacon, len); 2938b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2939aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 2940b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 2941b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2942b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 2943b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 2944b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 2945b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 2946a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_PRE_SCAN. 2947a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2948a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_pre_scan { 2949a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2950ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2951a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2952a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) 2953a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2954a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_pre_scan *cmd; 2955a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2956a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2957a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2958a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2959a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2960a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2961a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN); 2962a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2963a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2964a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2965a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2966a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2967a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2968a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2969a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2970a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 2971a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_POST_SCAN. 2972a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 2973a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_post_scan { 2974a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 2975a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 isibss; 2976d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek __u8 bssid[ETH_ALEN]; 2977ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 2978a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2979a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 29800a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhekmwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) 2981a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 2982a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_post_scan *cmd; 2983a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 2984a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2985a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2986a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 2987a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 2988a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2989a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN); 2990a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 2991a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->isibss = 0; 2992d89173f25228b8795af2d4b53e985cc44c729332Lennert Buytenhek memcpy(cmd->bssid, mac, ETH_ALEN); 2993a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2994a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 2995a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 2996a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 2997a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 2998a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 2999a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3000a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3001a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_RF_CHANNEL. 3002a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3003a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_rf_channel { 3004a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 3005a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 3006a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __u8 current_channel; 3007a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le32 channel_flags; 3008ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3009a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3010a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, 3011610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_conf *conf) 3012a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3013610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek struct ieee80211_channel *channel = conf->channel; 3014a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_rf_channel *cmd; 3015a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3016a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3017a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3018a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3019a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3020a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3021a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL); 3022a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3023a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 3024a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->current_channel = channel->hw_value; 3025610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 3026a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (channel->band == IEEE80211_BAND_2GHZ) 3027610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000001); 302842574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek else if (channel->band == IEEE80211_BAND_5GHZ) 302942574ea2274ec0a2a9c58ab01be91b65e60a2291Lennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000004); 3030610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek 3031610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek if (conf->channel_type == NL80211_CHAN_NO_HT || 3032610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek conf->channel_type == NL80211_CHAN_HT20) 3033610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x00000080); 3034610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40MINUS) 3035610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000001900); 3036610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek else if (conf->channel_type == NL80211_CHAN_HT40PLUS) 3037610677d2f0415570a7590790e8be376a946cd08bLennert Buytenhek cmd->channel_flags |= cpu_to_le32(0x000000900); 3038a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3039a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3040a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3041a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3042a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3043a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3044a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3045a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 304655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_AID. 3047a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 304855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_DISABLED 0x00 304955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11G 0x07 305055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 305155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 3052a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 305355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_set_aid { 305455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 305555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 aid; 3056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 305755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* AP's MAC address (BSSID) */ 305855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 bssid[ETH_ALEN]; 305955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 protection_mode; 306055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 supp_rates[14]; 3061ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3062a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3063c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekstatic void legacy_rate_mask_to_array(u8 *rates, u32 mask) 3064c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek{ 3065c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int i; 3066c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek int j; 3067c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 3068c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek /* 3069c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek * Clear nonstandard rates 4 and 13. 3070c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek */ 3071c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek mask &= 0x1fef; 3072c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 3073c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek for (i = 0, j = 0; i < 14; i++) { 3074c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek if (mask & (1 << i)) 3075777ad375d5960e0d2a945a34032b182eb2952d45Lennert Buytenhek rates[j++] = mwl8k_rates_24[i].hw_value; 3076c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek } 3077c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek} 3078c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 307955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 3080c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_aid(struct ieee80211_hw *hw, 3081c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, u32 legacy_rate_mask) 3082a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 308355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_set_aid *cmd; 308455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek u16 prot_mode; 3085a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3086a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3088a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3089a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3090a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 309155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); 3092a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 30937dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek cmd->aid = cpu_to_le16(vif->bss_conf.aid); 30940a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); 3095a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 30967dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.use_cts_prot) { 309755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11G; 309855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 30997dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek switch (vif->bss_conf.ht_operation_mode & 310055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek IEEE80211_HT_OP_MODE_PROTECTION) { 310155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: 310255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; 310355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 310455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: 310555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL; 310655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 310755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek default: 310855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek prot_mode = MWL8K_FRAME_PROT_DISABLED; 310955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek break; 311055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 311155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 311255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->protection_mode = cpu_to_le16(prot_mode); 3113a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3114c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); 3115a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3116a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3117a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3118a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3119a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3120a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3121a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3122a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 312355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATE. 312432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek */ 312555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate { 312655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 312755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 legacy_rates[14]; 312855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 312955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Bitmap for supported MCS codes. */ 313055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mcs_set[16]; 313155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 reserved[16]; 3132ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 313332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 313455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int 3135c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhekmwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 313613935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u32 legacy_rate_mask, u8 *mcs_rates) 313732060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek{ 313855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate *cmd; 313932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek int rc; 314032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 314132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 314232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (cmd == NULL) 314332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return -ENOMEM; 314432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 314555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); 314632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3147c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); 314813935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->mcs_set, mcs_rates, 16); 314932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 315032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 315132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek kfree(cmd); 315232060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 315332060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek return rc; 315432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek} 315532060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 315632060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek/* 315755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_FINALIZE_JOIN. 3158a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 315955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek#define MWL8K_FJ_BEACON_MAXLEN 128 316055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 316155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_finalize_join { 3162a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 316355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 sleep_interval; /* Number of beacon periods to sleep */ 316455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; 3165ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3166a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 316755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, 316855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int framelen, int dtim) 3169a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 317055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_finalize_join *cmd; 317155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct ieee80211_mgmt *payload = frame; 317255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int payload_len; 3173a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3174a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3175a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3176a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3177a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3178a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 317955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); 3180a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 318155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); 318255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 318355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = framelen - ieee80211_hdrlen(payload->frame_control); 318455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (payload_len < 0) 318555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = 0; 318655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek else if (payload_len > MWL8K_FJ_BEACON_MAXLEN) 318755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek payload_len = MWL8K_FJ_BEACON_MAXLEN; 318855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 318955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); 3190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3192a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3194a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3195a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3196a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3197a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 319855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RTS_THRESHOLD. 3199a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 320055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rts_threshold { 3201a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 3202a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 320355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 threshold; 3204ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3205a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3206c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekstatic int 3207c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhekmwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) 3208a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 320955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rts_threshold *cmd; 3210a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3211a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3212a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3214a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 321655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); 3217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3218c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 3219c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek cmd->threshold = cpu_to_le16(rts_thresh); 3220a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3221a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3222a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3224a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3225a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3226a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3227a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 322855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_SLOT. 3229a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 323055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_slot { 3231a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 3232a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 323355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 short_slot; 3234ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3235a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 323655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) 3237a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 323855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_slot *cmd; 3239a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3240a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3241a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3242a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3243a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3244a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 324555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); 3246a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 324755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 324855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->short_slot = short_slot_time; 3249a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3250a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3251a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3252a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3253a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3254a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3255a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3256a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3257a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * CMD_SET_EDCA_PARAMS. 3258a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3259a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstruct mwl8k_cmd_set_edca_params { 3260a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 3261a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3262a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* See MWL8K_SET_EDCA_XXX below */ 3263a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 action; 3264a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3265a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* TX opportunity in units of 32 us */ 3266a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek __le16 txop; 3267a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 32682e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek union { 32692e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 32702e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 32712e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_max; 32722e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 32732e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 32742e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __le32 log_cw_min; 32752e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 32762e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 32772e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 32782e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek 32792e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 32802e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 32812e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } ap; 32822e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct { 32832e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of max contention period: 0...15 */ 32842e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_max; 3285a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 32862e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Log exponent of min contention period: 0...15 */ 32872e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 log_cw_min; 3288a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 32892e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* Adaptive interframe spacing in units of 32us */ 32902e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 aifs; 3291a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 32922e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek /* TX queue to configure */ 32932e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek __u8 txq; 32942e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } sta; 32952e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek }; 3296ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3297a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3298a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_CW 0x01 3299a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_TXOP 0x02 3300a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_AIFS 0x04 3301a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3302a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek#define MWL8K_SET_EDCA_ALL (MWL8K_SET_EDCA_CW | \ 3303a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_TXOP | \ 3304a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek MWL8K_SET_EDCA_AIFS) 3305a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3306a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int 330755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekmwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, 330855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u16 cw_min, __u16 cw_max, 330955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 aifs, __u16 txop) 3310a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 33112e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3312a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_set_edca_params *cmd; 3313a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3314a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3315a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3316a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3317a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3318a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3319a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); 3320a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3321a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); 3322a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->txop = cpu_to_le16(txop); 33232e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek if (priv->ap_fw) { 33242e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1)); 33252e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1)); 33262e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.aifs = aifs; 33272e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->ap.txq = qnum; 33282e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } else { 33292e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1); 33302e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1); 33312e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.aifs = aifs; 33322e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek cmd->sta.txq = qnum; 33332e484c8964f7845d320eb1161c514dbfcafdda78Lennert Buytenhek } 3334a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3335a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3336a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3337a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3338a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3339a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3340a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3341a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 334255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_WMM_MODE. 3343a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 334455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_wmm_mode { 3345a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_cmd_pkt header; 334655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 3347ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3348a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 334955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) 3350a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 335155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 335255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_wmm_mode *cmd; 3353a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3354a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3355a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3356a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3357a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3358a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 335955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); 3360a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 336155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(!!enable); 3362a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3363a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3364a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 336516cec43da50c4b4702653ca710549fd3457a4e6cLennert Buytenhek 336655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (!rc) 336755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek priv->wmm_enabled = enable; 3368a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3369a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3370a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3371a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3372a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 337355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_MIMO_CONFIG. 3374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 337555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_mimo_config { 337655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 337755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 337855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 rx_antenna_map; 337955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 tx_antenna_map; 3380ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3381a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 338255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) 3383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 338455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_mimo_config *cmd; 3385a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3388a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3389a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 339155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG); 3392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 339355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET); 339455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->rx_antenna_map = rx; 339555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->tx_antenna_map = tx; 3396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3397a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3398a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3399a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3400a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3401a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3402a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3403a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 3404b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek * CMD_USE_FIXED_RATE (STA version). 3405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 3406b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_sta { 3407b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_pkt header; 3408b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 action; 3409b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 allow_rate_drop; 3410b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 num_rates; 3411b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct { 3412b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 is_ht_rate; 3413b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 enable_retry; 3414b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate; 3415b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 retry_count; 3416b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek } rate_entry[8]; 3417b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 rate_type; 3418b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved1; 3419b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek __le32 reserved2; 3420ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3421a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3422b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_USE_AUTO_RATE 0x0002 3423b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek#define MWL8K_UCAST_RATE 0 3424a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3425b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhekstatic int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) 3426a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 3427b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_sta *cmd; 3428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 3429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3431a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (cmd == NULL) 3432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return -ENOMEM; 3433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 3435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3436b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 3437b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); 3438a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek kfree(cmd); 3441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 3442a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 3443a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 3444a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 344555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 3446088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek * CMD_USE_FIXED_RATE (AP version). 3447088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek */ 3448088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstruct mwl8k_cmd_use_fixed_rate_ap { 3449088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_pkt header; 3450088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 action; 3451088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 allow_rate_drop; 3452088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 num_rates; 3453088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_rate_entry_ap { 3454088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 is_ht_rate; 3455088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 enable_retry; 3456088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 rate; 3457088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek __le32 retry_count; 3458088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek } rate_entry[4]; 3459088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate; 3460088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 multicast_rate_type; 3461088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek u8 management_rate; 3462ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3463088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3464088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekstatic int 3465088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhekmwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) 3466088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek{ 3467088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek struct mwl8k_cmd_use_fixed_rate_ap *cmd; 3468088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek int rc; 3469088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3470088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3471088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek if (cmd == NULL) 3472088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return -ENOMEM; 3473088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3474088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); 3475088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3476088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); 3477088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->multicast_rate = mcast; 3478088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek cmd->management_rate = mgmt; 3479088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3480088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 3481088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek kfree(cmd); 3482088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3483088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek return rc; 3484088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek} 3485088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek 3486088aab8b62666a002907c912cd346ae6dc9f42b7Lennert Buytenhek/* 348755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_ENABLE_SNIFFER. 348855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 348955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_enable_sniffer { 349055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 349155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 3492ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 349355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 349455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) 349555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 349655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_enable_sniffer *cmd; 349755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 349855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 349955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 350055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 350155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 350255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 350355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); 350455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 350555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le32(!!enable); 350655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 350755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 350855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 350955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 351055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 351155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 351255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3513197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powarstruct mwl8k_cmd_update_mac_addr { 351455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 351555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek union { 351655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct { 351755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mac_type; 351855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 351955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } mbss; 352055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 mac_addr[ETH_ALEN]; 352155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek }; 3522ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 352355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3524ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 3525ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 3526ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_PRIMARY_AP 2 3527ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek#define MWL8K_MAC_TYPE_SECONDARY_AP 3 3528a9e00b151ec2121b7ae09d84a2b5a68b6461e98aLennert Buytenhek 3529197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powarstatic int mwl8k_cmd_update_mac_addr(struct ieee80211_hw *hw, 3530197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar struct ieee80211_vif *vif, u8 *mac, bool set) 353155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 353255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 3533ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3534197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar struct mwl8k_cmd_update_mac_addr *cmd; 3535ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek int mac_type; 353655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 353755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3538ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3539ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { 3540ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) 3541af458831c49d634027811b6cf9072cdcd03961e8Yogesh Ashok Powar if (priv->ap_fw) 3542af458831c49d634027811b6cf9072cdcd03961e8Yogesh Ashok Powar mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; 3543af458831c49d634027811b6cf9072cdcd03961e8Yogesh Ashok Powar else 3544af458831c49d634027811b6cf9072cdcd03961e8Yogesh Ashok Powar mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; 3545ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3546ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; 3547ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { 3548ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) 3549ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; 3550ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek else 3551ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; 3552ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 3553ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 355455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 355555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 355655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 355755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3558197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar if (set) 3559197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); 3560197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar else 3561197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar cmd->header.code = cpu_to_le16(MWL8K_CMD_DEL_MAC_ADDR); 3562197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar 356355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 356455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (priv->ap_fw) { 3565ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek cmd->mbss.mac_type = cpu_to_le16(mac_type); 356655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); 356755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } else { 356855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek memcpy(cmd->mac_addr, mac, ETH_ALEN); 356955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek } 357055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 3571aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 357255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 357355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 357455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 357555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 357655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 357755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 3578197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar * MWL8K_CMD_SET_MAC_ADDR. 3579197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar */ 3580197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powarstatic inline int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, 3581197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar struct ieee80211_vif *vif, u8 *mac) 3582197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar{ 3583197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar return mwl8k_cmd_update_mac_addr(hw, vif, mac, true); 3584197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar} 3585197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar 3586197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar/* 3587197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar * MWL8K_CMD_DEL_MAC_ADDR. 3588197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar */ 3589197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powarstatic inline int mwl8k_cmd_del_mac_addr(struct ieee80211_hw *hw, 3590197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar struct ieee80211_vif *vif, u8 *mac) 3591197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar{ 3592197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar return mwl8k_cmd_update_mac_addr(hw, vif, mac, false); 3593197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar} 3594197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar 3595197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar/* 359655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_SET_RATEADAPT_MODE. 359755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 359855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_set_rate_adapt_mode { 359955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 360055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 action; 360155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le16 mode; 3602ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 360355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 360455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstatic int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) 360555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 360655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_set_rate_adapt_mode *cmd; 360755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 360855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 360955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 361055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 361155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 361255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 361355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE); 361455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 361555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_CMD_SET); 361655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->mode = cpu_to_le16(mode); 361755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 361855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 361955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 362055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 362155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 362255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 362355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 362455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek/* 36253aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam * CMD_GET_WATCHDOG_BITMAP. 36263aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam */ 36273aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadamstruct mwl8k_cmd_get_watchdog_bitmap { 36283aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam struct mwl8k_cmd_pkt header; 36293aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam u8 bitmap; 36303aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam} __packed; 36313aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36323aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadamstatic int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) 36333aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam{ 36343aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam struct mwl8k_cmd_get_watchdog_bitmap *cmd; 36353aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam int rc; 36363aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36373aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 36383aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam if (cmd == NULL) 36393aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam return -ENOMEM; 36403aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36413aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); 36423aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 36433aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36443aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam rc = mwl8k_post_cmd(hw, &cmd->header); 36453aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam if (!rc) 36463aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam *bitmap = cmd->bitmap; 36473aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36483aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam kfree(cmd); 36493aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36503aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam return rc; 36513aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam} 36523aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 3653cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar#define MWL8K_WMM_QUEUE_NUMBER 3 3654cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar 3655cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powarstatic void mwl8k_destroy_ba(struct ieee80211_hw *hw, 3656cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar u8 idx); 3657cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar 36583aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadamstatic void mwl8k_watchdog_ba_events(struct work_struct *work) 36593aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam{ 36603aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam int rc; 36613aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam u8 bitmap = 0, stream_index; 36623aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam struct mwl8k_ampdu_stream *streams; 36633aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam struct mwl8k_priv *priv = 36643aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam container_of(work, struct mwl8k_priv, watchdog_ba_handle); 3665cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar struct ieee80211_hw *hw = priv->hw; 3666cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar int i; 3667cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar u32 status = 0; 3668cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar 3669cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar mwl8k_fw_lock(hw); 36703aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36713aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); 36723aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam if (rc) 3673cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar goto done; 36743aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 3675cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar spin_lock(&priv->stream_lock); 36763aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 36773aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam /* the bitmap is the hw queue number. Map it to the ampdu queue. */ 3678cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) { 3679cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar if (bitmap & (1 << i)) { 3680cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) % 3681cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar TOTAL_HW_TX_QUEUES; 3682cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar streams = &priv->ampdu[stream_index]; 3683cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar if (streams->state == AMPDU_STREAM_ACTIVE) { 3684cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar ieee80211_stop_tx_ba_session(streams->sta, 3685cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar streams->tid); 3686cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar spin_unlock(&priv->stream_lock); 3687cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar mwl8k_destroy_ba(hw, stream_index); 3688cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar spin_lock(&priv->stream_lock); 3689cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar } 3690cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar } 3691cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar } 36923aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 3693cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar spin_unlock(&priv->stream_lock); 3694cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powardone: 3695c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar atomic_dec(&priv->watchdog_event_pending); 3696cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 3697cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG), 3698cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 3699cfacba12f573abd04a202e3e86c09f246339071fYogesh Ashok Powar mwl8k_fw_unlock(hw); 37003aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam return; 37013aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam} 37023aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 37033aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 37043aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam/* 3705b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * CMD_BSS_START. 3706b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 3707b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstruct mwl8k_cmd_bss_start { 3708b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_pkt header; 3709b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek __le32 enable; 3710ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 3711b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3712aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhekstatic int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, 3713aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek struct ieee80211_vif *vif, int enable) 3714b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3715b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_bss_start *cmd; 3716e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3717e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar struct mwl8k_priv *priv = hw->priv; 3718b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3719b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3720e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid))) 3721e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar return 0; 3722e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 3723e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid))) 3724e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar return 0; 3725e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 3726b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3727b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3728b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3729b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3730b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); 3731b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3732b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->enable = cpu_to_le32(enable); 3733b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3734aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3735b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3736b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3737e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (!rc) { 3738e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (enable) 3739e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar priv->running_bsses |= (1 << mwl8k_vif->macid); 3740e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar else 3741e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar priv->running_bsses &= ~(1 << mwl8k_vif->macid); 3742e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar } 3743b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3744b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3745b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3746e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powarstatic void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap) 3747e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar{ 3748e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar struct mwl8k_priv *priv = hw->priv; 3749e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar struct mwl8k_vif *mwl8k_vif, *tmp_vif; 3750e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar struct ieee80211_vif *vif; 3751e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 3752e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) { 3753e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar vif = mwl8k_vif->vif; 3754e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 3755e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (!(bitmap & (1 << mwl8k_vif->macid))) 3756e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar continue; 3757e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 3758e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar if (vif->type == NL80211_IFTYPE_AP) 3759e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar mwl8k_cmd_bss_start(hw, vif, enable); 3760e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar } 3761e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar} 3762b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek/* 37635faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam * CMD_BASTREAM. 37645faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam */ 37655faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 37665faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam/* 37675faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam * UPSTREAM is tx direction 37685faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam */ 37695faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 37705faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 37715faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 3772ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powarenum ba_stream_action_type { 37735faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_BA_CREATE, 37745faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_BA_UPDATE, 37755faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_BA_DESTROY, 37765faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_BA_FLUSH, 37775faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam MWL8K_BA_CHECK, 3778ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar}; 37795faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 37805faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 37815faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstruct mwl8k_create_ba_stream { 37825faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 flags; 37835faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 idle_thrs; 37845faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 bar_thrs; 37855faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 window_size; 37865faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 peer_mac_addr[6]; 37875faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 dialog_token; 37885faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 tid; 37895faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 queue_id; 37905faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 param_info; 37915faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 ba_context; 37925faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 reset_seq_no_flag; 37935faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le16 curr_seq_no; 37945faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam u8 sta_src_mac_addr[6]; 37955faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} __packed; 37965faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 37975faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstruct mwl8k_destroy_ba_stream { 37985faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 flags; 37995faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 ba_context; 38005faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} __packed; 38015faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38025faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstruct mwl8k_cmd_bastream { 38035faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_cmd_pkt header; 38045faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam __le32 action; 38055faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam union { 38065faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_create_ba_stream create_params; 38075faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_destroy_ba_stream destroy_params; 38085faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam }; 38095faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} __packed; 38105faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38115faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstatic int 3812f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powarmwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, 3813f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar struct ieee80211_vif *vif) 38145faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam{ 38155faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_cmd_bastream *cmd; 38165faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam int rc; 38175faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38185faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 38195faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam if (cmd == NULL) 38205faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam return -ENOMEM; 38215faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38225faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); 38235faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 38245faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38255faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_BA_CHECK); 38265faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38275faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.queue_id = stream->idx; 38285faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, 38295faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam ETH_ALEN); 38305faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.tid = stream->tid; 38315faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38325faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.flags = 38335faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | 38345faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); 38355faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 3836f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 38375faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38385faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam kfree(cmd); 38395faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38405faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam return rc; 38415faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} 38425faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38435faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstatic int 38445faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadammwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, 3845f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar u8 buf_size, struct ieee80211_vif *vif) 38465faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam{ 38475faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_cmd_bastream *cmd; 38485faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam int rc; 38495faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38505faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 38515faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam if (cmd == NULL) 38525faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam return -ENOMEM; 38535faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38545faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38555faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); 38565faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 38575faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38585faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_BA_CREATE); 38595faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38605faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); 38615faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.window_size = cpu_to_le32((u32)buf_size); 38625faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.queue_id = stream->idx; 38635faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38645faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); 38655faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.tid = stream->tid; 38665faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.curr_seq_no = cpu_to_le16(0); 38675faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.reset_seq_no_flag = 1; 38685faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38695faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.param_info = 38705faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam (stream->sta->ht_cap.ampdu_factor & 38715faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam IEEE80211_HT_AMPDU_PARM_FACTOR) | 38725faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam ((stream->sta->ht_cap.ampdu_density << 2) & 38735faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam IEEE80211_HT_AMPDU_PARM_DENSITY); 38745faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38755faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->create_params.flags = 38765faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | 38775faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam BASTREAM_FLAG_DIRECTION_UPSTREAM); 38785faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 3879f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 38805faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38815faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", 38825faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam stream->sta->addr, stream->tid); 38835faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam kfree(cmd); 38845faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38855faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam return rc; 38865faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} 38875faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38885faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadamstatic void mwl8k_destroy_ba(struct ieee80211_hw *hw, 388907f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar u8 idx) 38905faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam{ 38915faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam struct mwl8k_cmd_bastream *cmd; 38925faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38935faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 38945faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam if (cmd == NULL) 38955faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam return; 38965faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 38975faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); 38985faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 38995faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); 39005faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 390107f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar cmd->destroy_params.ba_context = cpu_to_le32(idx); 39025faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam mwl8k_post_cmd(hw, &cmd->header); 39035faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 390407f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx); 39055faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 39065faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam kfree(cmd); 39075faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam} 39085faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam 39095faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5Nishant Sarmukadam/* 39103f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek * CMD_SET_NEW_STN. 39113f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek */ 39123f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstruct mwl8k_cmd_set_new_stn { 39133f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_pkt header; 39143f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 aid; 39153f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_addr[6]; 39163f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stn_id; 39173f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 action; 39183f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 rsvd; 39193f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 legacy_rates; 39203f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 ht_rates[4]; 39213f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 cap_info; 39223f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 ht_capabilities_info; 39233f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 mac_ht_param_info; 39243f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 rev; 39253f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 control_channel; 39263f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_channel; 39273f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 op_mode; 39283f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le16 stbc; 39293f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 add_qos_info; 39303f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __u8 is_qos_sta; 39313f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek __le32 fw_sta_ptr; 3932ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 39333f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 39343f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_ADD 0 39353f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek#define MWL8K_STA_ACTION_REMOVE 2 39363f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 39373f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, 39383f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, 39393f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_sta *sta) 39403f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 39413f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 39428707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 39433f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek int rc; 39443f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 39453f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 39463f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 39473f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 39483f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 39493f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 39503f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 39513f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->aid = cpu_to_le16(sta->aid); 39523f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); 39533f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->stn_id = cpu_to_le16(sta->aid); 39543f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); 39558707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 39568707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 39578707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 39588707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 39598707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek cmd->legacy_rates = cpu_to_le32(rates); 39603f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (sta->ht_cap.ht_supported) { 39613f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; 39623f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; 39633f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; 39643f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; 39653f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); 39663f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | 39673f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 39683f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->is_qos_sta = 1; 39693f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek } 39703f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3971aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 39723f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 39733f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 39743f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 39753f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 39763f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 3977b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, 3978b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_vif *vif) 3979b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 3980b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 3981b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 3982b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3983b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3984b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (cmd == NULL) 3985b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return -ENOMEM; 3986b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3987b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 3988b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3989b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); 3990b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3991aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3992b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree(cmd); 3993b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 3994b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return rc; 3995b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 3996b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 39973f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhekstatic int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, 39983f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 39993f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 40003f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_cmd_set_new_stn *cmd; 40010dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar struct mwl8k_priv *priv = hw->priv; 40020dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar int rc, i; 40030dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar u8 idx; 40040dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar 40050dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar spin_lock(&priv->stream_lock); 40060dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar /* Destroy any active ampdu streams for this sta */ 40070dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) { 40080dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar struct mwl8k_ampdu_stream *s; 40090dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar s = &priv->ampdu[i]; 40100dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar if (s->state != AMPDU_NO_STREAM) { 40110dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) { 40120dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar if (s->state == AMPDU_STREAM_ACTIVE) { 40130dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar idx = s->idx; 40140dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar spin_unlock(&priv->stream_lock); 40150dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar mwl8k_destroy_ba(hw, idx); 40160dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar spin_lock(&priv->stream_lock); 40170dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar } else if (s->state == AMPDU_STREAM_NEW) { 40180dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar mwl8k_remove_stream(hw, s); 40190dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar } 40200dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar } 40210dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar } 40220dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar } 40230dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar 40240dd13a48a913f096cb44dbcb6c1daebd94b2cf84Yogesh Ashok Powar spin_unlock(&priv->stream_lock); 40253f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 40263f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 40273f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek if (cmd == NULL) 40283f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return -ENOMEM; 40293f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 40303f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); 40313f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 40323f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek memcpy(cmd->mac_addr, addr, ETH_ALEN); 40333f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); 40343f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 4035aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 40363f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek kfree(cmd); 40373f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 40383f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek return rc; 40393f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek} 40403f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 40413f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek/* 4042fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam * CMD_UPDATE_ENCRYPTION. 4043fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam */ 4044fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4045fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MAX_ENCR_KEY_LENGTH 16 4046fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MIC_KEY_LENGTH 8 4047fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4048fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_update_encryption { 4049fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 4050fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4051fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 4052fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 4053fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 4054fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 encr_type; 4055fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4056ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar} __packed; 4057fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4058fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstruct mwl8k_cmd_set_key { 4059fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_pkt header; 4060fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4061fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 action; 4062fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 reserved; 4063fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 length; 4064fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_type_id; 4065fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_info; 4066fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 key_id; 4067fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 key_len; 4068fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 key_material[MAX_ENCR_KEY_LENGTH]; 4069fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; 4070fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; 4071fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_rsc_low; 4072fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_rsc_high; 4073fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le16 tkip_tsc_low; 4074fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __le32 tkip_tsc_high; 4075fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam __u8 mac_addr[6]; 4076ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar} __packed; 4077fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4078fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 4079fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_ENABLE, 4080fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_KEY, 4081fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_REMOVE_KEY, 4082fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ENCR_SET_GROUP_KEY, 4083fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 4084fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4085fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 4086fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 4087fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 4088fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 4089fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 4090fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4091fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamenum { 4092fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_WEP, 4093fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_TKIP, 4094fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam MWL8K_ALG_CCMP, 4095fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam}; 4096fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4097fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 4098fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 4099fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 4100fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 4101fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam#define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 4102fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4103fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, 4104fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 4105fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 4106fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type) 4107fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 4108fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_update_encryption *cmd; 4109fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 4110fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4111fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 4112fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 4113fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 4114fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4115fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 4116fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 4117fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); 4118fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 4119fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->encr_type = encr_type; 4120fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4121fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 4122fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 4123fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4124fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 4125fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 4126fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4127fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, 4128fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 4129fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 4130fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 4131fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 4132fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->header.length = cpu_to_le16(sizeof(*cmd)); 4133fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->length = cpu_to_le16(sizeof(*cmd) - 4134fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam offsetof(struct mwl8k_cmd_set_key, length)); 4135fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_id = cpu_to_le32(key->keyidx); 4136fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_len = cpu_to_le16(key->keylen); 4137fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->mac_addr, addr, ETH_ALEN); 4138fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4139fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 4140fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 4141fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 4142fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); 4143fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->keyidx == 0) 4144fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); 4145fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4146fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4147fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 4148fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); 4149fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 4150fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 4151fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 4152fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID 4153fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam | MWL8K_KEY_FLAG_TSC_VALID); 4154fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4155fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 4156fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); 4157fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 4158fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 4159fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 4160fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4161fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 4162fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOTSUPP; 4163fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 4164fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4165fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return 0; 4166fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 4167fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4168fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, 4169fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 4170fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 4171fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 4172fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 4173fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 4174fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 4175fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int keymlen; 4176fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u32 action; 4177fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 idx; 4178fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4179fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4180fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 4181fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 4182fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 4183fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4184fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 4185fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 4186fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 4187fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4188fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam idx = key->keyidx; 4189fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4190fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 4191fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 4192fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 4193fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_GROUP_KEY; 4194fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4195fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam switch (key->cipher) { 4196fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP40: 4197fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_WEP104: 4198fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (!mwl8k_vif->wep_key_conf[idx].enabled) { 4199fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(mwl8k_vif->wep_key_conf[idx].key, key, 4200fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam sizeof(*key) + key->keylen); 4201fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[idx].enabled = 1; 4202fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 4203fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 42049b571e24a9922f79ed2440b4482cb9f11a8f1889Yogesh Ashok Powar keymlen = key->keylen; 4205fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam action = MWL8K_ENCR_SET_KEY; 4206fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4207fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_TKIP: 4208fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; 4209fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4210fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam case WLAN_CIPHER_SUITE_CCMP: 4211fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam keymlen = key->keylen; 4212fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam break; 4213fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam default: 4214fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = -ENOTSUPP; 4215fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 4216fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 4217fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4218fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam memcpy(cmd->key_material, key->key, keymlen); 4219fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(action); 4220fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4221fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 4222fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 4223fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 4224fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4225fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 4226fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 4227fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4228fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, 4229fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 4230fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr, 4231fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 4232fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 4233fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_cmd_set_key *cmd; 4234fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc; 4235fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4236fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4237fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 4238fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd == NULL) 4239fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -ENOMEM; 4240fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4241fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 4242fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc < 0) 4243fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto done; 4244fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4245fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || 4246d981e05908f85beb68ae0d935e59c5e399d2136eDan Carpenter key->cipher == WLAN_CIPHER_SUITE_WEP104) 4247fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; 4248fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4249fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); 4250fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4251fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 4252fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamdone: 4253fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam kfree(cmd); 4254fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4255fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 4256fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 4257fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4258fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamstatic int mwl8k_set_key(struct ieee80211_hw *hw, 4259fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam enum set_key_cmd cmd_param, 4260fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_vif *vif, 4261fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_sta *sta, 4262fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key) 4263fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam{ 4264fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int rc = 0; 4265fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 encr_type; 4266fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam u8 *addr; 4267fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4268751930cb1d6da7b7891d8ffe84877cbf21915e0dYogesh Ashok Powar struct mwl8k_priv *priv = hw->priv; 4269fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4270751930cb1d6da7b7891d8ffe84877cbf21915e0dYogesh Ashok Powar if (vif->type == NL80211_IFTYPE_STATION && !priv->ap_fw) 4271fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return -EOPNOTSUPP; 4272fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4273fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (sta == NULL) 4274ff7e9f99f7effb385a9be2f7198743c1ad2bb126Yogesh Ashok Powar addr = vif->addr; 4275fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 4276fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam addr = sta->addr; 4277fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4278fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (cmd_param == SET_KEY) { 4279fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); 4280fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 4281fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 4282fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4283fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) 4284fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) 4285fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; 4286fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam else 4287fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; 4288fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4289fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, 4290fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam encr_type); 4291fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 4292fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 4293fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4294fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = true; 4295fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4296fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } else { 4297fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); 4298fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4299fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam if (rc) 4300fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam goto out; 4301fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam } 4302fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadamout: 4303fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return rc; 4304fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam} 4305fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam 4306fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam/* 430755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek * CMD_UPDATE_STADB. 430855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek */ 430925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct ewc_ht_info { 431025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control1; 431125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control2; 431225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 control3; 4313ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 431425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 431525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhekstruct peer_capability_info { 431625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Peer type - AP vs. STA. */ 431725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 peer_type; 431825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 431925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Basic 802.11 capabilities from assoc resp. */ 432025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 basic_caps; 432125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 432225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Set if peer supports 802.11n high throughput (HT). */ 432325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_support; 432425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 432525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Valid if HT is supported. */ 432625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 ht_caps; 432725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 extended_ht_caps; 432825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek struct ewc_ht_info ewc_info; 432925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 433025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* Legacy rate table. Intersection of our rates and peer rates. */ 433125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 legacy_rates[12]; 433225d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 433325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* HT rate table. Intersection of our rates and peer rates. */ 433425d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 ht_rates[16]; 433525d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad[16]; 433625d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 433725d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek /* If set, interoperability mode, no proprietary extensions. */ 433825d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 interop; 433925d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 pad2; 434025d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __u8 station_id; 434125d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek __le16 amsdu_enabled; 4342ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 434325d81b1e1a0cca41a71a08468a7d3a4c751c8565Lennert Buytenhek 434455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhekstruct mwl8k_cmd_update_stadb { 434555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_pkt header; 434655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 434755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* See STADB_ACTION_TYPE */ 434855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 action; 434955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 435055489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer MAC address */ 435155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __u8 peer_addr[ETH_ALEN]; 435255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 435355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek __le32 reserved; 435455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 435555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek /* Peer info - valid during add/update. */ 435655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct peer_capability_info peer_info; 4357ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 435855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 4359a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_MODIFY_ENTRY 1 4360a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_STA_DB_DEL_ENTRY 2 4361a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4362a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek/* Peer Entry flags - used to define the type of the peer node */ 4363a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek#define MWL8K_PEER_TYPE_ACCESSPOINT 2 4364a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4365a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, 4366c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_vif *vif, 436713935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek struct ieee80211_sta *sta) 436855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek{ 436955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 4370a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct peer_capability_info *p; 43718707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek u32 rates; 437255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek int rc; 437355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 437455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 437555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (cmd == NULL) 437655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return -ENOMEM; 437755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 437855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 437955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 4380a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); 438113935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); 438255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 4383a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p = &cmd->peer_info; 4384a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; 4385a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); 438613935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->ht_support = sta->ht_cap.ht_supported; 4387b603742f49c3ec922522602e18ac22e8f6835132John W. Linville p->ht_caps = cpu_to_le16(sta->ht_cap.cap); 438813935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | 438913935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek ((sta->ht_cap.ampdu_density & 7) << 2); 43908707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 43918707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; 43928707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 43938707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; 43948707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek legacy_rate_mask_to_array(p->legacy_rates, rates); 439513935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); 4396a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->interop = 1; 4397a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek p->amsdu_enabled = 0; 4398a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4399a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 4400c4f74d35cac7cbc44877313b69550e2f5aeae77dNickolai Zeldovich if (!rc) 4401c4f74d35cac7cbc44877313b69550e2f5aeae77dNickolai Zeldovich rc = p->station_id; 4402a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek kfree(cmd); 4403a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4404c4f74d35cac7cbc44877313b69550e2f5aeae77dNickolai Zeldovich return rc; 4405a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek} 4406a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4407a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhekstatic int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, 4408a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct ieee80211_vif *vif, u8 *addr) 4409a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek{ 4410a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek struct mwl8k_cmd_update_stadb *cmd; 4411a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek int rc; 4412a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4413a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 4414a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek if (cmd == NULL) 4415a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek return -ENOMEM; 4416a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek 4417a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); 4418a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->header.length = cpu_to_le16(sizeof(*cmd)); 4419a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); 4420bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek memcpy(cmd->peer_addr, addr, ETH_ALEN); 442155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 4422a680400e8ac32adda81b5e2d7f23dfac63e064feLennert Buytenhek rc = mwl8k_post_cmd(hw, &cmd->header); 442355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek kfree(cmd); 442455489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 442555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return rc; 442655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek} 442755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek 4428a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4429a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 4430a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Interrupt handling. 4431a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 4432a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic irqreturn_t mwl8k_interrupt(int irq, void *dev_id) 4433a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4434a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = dev_id; 4435a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4436a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek u32 status; 4437a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4438a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 4439a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (!status) 4440a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_NONE; 4441a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 44421e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (status & MWL8K_A2H_INT_TX_DONE) { 44431e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek status &= ~MWL8K_A2H_INT_TX_DONE; 44441e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 44451e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 44461e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 4447a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_RX_READY) { 444867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek status &= ~MWL8K_A2H_INT_RX_READY; 444967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 4450a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4451a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 44523aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam if (status & MWL8K_A2H_INT_BA_WATCHDOG) { 4453c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG, 4454c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 4455c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar 4456c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar atomic_inc(&priv->watchdog_event_pending); 44573aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam status &= ~MWL8K_A2H_INT_BA_WATCHDOG; 44583aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam ieee80211_queue_work(hw, &priv->watchdog_ba_handle); 44593aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam } 44603aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam 446167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (status) 446267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 446367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 4464a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_OPC_DONE) { 4465618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (priv->hostcmd_wait != NULL) 4466a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek complete(priv->hostcmd_wait); 4467a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4468a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4469a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { 4470618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek if (!mutex_is_locked(&priv->fw_mutex) && 447188de754ad59025eba797e7a8375807755577f450Lennert Buytenhek priv->radio_on && priv->pending_tx_pkts) 4472618952a7b19b796fce98364fb26551cbe3e16a75Lennert Buytenhek mwl8k_tx_start(priv); 4473a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4474a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4475a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return IRQ_HANDLED; 4476a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4477a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 44781e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhekstatic void mwl8k_tx_poll(unsigned long data) 44791e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek{ 44801e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 44811e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 44821e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int limit; 44831e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek int i; 44841e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 44851e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit = 32; 44861e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 44871e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_lock_bh(&priv->tx_lock); 44881e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 4489e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 44901e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek limit -= mwl8k_txq_reclaim(hw, i, limit, 0); 44911e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 44921e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { 44931e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek complete(priv->tx_wait); 44941e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->tx_wait = NULL; 44951e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 44961e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 44971e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek spin_unlock_bh(&priv->tx_lock); 44981e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 44991e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek if (limit) { 45001e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek writel(~MWL8K_A2H_INT_TX_DONE, 45011e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 45021e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } else { 45031e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_schedule(&priv->poll_tx_task); 45041e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek } 45051e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek} 45061e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek 450767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhekstatic void mwl8k_rx_poll(unsigned long data) 450867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek{ 450967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct ieee80211_hw *hw = (struct ieee80211_hw *)data; 451067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 451167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek int limit; 451267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 451367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit = 32; 451467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_process(hw, 0, limit); 451567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek limit -= rxq_refill(hw, 0, limit); 451667e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 451767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek if (limit) { 451867e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek writel(~MWL8K_A2H_INT_RX_READY, 451967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 452067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } else { 452167e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_schedule(&priv->poll_rx_task); 452267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek } 452367e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek} 452467e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek 4525a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4526a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek/* 4527a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Core driver operations. 4528a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 452936323f817af0376c78612cfdab714b0feb05fea5Thomas Huehnstatic void mwl8k_tx(struct ieee80211_hw *hw, 453036323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn struct ieee80211_tx_control *control, 453136323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn struct sk_buff *skb) 4532a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4533a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4534a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int index = skb_get_queue_mapping(skb); 4535a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45369189c10087a738c764046fa27651d332594cd8e6Lennert Buytenhek if (!priv->radio_on) { 4537c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_debug(hw->wiphy, 4538c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "dropped TX frame since radio disabled\n"); 4539a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(skb); 45407bb4568372856688bc070917265bce0b88bb7d4dJohannes Berg return; 4541a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4542a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 454336323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn mwl8k_txq_xmit(hw, index, control->sta, skb); 4544a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4545a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4546a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_start(struct ieee80211_hw *hw) 4547a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4548a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4549a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 4550a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4551a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 4552a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 4553a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 4554bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo priv->irq = -1; 45555db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 45562ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek return -EIO; 4557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4558bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo priv->irq = priv->pdev->irq; 4559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 456067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Enable TX reclaim and RX tasklets. */ 45611e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_enable(&priv->poll_tx_task); 456267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_enable(&priv->poll_rx_task); 45632ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 4564a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Enable interrupts */ 4565c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 456612488e01fb2b06bb3f6ee137efc88e29d827817eNishant Sarmukadam iowrite32(MWL8K_A2H_EVENTS, 456712488e01fb2b06bb3f6ee137efc88e29d827817eNishant Sarmukadam priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 4568a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45692ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek rc = mwl8k_fw_lock(hw); 45702ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) { 457155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 4572a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45735e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!priv->ap_fw) { 45745e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 457555489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_enable_sniffer(hw, 0); 4576a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45775e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 45785e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_pre_scan(hw); 45795e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek 45805e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek if (!rc) 45815e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek rc = mwl8k_cmd_set_post_scan(hw, 45825e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek "\x00\x00\x00\x00\x00\x00"); 45835e4cf166f4a9801ea9ca1bab210d763d27538de6Lennert Buytenhek } 45842ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 45852ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 458655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_rateadapt_mode(hw, 0); 4587a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45882ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (!rc) 458955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 0); 4590a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 45912ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek mwl8k_fw_unlock(hw); 45922ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 45932ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek 45942ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek if (rc) { 45952ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 45962ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek free_irq(priv->pdev->irq, hw); 4597bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo priv->irq = -1; 45981e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 459967e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 46004850b6d355b457738fe7d872c833474dbec25304Nishant Sarmukadam } else { 46014850b6d355b457738fe7d872c833474dbec25304Nishant Sarmukadam ieee80211_wake_queues(hw); 46022ec610cb6d57032cdab89781e37ed3e442c73367Lennert Buytenhek } 4603a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4604a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 4605a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4606a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4607a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_stop(struct ieee80211_hw *hw) 4608a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4609a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4610a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 4611a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 46126b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!priv->hw_restart_in_progress) 46136b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_cmd_radio_disable(hw); 4614a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4615a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 4616a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4617a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 4618a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 4619bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo if (priv->irq != -1) { 4620bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo free_irq(priv->pdev->irq, hw); 4621bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo priv->irq = -1; 4622bf3ca7f752d8f5009c9a83db56035566f3e313deBrian Cavagnolo } 4623a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4624a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop finalize join worker */ 4625a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek cancel_work_sync(&priv->finalize_join_worker); 46263aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam cancel_work_sync(&priv->watchdog_ba_handle); 4627a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->beacon_skb != NULL) 4628a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek dev_kfree_skb(priv->beacon_skb); 4629a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 463067e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Stop TX reclaim and RX tasklets. */ 46311e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_disable(&priv->poll_tx_task); 463267e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_disable(&priv->poll_rx_task); 4633a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4634a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 4635e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 4636efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 4637a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 46390863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image); 46400863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 4641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_add_interface(struct ieee80211_hw *hw, 4642f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct ieee80211_vif *vif) 4643a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4644a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4645a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 4646ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek u32 macids_supported; 46470863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo int macid, rc; 46480863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 4649a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4650a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4651a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Reject interface creation if sniffer mode is active, as 4652a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * STA operation is mutually exclusive with hardware sniffer 4653b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * mode. (Sniffer mode is only used on STA firmware.) 4654a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 4655a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 4656c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 4657c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "unable to create STA interface because sniffer mode is enabled\n"); 4658a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return -EINVAL; 4659a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 4660a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 46610863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 4662ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek switch (vif->type) { 4663ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_AP: 46640863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!priv->ap_fw && di->fw_image_ap) { 46650863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* we must load the ap fw to meet this request */ 46660863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (!list_empty(&priv->vif_list)) 46670863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return -EBUSY; 46680863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo rc = mwl8k_reload_firmware(hw, di->fw_image_ap); 46690863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (rc) 46700863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo return rc; 46710863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 4672ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->ap_macids_supported; 4673ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 4674ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek case NL80211_IFTYPE_STATION: 46750863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo if (priv->ap_fw && di->fw_image_sta) { 4676d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar if (!list_empty(&priv->vif_list)) { 4677d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar wiphy_warn(hw->wiphy, "AP interface is running.\n" 4678d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar "Adding STA interface for WDS"); 4679d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar } else { 4680d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar /* we must load the sta fw to 4681d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar * meet this request. 4682d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar */ 4683d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar rc = mwl8k_reload_firmware(hw, 4684d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar di->fw_image_sta); 4685d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar if (rc) 4686d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar return rc; 4687d59c1cfd7c106f53272143bc3f05b0b15bdd5dfaYogesh Ashok Powar } 46880863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } 4689ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macids_supported = priv->sta_macids_supported; 4690ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek break; 4691ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek default: 4692ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EINVAL; 4693ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek } 4694ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 4695ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek macid = ffs(macids_supported & ~priv->macids_used); 4696ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek if (!macid--) 4697ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek return -EBUSY; 4698ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek 4699f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek /* Setup driver private area. */ 47001ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg mwl8k_vif = MWL8K_VIF(vif); 4701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); 4702f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif->vif = vif; 4703ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek mwl8k_vif->macid = macid; 4704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_vif->seqno = 0; 4705d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); 4706d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_vif->is_hw_crypto_enabled = false; 4707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4708aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek /* Set the mac address. */ 4709aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); 4710aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 4711aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek if (priv->ap_fw) 4712aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_new_stn_add_self(hw, vif); 4713aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek 4714ee0ddf1865954f44ee929d963e2c968eb377f447Lennert Buytenhek priv->macids_used |= 1 << mwl8k_vif->macid; 4715f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek list_add_tail(&mwl8k_vif->list, &priv->vif_list); 4716a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4717a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 4718a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4719a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 47206b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powarstatic void mwl8k_remove_vif(struct mwl8k_priv *priv, struct mwl8k_vif *vif) 47216b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar{ 47226b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* Has ieee80211_restart_hw re-added the removed interfaces? */ 47236b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!priv->macids_used) 47246b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar return; 47256b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47266b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->macids_used &= ~(1 << vif->macid); 47276b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar list_del(&vif->list); 47286b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar} 47296b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 4730a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_remove_interface(struct ieee80211_hw *hw, 47311ed32e4fc8cfc9656cc1101e7f9617d485fcbe7bJohannes Berg struct ieee80211_vif *vif) 4732a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4733a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4734f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4736b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (priv->ap_fw) 4737b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); 4738b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4739197a4e4e1f7ef11458f09b4dd74397baf6758133Yogesh Ashok Powar mwl8k_cmd_del_mac_addr(hw, vif, vif->addr); 474032060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 47416b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_remove_vif(priv, mwl8k_vif); 47426b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar} 47436b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47446b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powarstatic void mwl8k_hw_restart_work(struct work_struct *work) 47456b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar{ 47466b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct mwl8k_priv *priv = 47476b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar container_of(work, struct mwl8k_priv, fw_reload); 47486b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct ieee80211_hw *hw = priv->hw; 47496b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct mwl8k_device_info *di; 47506b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar int rc; 47516b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47526b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* If some command is waiting for a response, clear it */ 47536b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->hostcmd_wait != NULL) { 47546b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar complete(priv->hostcmd_wait); 47556b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hostcmd_wait = NULL; 47566b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar } 47576b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47586b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hw_restart_owner = current; 47596b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar di = priv->device_info; 47606b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_fw_lock(hw); 47616b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47626b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->ap_fw) 47636b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar rc = mwl8k_reload_firmware(hw, di->fw_image_ap); 47646b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar else 47656b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar rc = mwl8k_reload_firmware(hw, di->fw_image_sta); 47666b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47676b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (rc) 47686b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar goto fail; 47696b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47706b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hw_restart_owner = NULL; 47716b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hw_restart_in_progress = false; 47726b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47736b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* 47746b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * This unlock will wake up the queues and 47756b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * also opens the command path for other 47766b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * commands 47776b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 47786b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_fw_unlock(hw); 47796b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47806b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar ieee80211_restart_hw(hw); 47816b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47826b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar wiphy_err(hw->wiphy, "Firmware restarted successfully\n"); 47836b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47846b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar return; 47856b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powarfail: 47866b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_fw_unlock(hw); 47876b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 47886b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar wiphy_err(hw->wiphy, "Firmware restart failed\n"); 4789a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4790a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4791ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekstatic int mwl8k_config(struct ieee80211_hw *hw, u32 changed) 4792a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4793a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_conf *conf = &hw->conf; 4794a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4795ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek int rc; 4796a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 47977595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek if (conf->flags & IEEE80211_CONF_IDLE) { 479855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_radio_disable(hw); 4799ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return 0; 48007595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek } 48017595d67a06466cc00e3aae1b86544278b57481eeLennert Buytenhek 4802ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek rc = mwl8k_fw_lock(hw); 4803ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 4804ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 4805a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 480655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_enable(hw); 4807ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek if (rc) 4808ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek goto out; 4809a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 48100f4316b97d045e9b5b270cafa4b924769699eb3dYogesh Ashok Powar if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 48110f4316b97d045e9b5b270cafa4b924769699eb3dYogesh Ashok Powar rc = mwl8k_cmd_set_rf_channel(hw, conf); 48120f4316b97d045e9b5b270cafa4b924769699eb3dYogesh Ashok Powar if (rc) 48130f4316b97d045e9b5b270cafa4b924769699eb3dYogesh Ashok Powar goto out; 48140f4316b97d045e9b5b270cafa4b924769699eb3dYogesh Ashok Powar } 4815ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek 4816a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (conf->power_level > 18) 4817a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek conf->power_level = 18; 4818a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 481908b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek if (priv->ap_fw) { 48200321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam 48210321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { 48220321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); 48230321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam if (rc) 48240321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam goto out; 48250321708748d8f2ecfffa4a9feafb332312e4e57fNishant Sarmukadam } 482641fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam 4827da62b761769f60e5d476ad882c5ba40fb5d61664Nishant Sarmukadam 482808b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } else { 482941fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); 483041fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam if (rc) 483141fdf0974d9eb81215cb578211a6d8f8a022a9ebNishant Sarmukadam goto out; 483208b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); 483308b063477e45cb366df7204cbcdc79ff86513ef9Lennert Buytenhek } 4834a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4835ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhekout: 4836ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek mwl8k_fw_unlock(hw); 4837a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4838ee03a93241eb954d669fb795b4e5c0eec92eef22Lennert Buytenhek return rc; 4839a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4840a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4841b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4842b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4843b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4844a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 4845a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4846ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8feYogesh Ashok Powar u32 ap_legacy_rates = 0; 484713935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek u8 ap_mcs_rates[16]; 48483a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek int rc; 48493a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 4850c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (mwl8k_fw_lock(hw)) 48513a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek return; 4852a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4853c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 4854c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek * No need to capture a beacon if we're no longer associated. 4855c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 4856c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) 4857c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek priv->capture_beacon = false; 48583a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek 4859c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek /* 486013935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek * Get the AP's legacy and MCS rates. 4861c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek */ 48627dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek if (vif->bss_conf.assoc) { 4863c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek struct ieee80211_sta *ap; 4864c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek 4865c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek rcu_read_lock(); 4866c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4867c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); 4868c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (ap == NULL) { 4869c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4870c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek goto out; 4871c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4872c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 48738707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { 48748707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; 48758707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } else { 48768707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap_legacy_rates = 48778707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; 48788707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek } 487913935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); 4880c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek 4881c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rcu_read_unlock(); 4882c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4883c6e9601071173fed2a77f9c435c41f3b33d1018fLennert Buytenhek 4884c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { 488513935e2cf39b124c9a2ff0349b294e0b1e2e3aefLennert Buytenhek rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); 48863a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 48873a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4888a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4889b71ed2c6ce8b5c3782ed70d67dc9adbd7ed07684Lennert Buytenhek rc = mwl8k_cmd_use_fixed_rate_sta(hw); 48903a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 48913a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4892c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4893a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4894c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 48957dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 48967dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek vif->bss_conf.use_short_preamble); 48973a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 48983a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4899c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4900a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4901c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (changed & BSS_CHANGED_ERP_SLOT) { 49027dc6a7a7635365b140af969e972900866d0bf34bLennert Buytenhek rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); 49033a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 49043a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4905c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4906a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4907c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek if (vif->bss_conf.assoc && 4908c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | 4909c97470dd253831e880c72ea5d022ed7f3aee45c3Lennert Buytenhek BSS_CHANGED_HT))) { 4910c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); 49113a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek if (rc) 49123a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek goto out; 4913c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek } 4914a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4915c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek if (vif->bss_conf.assoc && 4916c3cbbe8a5cd2886e13e9c93e059d9761f3715665Lennert Buytenhek (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { 4917a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 4918a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Finalize the join. Tell rx handler to process 4919a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * next beacon from our BSSID. 4920a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 49210a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); 4922a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->capture_beacon = true; 4923a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 4924a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 49253a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhekout: 49263a980d0a505161b99fc936827cb28ec8eb853284Lennert Buytenhek mwl8k_fw_unlock(hw); 4927a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 4928a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 4929b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4930b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4931b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4932b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4933b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rc; 4934b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4935b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (mwl8k_fw_lock(hw)) 4936b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek return; 4937b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4938b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_ERP_PREAMBLE) { 4939b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek rc = mwl8k_set_radio_preamble(hw, 4940b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek vif->bss_conf.use_short_preamble); 4941b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (rc) 4942b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek goto out; 4943b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4944b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4945b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BASIC_RATES) { 4946b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int idx; 4947b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek int rate; 4948b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4949b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek /* 4950b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * Use lowest supported basic rate for multicasts 4951b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * and management frames (such as probe responses -- 4952b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek * beacons will always go out at 1 Mb/s). 4953b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek */ 4954b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek idx = ffs(vif->bss_conf.basic_rates); 49558707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (idx) 49568707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek idx--; 49578707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek 49588707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) 49598707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_24[idx].hw_value; 49608707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek else 49618707d0262585423cdc053bf8db0912e53915e5e4Lennert Buytenhek rate = mwl8k_rates_50[idx].hw_value; 4962b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4963b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); 4964b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4965b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4966b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { 4967b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct sk_buff *skb; 4968b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4969b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek skb = ieee80211_beacon_get(hw, vif); 4970b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (skb != NULL) { 4971aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); 4972b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek kfree_skb(skb); 4973b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4974b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek } 4975b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4976b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (changed & BSS_CHANGED_BEACON_ENABLED) 4977aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); 4978b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4979b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekout: 4980b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_fw_unlock(hw); 4981b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4982b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4983b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekstatic void 4984b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhekmwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 4985b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct ieee80211_bss_conf *info, u32 changed) 4986b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek{ 4987b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 4988b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4989b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek if (!priv->ap_fw) 4990b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_sta(hw, vif, info, changed); 4991b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek else 4992b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek mwl8k_bss_info_changed_ap(hw, vif, info, changed); 4993b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek} 4994b64fe619e371fc17d8d686d6d44aef1b41317880Lennert Buytenhek 4995e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhekstatic u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, 499622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr_list *mc_list) 4997e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek{ 4998e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek struct mwl8k_cmd_pkt *cmd; 4999e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 5000447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 5001447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * Synthesize and return a command packet that programs the 5002447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * hardware multicast address filter. At this point we don't 5003447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * know whether FIF_ALLMULTI is being requested, but if it is, 5004447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * we'll end up throwing this packet away and creating a new 5005447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * one in mwl8k_configure_filter(). 5006447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 500722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_list); 5008e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 5009e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek return (unsigned long)cmd; 5010e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek} 5011e81cd2d664fe5b75a0db9bb24b43c0dfbde32319Lennert Buytenhek 5012a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekstatic int 5013a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhekmwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, 5014a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int changed_flags, 5015a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek unsigned int *total_flags) 5016a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek{ 5017a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 5018a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5019a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 5020a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Hardware sniffer mode is mutually exclusive with STA 5021a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * operation, so refuse to enable sniffer mode if a STA 5022a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * interface is active. 5023a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 5024f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) { 5025a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (net_ratelimit()) 5026c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, 5027c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "not enabling sniffer mode because STA interface is active\n"); 5028a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 5029a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 5030a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5031a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (!priv->sniffer_enabled) { 503255489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek if (mwl8k_cmd_enable_sniffer(hw, 1)) 5033a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 0; 5034a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = true; 5035a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 5036a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5037a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | 5038a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | 5039a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek FIF_OTHER_BSS; 5040a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5041a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return 1; 5042a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek} 5043a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5044f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhekstatic struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) 5045f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek{ 5046f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (!list_empty(&priv->vif_list)) 5047f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return list_entry(priv->vif_list.next, struct mwl8k_vif, list); 5048f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 5049f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek return NULL; 5050f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek} 5051f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek 5052e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhekstatic void mwl8k_configure_filter(struct ieee80211_hw *hw, 5053e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int changed_flags, 5054e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek unsigned int *total_flags, 5055e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek u64 multicast) 5056e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek{ 5057e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 5058a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; 5059a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5060a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek /* 5061c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * AP firmware doesn't allow fine-grained control over 5062c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek * the receive filter. 5063c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek */ 5064c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek if (priv->ap_fw) { 5065c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 5066c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek kfree(cmd); 5067c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek return; 5068c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek } 5069c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek 5070c0adae2caa1a152c6ec691c5d1e815e47dac2a0cLennert Buytenhek /* 5071a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * Enable hardware sniffer mode if FIF_CONTROL or 5072a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek * FIF_OTHER_BSS is requested. 5073a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek */ 5074a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (*total_flags & (FIF_CONTROL | FIF_OTHER_BSS) && 5075a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek mwl8k_configure_filter_sniffer(hw, changed_flags, total_flags)) { 5076a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek kfree(cmd); 5077a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek return; 5078a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 5079a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5080e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek /* Clear unsupported feature flags */ 5081447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; 5082a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 508390852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek if (mwl8k_fw_lock(hw)) { 508490852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek kfree(cmd); 5085e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek return; 508690852f7aed0f90d443efd7e0f9b82d8ac8186848Lennert Buytenhek } 5087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5088a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek if (priv->sniffer_enabled) { 508955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek mwl8k_cmd_enable_sniffer(hw, 0); 5090a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek priv->sniffer_enabled = false; 5091a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek } 5092a43c49a817f31ce1accc029239827b108319ecf9Lennert Buytenhek 5093e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 509477165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { 509577165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 509677165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Disable the BSS filter. 509777165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 5098e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_pre_scan(hw); 509977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek } else { 5100f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek struct mwl8k_vif *mwl8k_vif; 51010a11dfc36604d9b24deda17461b7ea69851846aaLennert Buytenhek const u8 *bssid; 5102a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 510377165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek /* 510477165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * Enable the BSS filter. 510577165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * 510677165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * If there is an active STA interface, use that 510777165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * interface's BSSID, otherwise use a dummy one 510877165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * (where the OUI part needs to be nonzero for 510977165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek * the BSSID to be accepted by POST_SCAN). 511077165d8809cda1a77bc8752148a6252d7735c12eLennert Buytenhek */ 5111f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek mwl8k_vif = mwl8k_first_vif(priv); 5112f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek if (mwl8k_vif != NULL) 5113f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = mwl8k_vif->vif->bss_conf.bssid; 5114f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek else 5115f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek bssid = "\x01\x00\x00\x00\x00\x00"; 5116a94cc97e14c5750ec2b50b2e4ecdfb0f369ed0f4Lennert Buytenhek 5117e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_cmd_set_post_scan(hw, bssid); 5118a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5119a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5120a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5121447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek /* 5122447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * If FIF_ALLMULTI is being requested, throw away the command 5123447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packet that ->prepare_multicast() built and replace it with 5124447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * a command packet that enables reception of all multicast 5125447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek * packets. 5126447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek */ 5127447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (*total_flags & FIF_ALLMULTI) { 5128447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 512922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, NULL); 5130447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek } 5131447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek 5132447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek if (cmd != NULL) { 5133447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek mwl8k_post_cmd(hw, cmd); 5134447ced07d04525218ae586cd70b759b48bcb1fc8Lennert Buytenhek kfree(cmd); 5135e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek } 5136a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5137e6935ea10485f34b82d16f8dff9aa2bdf32ab4bfLennert Buytenhek mwl8k_fw_unlock(hw); 5138a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5139a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5140a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 5141a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5142c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek return mwl8k_cmd_set_rts_threshold(hw, value); 5143a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5144a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 51454a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_remove(struct ieee80211_hw *hw, 51464a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 51474a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 51483f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek{ 51493f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek struct mwl8k_priv *priv = hw->priv; 51503f5610ff560aeaccf051a6f93f25535c219599a0Lennert Buytenhek 51514a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (priv->ap_fw) 51524a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_set_new_stn_del(hw, vif, sta->addr); 51534a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg else 51544a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg return mwl8k_cmd_update_stadb_del(hw, vif, sta->addr); 5155bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 5156bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 51574a6967b88af02eebeedfbb91bc09160750225bb5Johannes Bergstatic int mwl8k_sta_add(struct ieee80211_hw *hw, 51584a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_vif *vif, 51594a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg struct ieee80211_sta *sta) 5160bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek{ 5161bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 51624a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg int ret; 5163fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam int i; 5164fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 5165fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam struct ieee80211_key_conf *key; 5166bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 51674a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (!priv->ap_fw) { 51684a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); 51694a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg if (ret >= 0) { 51704a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg MWL8K_STA(sta)->peer_id = ret; 5171170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam if (sta->ht_cap.ht_supported) 5172170335432ad36584a6d24fc1fd903024d221ef55Nishant Sarmukadam MWL8K_STA(sta)->is_ampdu_allowed = true; 5173fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam ret = 0; 51744a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg } 5175bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 5176d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } else { 5177d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); 5178bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek } 51794a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg 5180d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam for (i = 0; i < NUM_WEP_KEYS; i++) { 5181d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); 5182d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam if (mwl8k_vif->wep_key_conf[i].enabled) 5183d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam mwl8k_set_key(hw, SET_KEY, vif, sta, key); 5184d9a07d4980514e701555c4f03b865a54c4c48b4aNishant Sarmukadam } 5185fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam return ret; 5186bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek} 5187bbfd9128d3b4a80bea017ebdd47b31a80dc7eadfLennert Buytenhek 51888a3a3c85e44d58f5af0adac74a0b866ba89a1978Eliad Pellerstatic int mwl8k_conf_tx(struct ieee80211_hw *hw, 51898a3a3c85e44d58f5af0adac74a0b866ba89a1978Eliad Peller struct ieee80211_vif *vif, u16 queue, 5190a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek const struct ieee80211_tx_queue_params *params) 5191a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 51923e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek struct mwl8k_priv *priv = hw->priv; 5193a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 5194a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 51953e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek rc = mwl8k_fw_lock(hw); 51963e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!rc) { 5197e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); 51980863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo memcpy(&priv->wmm_params[queue], params, sizeof(*params)); 51990863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo 52003e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek if (!priv->wmm_enabled) 520155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_set_wmm_mode(hw, 1); 5202a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 520385c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam if (!rc) { 5204e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo int q = MWL8K_TX_WMM_QUEUES - 1 - queue; 520585c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam rc = mwl8k_cmd_set_edca_params(hw, q, 520655489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_min, 520755489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->cw_max, 520855489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->aifs, 520955489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek params->txop); 521085c9205c79c794a6eea0c7217db93b4c637f136eNishant Sarmukadam } 52113e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 52123e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek mwl8k_fw_unlock(hw); 5213a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 52143e4f542cfbf5a60f2295b2de9a31bdd14beb7b4aLennert Buytenhek 5215a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 5216a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5217a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5218a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic int mwl8k_get_stats(struct ieee80211_hw *hw, 5219a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_low_level_stats *stats) 5220a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 522155489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek return mwl8k_cmd_get_stat(hw, stats); 5222a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5223a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 52240d462bbb0e20863b6c796abd779bfdb534d60278John W. Linvillestatic int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, 52250d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct survey_info *survey) 52260d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville{ 52270d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct mwl8k_priv *priv = hw->priv; 52280d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville struct ieee80211_conf *conf = &hw->conf; 52290d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 52300d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville if (idx != 0) 52310d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return -ENOENT; 52320d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 52330d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->channel = conf->channel; 52340d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->filled = SURVEY_INFO_NOISE_DBM; 52350d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville survey->noise = priv->noise; 52360d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 52370d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville return 0; 52380d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville} 52390d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville 524065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam#define MAX_AMPDU_ATTEMPTS 5 524165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 5242a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekstatic int 5243a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhekmwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 5244a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek enum ieee80211_ampdu_mlme_action action, 52450b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg struct ieee80211_sta *sta, u16 tid, u16 *ssn, 52460b01f030d38e00650e2db42da083d8647aad40a5Johannes Berg u8 buf_size) 5247a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek{ 524865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 524965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam int i, rc = 0; 525065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam struct mwl8k_priv *priv = hw->priv; 525165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam struct mwl8k_ampdu_stream *stream; 525207f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar u8 *addr = sta->addr, idx; 5253fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar struct mwl8k_sta *sta_info = MWL8K_STA(sta); 525465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 525565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) 525665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam return -ENOTSUPP; 525765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 525865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 525965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam stream = mwl8k_lookup_stream(hw, addr, tid); 526065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 5261a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek switch (action) { 5262a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_START: 5263a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek case IEEE80211_AMPDU_RX_STOP: 526465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 526565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam case IEEE80211_AMPDU_TX_START: 526665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* By the time we get here the hw queues may contain outgoing 526765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * packets for this RA/TID that are not part of this BA 526865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * session. The hw will assign sequence numbers to these 526965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * packets as they go out. So if we query the hw for its next 527065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * sequence number and use that for the SSN here, it may end up 527165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * being wrong, which will lead to sequence number mismatch at 527265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * the recipient. To avoid this, we reset the sequence number 527365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * to O for the first MPDU in this BA stream. 527465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 527565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam *ssn = 0; 527665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (stream == NULL) { 527765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* This means that somebody outside this driver called 527865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * ieee80211_start_tx_ba_session. This is unexpected 527965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * because we do our own rate control. Just warn and 528065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * move on. 528165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 528265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam wiphy_warn(hw->wiphy, "Unexpected call to %s. " 528365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam "Proceeding anyway.\n", __func__); 528465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam stream = mwl8k_add_stream(hw, sta, tid); 528565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 528665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (stream == NULL) { 528765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); 528865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam rc = -EBUSY; 528965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 529065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 529165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam stream->state = AMPDU_STREAM_IN_PROGRESS; 529265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 529365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* Release the lock before we do the time consuming stuff */ 529465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 529565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { 5296fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar 5297fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar /* Check if link is still valid */ 5298fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar if (!sta_info->is_ampdu_allowed) { 5299fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar spin_lock(&priv->stream_lock); 5300fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar mwl8k_remove_stream(hw, stream); 5301fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar spin_unlock(&priv->stream_lock); 5302fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar return -EBUSY; 5303fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar } 5304fd712f5f5e0723fbbd3720983b3fa2189b2e10f8Yogesh Ashok Powar 5305f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar rc = mwl8k_check_ba(hw, stream, vif); 530665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 53076b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* If HW restart is in progress mwl8k_post_cmd will 53086b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * return -EBUSY. Avoid retrying mwl8k_check_ba in 53096b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * such cases 53106b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 53116b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!rc || rc == -EBUSY) 531265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 531365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam /* 531465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * HW queues take time to be flushed, give them 531565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam * sufficient time 531665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam */ 531765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 531865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam msleep(1000); 531965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 532065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 532165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (rc) { 532265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" 532365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam " attempts\n", tid, MAX_AMPDU_ATTEMPTS); 532465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam mwl8k_remove_stream(hw, stream); 532565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam rc = -EBUSY; 532665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 532765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 532865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); 532965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 533018b559d5db47c86b10c14590aa2d26c0243c39e4Johannes Berg case IEEE80211_AMPDU_TX_STOP_CONT: 533118b559d5db47c86b10c14590aa2d26c0243c39e4Johannes Berg case IEEE80211_AMPDU_TX_STOP_FLUSH: 533218b559d5db47c86b10c14590aa2d26c0243c39e4Johannes Berg case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 5333eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar if (stream) { 5334eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar if (stream->state == AMPDU_STREAM_ACTIVE) { 533507f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar idx = stream->idx; 5336eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar spin_unlock(&priv->stream_lock); 533707f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar mwl8k_destroy_ba(hw, idx); 5338eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar spin_lock(&priv->stream_lock); 5339eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar } 5340eca107ff8a25e0528d6e6225ac6ce59bd498136fYogesh Ashok Powar mwl8k_remove_stream(hw, stream); 534165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 534265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); 534365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 534465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam case IEEE80211_AMPDU_TX_OPERATIONAL: 534565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam BUG_ON(stream == NULL); 534665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); 534765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 5348f95275c48b60fc486517f05da0800357dfd3ce2fYogesh Ashok Powar rc = mwl8k_create_ba(hw, stream, buf_size, vif); 534965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 535065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam if (!rc) 535165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam stream->state = AMPDU_STREAM_ACTIVE; 535265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam else { 535307f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar idx = stream->idx; 535465f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 535507f6dda1e7ed653c87ed329c99d6ae12ee114d52Yogesh Ashok Powar mwl8k_destroy_ba(hw, idx); 535665f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_lock(&priv->stream_lock); 535765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam wiphy_debug(hw->wiphy, 535865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam "Failed adding stream for sta %pM tid %d\n", 535965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam addr, tid); 536065f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam mwl8k_remove_stream(hw, stream); 536165f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam } 536265f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam break; 536365f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 5364a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek default: 536565f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam rc = -ENOTSUPP; 5366a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek } 536765f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam 536865f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam spin_unlock(&priv->stream_lock); 536965f3ddcd08fe24490359274a8c9bf526e81357a5Nishant Sarmukadam return rc; 5370a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek} 5371a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek 5372a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic const struct ieee80211_ops mwl8k_ops = { 5373a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .tx = mwl8k_tx, 5374a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .start = mwl8k_start, 5375a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .stop = mwl8k_stop, 5376a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .add_interface = mwl8k_add_interface, 5377a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .remove_interface = mwl8k_remove_interface, 5378a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .config = mwl8k_config, 5379a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .bss_info_changed = mwl8k_bss_info_changed, 53803ac64beecd27400d12cc7afb4108eef26c499f6aJohannes Berg .prepare_multicast = mwl8k_prepare_multicast, 5381a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .configure_filter = mwl8k_configure_filter, 5382fcdc403c31ed5bb5f3baf42f4e2b5e7198fef0c0Nishant Sarmukadam .set_key = mwl8k_set_key, 5383a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .set_rts_threshold = mwl8k_set_rts_threshold, 53844a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_add = mwl8k_sta_add, 53854a6967b88af02eebeedfbb91bc09160750225bb5Johannes Berg .sta_remove = mwl8k_sta_remove, 5386a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .conf_tx = mwl8k_conf_tx, 5387a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .get_stats = mwl8k_get_stats, 53880d462bbb0e20863b6c796abd779bfdb534d60278John W. Linville .get_survey = mwl8k_get_survey, 5389a2292d83b5dcb7f378956a124854d2b17fa53aa3Lennert Buytenhek .ampdu_action = mwl8k_ampdu_action, 5390a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 5391a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5392a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic void mwl8k_finalize_join_worker(struct work_struct *work) 5393a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 5394a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv = 5395a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek container_of(work, struct mwl8k_priv, finalize_join_worker); 5396a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct sk_buff *skb = priv->beacon_skb; 539756007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 539856007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable); 539956007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM, 540056007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mgmt->u.beacon.variable, len); 540156007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg int dtim_period = 1; 540256007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg 540356007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg if (tim && tim[1] >= 2) 540456007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg dtim_period = tim[3]; 5405a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 540656007a028c51cbf800a6c969d6f6431d23443b99Johannes Berg mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period); 5407a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5408f5bb87cfba5ae9dd3724b846ac2fa7e033425c1cLennert Buytenhek dev_kfree_skb(skb); 5409a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->beacon_skb = NULL; 5410a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 5411a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5412bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linvilleenum { 54139e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8363 = 0, 54149e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek MWL8687, 5415bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville MWL8366, 54166f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek}; 54176f6d1e9a8a7fea5e4400cad64bed717e322208e1Lennert Buytenhek 5418c2f2e2029bea2a8a759b2bc2a44f4d41539af236Yogesh Ashok Powar#define MWL8K_8366_AP_FW_API 3 5419952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" 5420952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) 5421952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo 54228dee5eef2ab313e519e6ce3c3bf9a16cfc6f5907Bill Pembertonstatic struct mwl8k_device_info mwl8k_info_tbl[] = { 54239e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek [MWL8363] = { 54249e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .part_name = "88w8363", 54259e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek .helper_image = "mwl8k/helper_8363.fw", 54260863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8363.fw", 54279e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek }, 542849eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8687] = { 5429bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8687", 5430bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8687.fw", 54310863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8687.fw", 5432bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 543349eb691c8f48a29adfdfbdeb82433f1f8cb6524dLennert Buytenhek [MWL8366] = { 5434bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .part_name = "88w8366", 5435bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville .helper_image = "mwl8k/helper_8366.fw", 54360863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo .fw_image_sta = "mwl8k/fmimage_8366.fw", 5437952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API), 5438952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian Cavagnolo .fw_api_ap = MWL8K_8366_AP_FW_API, 543989a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek .ap_rxd_ops = &rxd_8366_ap_ops, 5440bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville }, 544145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 544245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 5443c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8363.fw"); 5444c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); 5445c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8687.fw"); 5446c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); 5447c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/helper_8366.fw"); 5448c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert BuytenhekMODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); 5449952a0e963fb02e50f4afbf502f7d468a8fe2b0faBrian CavagnoloMODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); 5450c92d4edecf489dbcbb2e5dd3c513790e57e2ea0eLennert Buytenhek 545145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhekstatic DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { 5452e5868ba10c3c5d8a56c06bbafe098103356ac03fBenjamin Larsson { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, 54539e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, 54549e1b17ead81e72d3db37b4cf15cde1f613603822Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, 5455bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, 5456bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, 5457bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, 5458ca66527c60385dcec878ebd90749d1fdc43bc870Lennert Buytenhek { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, 5459bcb628d579a61d0ab0cac4c6cc8a403de5254920John W. Linville { }, 546045a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek}; 546145a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert BuytenhekMODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); 546245a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek 546399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_request_alt_fw(struct mwl8k_priv *priv) 546499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 546599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 546699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting preferred fw %s.\n" 546799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo "Trying alternative firmware %s\n", pci_name(priv->pdev), 546899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref, priv->fw_alt); 546999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true); 547099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 547199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 547299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), priv->fw_alt); 547399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 547499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 547599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return 0; 547699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 547799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 547899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv); 547999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic void mwl8k_fw_state_machine(const struct firmware *fw, void *context) 548099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo{ 548199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_priv *priv = context; 548299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo struct mwl8k_device_info *di = priv->device_info; 548399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo int rc; 548499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 548599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo switch (priv->fw_state) { 548699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_INIT: 548799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 548899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting helper fw %s\n", 548999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 549099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 549199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 549299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_helper = fw; 549399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode, 549499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo true); 549599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc && priv->fw_alt) { 549699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 549799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 549899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 549999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 550099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (rc) 550199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 550299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 550399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_PREF; 550499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 550599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 550699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_PREF: 550799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 550899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_alt) { 550999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_alt_fw(priv); 551099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 551199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 551299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_LOADING_ALT; 551399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else 551499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 551599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else { 551699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 551799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 551899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 551999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 552099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 552199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 552299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 552399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 552499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 552599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo case FW_STATE_LOADING_ALT: 552699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (!fw) { 552799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Error requesting alt fw %s\n", 552899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo pci_name(priv->pdev), di->helper_image); 552999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 553099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 553199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_ucode = fw; 553299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_firmware_load_success(priv); 553399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) 553499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto fail; 553599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo else 553699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 553799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo break; 553899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 553999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo default: 554099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n", 554199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo MWL8K_NAME, priv->fw_state); 554299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo BUG_ON(1); 554399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 554499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 554599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return; 554699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 554799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolofail: 554899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_state = FW_STATE_ERROR; 554999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo complete(&priv->firmware_loading_complete); 555099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo device_release_driver(&priv->pdev->dev); 555199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 555299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo} 555399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 55546b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar#define MAX_RESTART_ATTEMPTS 1 555599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolostatic int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, 555699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo bool nowait) 5557a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 55583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 5559a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int rc; 55606b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar int count = MAX_RESTART_ATTEMPTS; 5561be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 55626b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powarretry: 5563be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reset firmware and hardware */ 5564be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 5565be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 5566be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Ask userland hotplug daemon for the device firmware */ 556799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_request_firmware(priv, fw_image, nowait); 5568be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek if (rc) { 55695db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Firmware files not found\n"); 55703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 5571be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek } 5572be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 557399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (nowait) 557499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 557599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 5576be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Load firmware into hardware */ 5577be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek rc = mwl8k_load_firmware(hw); 55783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 55795db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot start firmware\n"); 5580be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 5581be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek /* Reclaim memory once firmware is successfully loaded */ 5582be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_release_firmware(priv); 5583be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 55846b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (rc && count) { 55856b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* FW did not start successfully; 55866b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * lets try one more time 55876b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 55886b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar count--; 55896b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar wiphy_err(hw->wiphy, "Trying to reload the firmware again\n"); 55906b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar msleep(20); 55916b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar goto retry; 55926b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar } 55936b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 55943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 55953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 55963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 559773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolostatic int mwl8k_init_txqs(struct ieee80211_hw *hw) 559873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo{ 559973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 560073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo int rc = 0; 560173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo int i; 560273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 5603e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) { 560473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_txq_init(hw, i); 560573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (rc) 560673b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo break; 560773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (priv->ap_fw) 560873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo iowrite32(priv->txq[i].txd_dma, 560973b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo priv->sram + priv->txq_offset[i]); 561073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo } 561173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo return rc; 561273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo} 561373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo 56143cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* initialize hw after successfully loading a firmware image */ 56153cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_probe_hw(struct ieee80211_hw *hw) 56163cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 56173cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 56183cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc = 0; 56193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i; 5620be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 562191942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->ap_fw) { 562289a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = priv->device_info->ap_rxd_ops; 562391942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek if (priv->rxd_ops == NULL) { 5624c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_err(hw->wiphy, 5625c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches "Driver does not have AP firmware image support for this hardware\n"); 5626a2ca8ecb8ffc985e82c9570c3837408f7efe8c9dAlexey Khoroshilov rc = -ENOENT; 562791942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek goto err_stop_firmware; 562891942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 562991942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } else { 563089a91f4f4cdae92daf3693d4852ae4958abb6c58Lennert Buytenhek priv->rxd_ops = &rxd_sta_ops; 563191942230689c1758685499e82e53769d5e7f32ebLennert Buytenhek } 5632be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 5633be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->sniffer_enabled = false; 5634be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->wmm_enabled = false; 5635be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek priv->pending_tx_pkts = 0; 5636c27a54d3f12383789b57a404649daf98a05cbd72Yogesh Ashok Powar atomic_set(&priv->watchdog_event_pending, 0); 5637be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 5638a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rc = mwl8k_rxq_init(hw, 0); 5639a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 56403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 5641a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek rxq_refill(hw, 0, INT_MAX); 5642a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 564373b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo /* For the sta firmware, we need to know the dma addresses of tx queues 564473b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them 564573b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * prior to issuing this command. But for the AP case, we learn the 564673b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * total number of queues from the result CMD_GET_HW_SPEC, so for this 564773b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo * case we must initialize the tx queues after. 564873b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo */ 56498a7a578c2e3ac463a17fe30b11ada0509658a952Brian Cavagnolo priv->num_ampdu_queues = 0; 565073b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (!priv->ap_fw) { 565173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_init_txqs(hw); 5652a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) 5653a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 5654a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5655a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5656a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 5657c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 56583aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| 56593aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam MWL8K_A2H_INT_BA_WATCHDOG, 56601e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); 566112488e01fb2b06bb3f6ee137efc88e29d827817eNishant Sarmukadam iowrite32(MWL8K_A2H_INT_OPC_DONE, 566212488e01fb2b06bb3f6ee137efc88e29d827817eNishant Sarmukadam priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 5663a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5664a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches rc = request_irq(priv->pdev->irq, mwl8k_interrupt, 5665a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek IRQF_SHARED, MWL8K_NAME, hw); 5666a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 56675db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); 5668a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek goto err_free_queues; 5669a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5670a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 56716b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* 56726b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * When hw restart is requested, 56736b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * mac80211 will take care of clearing 56746b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * the ampdu streams, so do not clear 56756b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * the ampdu state here 56766b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 56776b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (!priv->hw_restart_in_progress) 56786b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar memset(priv->ampdu, 0, sizeof(priv->ampdu)); 5679ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 5680a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* 5681a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * Temporarily enable interrupts. Initial firmware host 5682c2c2b12a8b6cd23d4abbc086642647c656bf406cLennert Buytenhek * commands use interrupts and avoid polling. Disable 5683a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek * interrupts when done. 5684a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek */ 5685c23b5a699471ea2ef9d146eae80e64836cfbf001Lennert Buytenhek iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 5686a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5687a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Get config data, mac addrs etc */ 568842fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (priv->ap_fw) { 568942fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_ap(hw); 569042fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek if (!rc) 569173b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo rc = mwl8k_init_txqs(hw); 569273b46320209e9fe0d65aba1b8c21489278047574Brian Cavagnolo if (!rc) 569342fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_set_hw_spec(hw); 569442fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } else { 569542fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek rc = mwl8k_cmd_get_hw_spec_sta(hw); 569642fba21d56df644887488a29b158cc8916b9ba99Lennert Buytenhek } 5697a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 56985db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot initialise firmware\n"); 5699be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 5700a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5701a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5702a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Turn radio off */ 570355489b6ed6801a42636fc3d4594b77dda9c409f2Lennert Buytenhek rc = mwl8k_cmd_radio_disable(hw); 5704a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (rc) { 57055db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot disable\n"); 5706be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 5707a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek } 5708a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 570932060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek /* Clear MAC address */ 5710aa21d0f69a5ca28d33f584b8952cca154115fd26Lennert Buytenhek rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); 571132060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek if (rc) { 57125db5584441c2dceb75696fb31a44ac7b9b925359Joe Perches wiphy_err(hw->wiphy, "Cannot clear MAC address\n"); 5713be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek goto err_free_irq; 571432060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek } 571532060e1b64f23fe315a35d2df8c2c7ad010df73eLennert Buytenhek 5716a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar /* Configure Antennas */ 5717a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); 5718a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar if (rc) 5719a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar wiphy_warn(hw->wiphy, "failed to set # of RX antennas"); 5720a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); 5721a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar if (rc) 5722a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar wiphy_warn(hw->wiphy, "failed to set # of TX antennas"); 5723a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar 5724a246ac38cdd886bf053f67d5275a20e1a99ff586Yogesh Ashok Powar 5725a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Disable interrupts */ 5726a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 5727a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 5728a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5729c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", 5730c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->device_info->part_name, 5731c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->hw_rev, hw->wiphy->perm_addr, 5732c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches priv->ap_fw ? "AP" : "STA", 5733c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, 5734c96c31e499b70964cfc88744046c998bb710e4b8Joe Perches (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); 5735a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5736a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return 0; 5737a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5738a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_irq: 5739a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 5740a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek free_irq(priv->pdev->irq, hw); 5741a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 5742a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_queues: 5743e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 5744a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 5745a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 5746a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 57473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_stop_firmware: 57483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_hw_reset(priv); 57493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 57513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 57523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo/* 57543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * invoke mwl8k_reload_firmware to change the firmware image after the device 57553cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * has already been registered 57563cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 57573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) 57583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 57593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc = 0; 57603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv = hw->priv; 57616b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar struct mwl8k_vif *vif, *tmp_vif; 57623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_stop(hw); 57643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 57653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57666b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* 57676b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * All the existing interfaces are re-added by the ieee80211_reconfig; 57686b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * which means driver should remove existing interfaces before calling 57696b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar * ieee80211_restart_hw 57706b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar */ 57716b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->hw_restart_in_progress) 57726b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar list_for_each_entry_safe(vif, tmp_vif, &priv->vif_list, list) 57736b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar mwl8k_remove_vif(priv, vif); 57746b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 5775e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 57763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 57773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 577899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, fw_image, false); 57793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 57803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 57813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 57833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 57843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 57853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57866b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar if (priv->hw_restart_in_progress) 57876b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar return rc; 57886b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 57893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_start(hw); 57903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 57913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 57923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 57933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_config(hw, ~0); 57943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 57953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 57963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 5797e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { 57988a3a3c85e44d58f5af0adac74a0b866ba89a1978Eliad Peller rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); 57993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 58003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto fail; 58013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 58023cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58033cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 58043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58053cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolofail: 58063cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); 58073cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 58083cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 58093cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58105d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powarstatic const struct ieee80211_iface_limit ap_if_limits[] = { 58115d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, 58122acdaa7a578cf43566950a6cfb70848ff6607553Yogesh Ashok Powar { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, 58135d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar}; 58145d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar 58155d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powarstatic const struct ieee80211_iface_combination ap_if_comb = { 58165d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar .limits = ap_if_limits, 58175d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar .n_limits = ARRAY_SIZE(ap_if_limits), 58185d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar .max_interfaces = 8, 58195d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar .num_different_channels = 1, 58205d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar}; 58215d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar 58225d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar 58233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolostatic int mwl8k_firmware_load_success(struct mwl8k_priv *priv) 58243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 58253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw = priv->hw; 58263cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int i, rc; 58273cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 582899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_load_firmware(hw); 582999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_release_firmware(priv); 583099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (rc) { 583199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wiphy_err(hw->wiphy, "Cannot start firmware\n"); 583299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 583399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 583499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 58353cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 58363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * Extra headroom is the size of the required DMA header 58373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * minus the size of the smallest 802.11 frame (CTS frame). 58383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 58393cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->extra_tx_headroom = 58403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); 58413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 5842ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; 5843ff776cecec92fe7cac4a9ce1919576ad6e737e08Yogesh Ashok Powar 58443cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->channel_change_time = 10; 58453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 5846e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo hw->queues = MWL8K_TX_WMM_QUEUES; 58473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set rssi values to dBm */ 58490bf22c3751d19f9be20205c0e7112723618a4858Nishant Sarmukadam hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; 58502a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar 58512a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar /* 58522a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar * Ask mac80211 to not to trigger PS mode 58532a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar * based on PM bit of incoming frames. 58542a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar */ 58552a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar if (priv->ap_fw) 58562a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar hw->flags |= IEEE80211_HW_AP_LINK_PS; 58572a36a0ec1550ffb4d608134e2504a6a67d1d1740Yogesh Ashok Powar 58583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->vif_data_size = sizeof(struct mwl8k_vif); 58593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->sta_data_size = sizeof(struct mwl8k_sta); 58603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->macids_used = 0; 58623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_LIST_HEAD(&priv->vif_list); 58633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Set default radio state and preamble */ 58653db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell priv->radio_on = false; 58663db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell priv->radio_short_preamble = false; 58673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Finalize join worker */ 58693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); 58703aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam /* Handle watchdog ba events */ 58713aefc37ee789188f0d4488cae04ff618f4c4ddf6Nishant Sarmukadam INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); 58726b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar /* To reload the firmware if it crashes */ 58736b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar INIT_WORK(&priv->fw_reload, mwl8k_hw_restart_work); 58743cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* TX reclaim and RX tasklets. */ 58763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); 58773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_tx_task); 58783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); 58793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo tasklet_disable(&priv->poll_rx_task); 58803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* Power management cookie */ 58823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); 58833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->cookie == NULL) 58843cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return -ENOMEM; 58853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mutex_init(&priv->fw_mutex); 58873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_owner = NULL; 58883cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->fw_mutex_depth = 0; 58893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hostcmd_wait = NULL; 58903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo spin_lock_init(&priv->tx_lock); 58923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 5893ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo spin_lock_init(&priv->stream_lock); 5894ac109fd0427008e5b55e0e52e59c364de6d686feBrian Cavagnolo 58953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->tx_wait = NULL; 58963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 58973cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = mwl8k_probe_hw(hw); 58983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 58993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_cookie; 59003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes = 0; 59025d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar 59035d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar if (priv->ap_macids_supported || priv->device_info->fw_image_ap) { 59043cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); 59052acdaa7a578cf43566950a6cfb70848ff6607553Yogesh Ashok Powar hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); 59065d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar hw->wiphy->iface_combinations = &ap_if_comb; 59075d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar hw->wiphy->n_iface_combinations = 1; 59085d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar } 59095d377fcaf48cc38882bb92c3b4a0cfcfb250087bYogesh Ashok Powar 59103cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sta_macids_supported || priv->device_info->fw_image_sta) 59113cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); 59123cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59133cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = ieee80211_register_hw(hw); 59143cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 59153cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot register device\n"); 59163cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_unprobe_hw; 59173cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59183cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59193cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return 0; 59203cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59213cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnoloerr_unprobe_hw: 5922e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 59233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_txq_deinit(hw, i); 59243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo mwl8k_rxq_deinit(hw, 0); 59253cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 5926be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_free_cookie: 5927a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->cookie != NULL) 5928a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_free_consistent(priv->pdev, 4, 5929a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv->cookie, priv->cookie_dma); 5930a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 59313cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 59323cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo} 59338dee5eef2ab313e519e6ce3c3bf9a16cfc6f5907Bill Pembertonstatic int mwl8k_probe(struct pci_dev *pdev, 59343cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo const struct pci_device_id *id) 59353cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo{ 59363cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo static int printed_version; 59373cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct ieee80211_hw *hw; 59383cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo struct mwl8k_priv *priv; 59390863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo struct mwl8k_device_info *di; 59403cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo int rc; 59413cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59423cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (!printed_version) { 59433cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); 59443cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printed_version = 1; 59453cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59463cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59473cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59483cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_enable_device(pdev); 59493cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 59503cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot enable new PCI device\n", 59513cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 59523cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo return rc; 59533cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59543cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59553cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = pci_request_regions(pdev, MWL8K_NAME); 59563cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) { 59573cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: Cannot obtain PCI resources\n", 59583cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo MWL8K_NAME); 59593cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_disable_device; 59603cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59613cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59623cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_master(pdev); 59633cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59643cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59653cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); 59663cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (hw == NULL) { 59673cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); 59683cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo rc = -ENOMEM; 59693cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_free_reg; 59703cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59713cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59723cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo SET_IEEE80211_DEV(hw, &pdev->dev); 59733cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo pci_set_drvdata(pdev, hw); 59743cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59753cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv = hw->priv; 59763cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->hw = hw; 59773cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->pdev = pdev; 59783cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->device_info = &mwl8k_info_tbl[id->driver_data]; 59793cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59803cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59813cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->sram = pci_iomap(pdev, 0, 0x10000); 59823cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->sram == NULL) { 59833cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); 5984a2ca8ecb8ffc985e82c9570c3837408f7efe8c9dAlexey Khoroshilov rc = -EIO; 59853cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 59863cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 59873cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 59883cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo /* 59893cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. 59903cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. 59913cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo */ 59923cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 1, 0x10000); 59933cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 59943cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo priv->regs = pci_iomap(pdev, 2, 0x10000); 59953cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (priv->regs == NULL) { 59963cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo wiphy_err(hw->wiphy, "Cannot map device registers\n"); 5997a2ca8ecb8ffc985e82c9570c3837408f7efe8c9dAlexey Khoroshilov rc = -EIO; 59983cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_iounmap; 59993cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 60003cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo } 60013cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 60020863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo /* 600399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * Choose the initial fw image depending on user input. If a second 600499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * image is available, make it the alternative image that will be 600599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo * loaded if the first one fails. 60060863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo */ 600799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo init_completion(&priv->firmware_loading_complete); 60080863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo di = priv->device_info; 600999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (ap_mode_default && di->fw_image_ap) { 601099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 601199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_sta; 601299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (!ap_mode_default && di->fw_image_sta) { 601399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 601499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_alt = di->fw_image_ap; 601599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { 60160863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); 601799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_sta; 60180863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { 60190863ade8d6bde1d151f75720d999ff27f9fe3533Brian Cavagnolo printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); 602099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo priv->fw_pref = di->fw_image_ap; 602199020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 602299020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo rc = mwl8k_init_firmware(hw, priv->fw_pref, true); 60233cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo if (rc) 60243cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo goto err_stop_firmware; 60256b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 60266b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar priv->hw_restart_in_progress = false; 60276b6accc3832e5a124eeb144c6b3b1ff65b503d2bYogesh Ashok Powar 6028e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar priv->running_bsses = 0; 6029e882efc96dba0a48adbe460b04d552d9a749a7c0Yogesh Ashok Powar 603099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo return rc; 60313cc7772c0a3cc193fa9873816168bd34d4f16837Brian Cavagnolo 6032be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_stop_firmware: 6033be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek mwl8k_hw_reset(priv); 6034be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhek 6035be695fc4f0a7ff9c9f91d59536b029b781cfea62Lennert Buytenhekerr_iounmap: 6036a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (priv->regs != NULL) 6037a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 6038a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 60395b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek if (priv->sram != NULL) 60405b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 60415b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek 6042a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 6043a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 6044a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6045a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekerr_free_reg: 6046a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 60473db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhek 60483db95e50c8813d8ed04a1ec7cd7b77dba7c81c80Lennert Buytenhekerr_disable_device: 6049a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 6050a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6051a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return rc; 6052a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 6053a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 60548dee5eef2ab313e519e6ce3c3bf9a16cfc6f5907Bill Pembertonstatic void mwl8k_remove(struct pci_dev *pdev) 6055a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek{ 6056a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct ieee80211_hw *hw = pci_get_drvdata(pdev); 6057a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek struct mwl8k_priv *priv; 6058a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek int i; 6059a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6060a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek if (hw == NULL) 6061a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek return; 6062a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek priv = hw->priv; 6063a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 606499020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo wait_for_completion(&priv->firmware_loading_complete); 606599020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 606699020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo if (priv->fw_state == FW_STATE_ERROR) { 606799020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo mwl8k_hw_reset(priv); 606899020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo goto unmap; 606999020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo } 607099020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolo 6071a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_stop_queues(hw); 6072a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 607360aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek ieee80211_unregister_hw(hw); 607460aa569f9212a13382c29cc734f275dec0f55e0bLennert Buytenhek 607567e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek /* Remove TX reclaim and RX tasklets. */ 60761e9f9de3b17db3aa358f39d6932662324178350dLennert Buytenhek tasklet_kill(&priv->poll_tx_task); 607767e2eb27958cae758ccbc86443c360ec285acc3eLennert Buytenhek tasklet_kill(&priv->poll_rx_task); 6078a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6079a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Stop hardware */ 6080a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_hw_reset(priv); 6081a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6082a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek /* Return all skbs to mac80211 */ 6083e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 6084efb7c49a68cf206f35793d7799608e1d69a209f9Lennert Buytenhek mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 6085a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6086e600707b021efdc109e7becd467798da339ec26dBrian Cavagnolo for (i = 0; i < mwl8k_tx_queues(priv); i++) 6087a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_txq_deinit(hw, i); 6088a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6089a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek mwl8k_rxq_deinit(hw, 0); 6090a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6091c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); 6092a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 609399020471001dbbd6edf61f105368cb6667cc683dBrian Cavagnolounmap: 6094a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_iounmap(pdev, priv->regs); 60955b9482dda6dda11dc7050ffa5b4ebfb0c775880fLennert Buytenhek pci_iounmap(pdev, priv->sram); 6096a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_set_drvdata(pdev, NULL); 6097a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek ieee80211_free_hw(hw); 6098a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_release_regions(pdev); 6099a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek pci_disable_device(pdev); 6100a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek} 6101a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 6102a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhekstatic struct pci_driver mwl8k_driver = { 6103a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .name = MWL8K_NAME, 610445a390ddd70d8bec0b17dd37bc8f77372c9c3d33Lennert Buytenhek .id_table = mwl8k_pci_id_table, 6105a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek .probe = mwl8k_probe, 61068dee5eef2ab313e519e6ce3c3bf9a16cfc6f5907Bill Pemberton .remove = mwl8k_remove, 6107a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek}; 6108a66098daacee2f354dab311b58011e7076aa248cLennert Buytenhek 61095b0a3b7eb37730c369cc47783549dcf6f54a1cd0Axel Linmodule_pci_driver(mwl8k_driver); 6110c2c357ce309221b85fd36e50aade66d01a556cdeLennert Buytenhek 6111c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_DESCRIPTION(MWL8K_DESC); 6112c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_VERSION(MWL8K_VERSION); 6113c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>"); 6114c2c357ce309221b85fd36e50aade66d01a556cdeLennert BuytenhekMODULE_LICENSE("GPL"); 6115