15b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 25b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Copyright (c) 2010 Broadcom Corporation 35b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 45b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Permission to use, copy, modify, and/or distribute this software for any 55b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * purpose with or without fee is hereby granted, provided that the above 65b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * copyright notice and this permission notice appear in all copies. 75b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 85b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 95b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define __UNDEF_NO_VERSION__ 1802f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/etherdevice.h> 215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/sched.h> 225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/firmware.h> 235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/interrupt.h> 24452962366c11a9126fabac8cb28af49c27464408Paul Gortmaker#include <linux/module.h> 252e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel#include <linux/bcma/bcma.h> 265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <net/mac80211.h> 275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <defs.h> 285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "nicpci.h" 295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "phy/phy_int.h" 305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "d11.h" 315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "channel.h" 325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "scb.h" 335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "pub.h" 345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "ucode_loader.h" 355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "mac80211_if.h" 365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "main.h" 375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ 395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Flags we support */ 415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ 425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel FIF_ALLMULTI | \ 435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel FIF_FCSFAIL | \ 445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel FIF_CONTROL | \ 455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel FIF_OTHER_BSS | \ 46be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers FIF_BCN_PRBRESP_PROMISC | \ 47be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers FIF_PSPOLL) 485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CHAN2GHZ(channel, freqency, chflags) { \ 505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .band = IEEE80211_BAND_2GHZ, \ 515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .center_freq = (freqency), \ 525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .hw_value = (channel), \ 535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .flags = chflags, \ 545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .max_antenna_gain = 0, \ 555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .max_power = 19, \ 565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CHAN5GHZ(channel, chflags) { \ 595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .band = IEEE80211_BAND_5GHZ, \ 605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .center_freq = 5000 + 5*(channel), \ 615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .hw_value = (channel), \ 625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .flags = chflags, \ 635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .max_antenna_gain = 0, \ 645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .max_power = 21, \ 655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define RATE(rate100m, _flags) { \ 685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .bitrate = (rate100m), \ 695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .flags = (_flags), \ 705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .hw_value = (rate100m / 5), \ 715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 735b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct firmware_hdr { 745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 offset; 755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 len; 765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 idx; 775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 795b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const char * const brcms_firmwares[MAX_FW_IMAGES] = { 805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "brcm/bcm43xx", 815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL 825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 845b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int n_adapters_found; 855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 865b435de0d786869c95d1962121af0d7df2542009Arend van SprielMODULE_AUTHOR("Broadcom Corporation"); 875b435de0d786869c95d1962121af0d7df2542009Arend van SprielMODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); 885b435de0d786869c95d1962121af0d7df2542009Arend van SprielMODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); 895b435de0d786869c95d1962121af0d7df2542009Arend van SprielMODULE_LICENSE("Dual BSD/GPL"); 905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 922e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel/* recognized BCMA Core IDs */ 932e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic struct bcma_device_id brcms_coreid_table[] = { 94eb032f03cbf7ac7baf78ae89a832100561bf0e29Arend van Spriel BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS), 95eb032f03cbf7ac7baf78ae89a832100561bf0e29Arend van Spriel BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS), 962e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel BCMA_CORETABLE_END 972e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel}; 982e756560a8a47ce754b852d0bc1ff7549433d0ebArend van SprielMODULE_DEVICE_TABLE(bcma, brcms_coreid_table); 995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1008ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 1015b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int msglevel = 0xdeadbeef; 1025b435de0d786869c95d1962121af0d7df2542009Arend van Sprielmodule_param(msglevel, int, 0); 1038ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 1045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1055b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic struct ieee80211_channel brcms_2ghz_chantable[] = { 1065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS), 1075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS), 1085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS), 1095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS), 1105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(5, 2432, 0), 1115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(6, 2437, 0), 1125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(7, 2442, 0), 1135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS), 1145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS), 1155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS), 1165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS), 1175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(12, 2467, 1185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | 1195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_NO_HT40PLUS), 1205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(13, 2472, 1215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | 1225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_NO_HT40PLUS), 1235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN2GHZ(14, 2484, 1245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | 1255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) 1265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 1275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1285b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic struct ieee80211_channel brcms_5ghz_nphy_chantable[] = { 1295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* UNII-1 */ 1305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS), 1315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS), 1325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS), 1335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS), 1345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* UNII-2 */ 1355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(52, 1365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(56, 1395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(60, 1425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(64, 1455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* MID */ 1485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(100, 1495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(104, 1525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(108, 1555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(112, 1585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(116, 1615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(120, 1645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(124, 1675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(128, 1705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(132, 1735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), 1755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(136, 1765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), 1785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(140, 1795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | 1805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | 1815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel IEEE80211_CHAN_NO_HT40MINUS), 1825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* UNII-3 */ 1835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), 1845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS), 1855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS), 1865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS), 1875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) 1885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 1895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 1915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * The rate table is used for both 2.4G and 5G rates. The 1925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * latter being a subset as it does not support CCK rates. 1935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 1945b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic struct ieee80211_rate legacy_ratetable[] = { 1955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(10, 0), 1965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(20, IEEE80211_RATE_SHORT_PREAMBLE), 1975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(55, IEEE80211_RATE_SHORT_PREAMBLE), 1985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(110, IEEE80211_RATE_SHORT_PREAMBLE), 1995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(60, 0), 2005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(90, 0), 2015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(120, 0), 2025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(180, 0), 2035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(240, 0), 2045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(360, 0), 2055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(480, 0), 2065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel RATE(540, 0), 2075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 2085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2095b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = { 2105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .band = IEEE80211_BAND_2GHZ, 2115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .channels = brcms_2ghz_chantable, 2125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .n_channels = ARRAY_SIZE(brcms_2ghz_chantable), 2135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .bitrates = legacy_ratetable, 2145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .n_bitrates = ARRAY_SIZE(legacy_ratetable), 2155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ht_cap = { 2165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* from include/linux/ieee80211.h */ 2175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .cap = IEEE80211_HT_CAP_GRN_FLD | 2186b1a89afbf97f40797255b9543d441ce361dbb52Arend van Spriel IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40, 2195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ht_supported = true, 2205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, 2215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ampdu_density = AMPDU_DEF_MPDU_DENSITY, 2225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .mcs = { 2235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* placeholders for now */ 2245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, 2255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .rx_highest = cpu_to_le16(500), 2265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .tx_params = IEEE80211_HT_MCS_TX_DEFINED} 2275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 2295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2305b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = { 2315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .band = IEEE80211_BAND_5GHZ, 2325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .channels = brcms_5ghz_nphy_chantable, 2335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable), 2345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET, 2355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .n_bitrates = ARRAY_SIZE(legacy_ratetable) - 2365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BRCMS_LEGACY_5G_RATE_OFFSET, 2375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ht_cap = { 2385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | 2396b1a89afbf97f40797255b9543d441ce361dbb52Arend van Spriel IEEE80211_HT_CAP_SGI_40, 2405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ht_supported = true, 2415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, 2425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ampdu_density = AMPDU_DEF_MPDU_DENSITY, 2435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .mcs = { 2445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* placeholders for now */ 2455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, 2465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .rx_highest = cpu_to_le16(500), 2475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .tx_params = IEEE80211_HT_MCS_TX_DEFINED} 2485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 2505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* flags the given rate in rateset as requested */ 2525b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br) 2535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 2545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 i; 2555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < rs->count; i++) { 2575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rate != (rs->rates[i] & 0x7f)) 2585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 2595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (is_br) 2615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rs->rates[i] |= BRCMS_RATE_FLAG; 2625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 2635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rs->rates[i] &= BRCMS_RATE_MASK; 2645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 2655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 2675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2685b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 2695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 2705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 2715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 2735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wl->pub->up) { 2745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "ops->tx called while down\n"); 2755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree_skb(skb); 2765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 2775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); 2795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel done: 2805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 2815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 2825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2835b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcms_ops_start(struct ieee80211_hw *hw) 2845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 2855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 2865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool blocked; 2872646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen int err; 2885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_wake_queues(hw); 2905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 2915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel blocked = brcms_rfkill_set_hw_state(wl); 2925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 2935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!blocked) 2945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); 2955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2962646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_lock_bh(&wl->lock); 297dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen /* avoid acknowledging frames before a non-monitor device is added */ 298dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen wl->mute_tx = true; 299dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen 3002646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen if (!wl->pub->up) 3012646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen err = brcms_up(wl); 3022646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen else 3032646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen err = -ENODEV; 3042646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_unlock_bh(&wl->lock); 3052646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen 3062646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen if (err != 0) 3072646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__, 3082646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen err); 3092646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen return err; 3105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3125b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_stop(struct ieee80211_hw *hw) 3135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3142646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen struct brcms_info *wl = hw->priv; 3152646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen int status; 3162646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen 3175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_stop_queues(hw); 3182646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen 3192646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen if (wl->wlc == NULL) 3202646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen return; 3212646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen 3222646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_lock_bh(&wl->lock); 3232646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen status = brcms_c_chipmatch(wl->wlc->hw->vendorid, 3242646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen wl->wlc->hw->deviceid); 3252646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_unlock_bh(&wl->lock); 3262646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen if (!status) { 3272646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen wiphy_err(wl->wiphy, 3282646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen "wl: brcms_ops_stop: chipmatch failed\n"); 3292646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen return; 3302646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen } 3312646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen 3322646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen /* put driver in down state */ 3332646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_lock_bh(&wl->lock); 3342646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen brcms_down(wl); 3352646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen spin_unlock_bh(&wl->lock); 3365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3385b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 3395b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 3405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 341dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen struct brcms_info *wl = hw->priv; 342dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen 3435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Just STA for now */ 3441525662ac280e61feb1af7778881241b542dc075Roland Vossen if (vif->type != NL80211_IFTYPE_STATION) { 3455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only" 3465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel " STA for now\n", __func__, vif->type); 3475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EOPNOTSUPP; 3485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 350dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen wl->mute_tx = false; 351dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen brcms_c_mute(wl->wlc, false); 352dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen 3532646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen return 0; 3545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3565b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 3575b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 3585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3615b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) 3625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_conf *conf = &hw->conf; 3645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 3655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err = 0; 3665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int new_int; 3675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct wiphy *wiphy = hw->wiphy; 3685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 3705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { 3715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_set_beacon_listen_interval(wl->wlc, 3725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel conf->listen_interval); 3735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_MONITOR) 375be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "%s: change monitor mode: %s\n", 3765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__, conf->flags & IEEE80211_CONF_MONITOR ? 3775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "true" : "false"); 3785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_PS) 3795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n", 3805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__, conf->flags & IEEE80211_CONF_PS ? 3815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "true" : "false"); 3825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_POWER) { 3845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = brcms_c_set_tx_power(wl->wlc, conf->power_level); 3855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err < 0) { 3865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: Error setting power_level\n", 3875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__); 3885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto config_out; 3895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel new_int = brcms_c_get_tx_power(wl->wlc); 3915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (new_int != conf->power_level) 3925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: Power level req != actual, %d %d" 3935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "\n", __func__, conf->power_level, 3945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel new_int); 3955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 3975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (conf->channel_type == NL80211_CHAN_HT20 || 3985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel conf->channel_type == NL80211_CHAN_NO_HT) 3995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = brcms_c_set_channel(wl->wlc, 4005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel conf->channel->hw_value); 4015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 4025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = -ENOTSUPP; 4035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) 4055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = brcms_c_set_rate_limit(wl->wlc, 4065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel conf->short_frame_max_tx_count, 4075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel conf->long_frame_max_tx_count); 4085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel config_out: 4105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return err; 4125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 4135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4145b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 4155b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_bss_info_changed(struct ieee80211_hw *hw, 4165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_vif *vif, 4175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_bss_conf *info, u32 changed) 4185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 4195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 4205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct wiphy *wiphy = hw->wiphy; 4215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_ASSOC) { 4235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* association status changed (associated/disassociated) 4245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * also implies a change in the AID. 4255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 4265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME, 4275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__, info->assoc ? "" : "dis"); 4285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_associate_upd(wl->wlc, info->assoc); 4305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_ERP_SLOT) { 4335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel s8 val; 4345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* slot timing changed */ 4365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (info->use_short_slot) 4375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel val = 1; 4385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 4395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel val = 0; 4405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_set_shortslot_override(wl->wlc, val); 4425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_HT) { 4465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 802.11n parameters changed */ 4475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 mode = info->ht_operation_mode; 4485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG, 4515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel mode & IEEE80211_HT_OP_MODE_PROTECTION); 4525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF, 4535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 4545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS, 4555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT); 4565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_BASIC_RATES) { 4595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_supported_band *bi; 4605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 br_mask, i; 4615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 rate; 4625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcm_rateset rs; 4635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int error; 4645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* retrieve the current rates */ 4665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_get_current_rateset(wl->wlc, &rs); 4685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel br_mask = info->basic_rates; 4715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)]; 4725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < bi->n_bitrates; i++) { 4735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* convert to internal rate value */ 4745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rate = (bi->bitrates[i].bitrate << 1) / 10; 4755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* set/clear basic rate flag */ 4775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_set_basic_rate(&rs, rate, br_mask & 1); 4785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel br_mask >>= 1; 4795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* update the rate set */ 4825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel error = brcms_c_set_rateset(wl->wlc, &rs); 4845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (error) 4865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "changing basic rates failed: %d\n", 4875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel error); 4885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_BEACON_INT) { 4905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Beacon interval changed */ 4915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_set_beacon_period(wl->wlc, info->beacon_int); 4935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 4945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 4955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_BSSID) { 4965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* BSSID changed, for whatever reason (IBSS and managed mode) */ 4975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 4985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); 4995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 5005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_BEACON) 5025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Beacon data changed, retrieve new beacon (beaconing modes) */ 5035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: beacon changed\n", __func__); 5045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_BEACON_ENABLED) { 5065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Beaconing should be enabled/disabled (beaconing modes) */ 5075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__, 5085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel info->enable_beacon ? "true" : "false"); 5095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_CQM) { 5125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Connection quality monitor config changed */ 5135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d " 5145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel " (implement)\n", __func__, info->cqm_rssi_thold, 5155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel info->cqm_rssi_hyst); 5165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_IBSS) { 5195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* IBSS join status changed */ 5205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__, 5215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel info->ibss_joined ? "true" : "false"); 5225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_ARP_FILTER) { 5255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Hardware ARP filter address list or state changed */ 5265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d" 5275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel " (implement)\n", __func__, info->arp_filter_enabled ? 5285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "true" : "false", info->arp_addr_cnt); 5295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed & BSS_CHANGED_QOS) { 5325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 5335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * QoS for this association was enabled/disabled. 5345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Note that it is only ever disabled for station mode. 5355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 5365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__, 5375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel info->qos ? "true" : "false"); 5385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 5395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 5405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 5415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5425b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 5435b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_configure_filter(struct ieee80211_hw *hw, 5445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned int changed_flags, 5455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned int *total_flags, u64 multicast) 5465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 5475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 5485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct wiphy *wiphy = hw->wiphy; 5495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel changed_flags &= MAC_FILTERS; 5515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *total_flags &= MAC_FILTERS; 552be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers 5535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed_flags & FIF_PROMISC_IN_BSS) 554be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n"); 5555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed_flags & FIF_ALLMULTI) 556be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_ALLMULTI\n"); 5575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed_flags & FIF_FCSFAIL) 558be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_FCSFAIL\n"); 5595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed_flags & FIF_CONTROL) 560be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_CONTROL\n"); 5615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (changed_flags & FIF_OTHER_BSS) 562be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_OTHER_BSS\n"); 563be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers if (changed_flags & FIF_PSPOLL) 564be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_PSPOLL\n"); 565be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers if (changed_flags & FIF_BCN_PRBRESP_PROMISC) 566be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n"); 567be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers 568be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers spin_lock_bh(&wl->lock); 569be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers brcms_c_mac_promisc(wl->wlc, *total_flags); 570be667669ec01d514b3820f8c74d9336115be6aa7Alwin Beukers spin_unlock_bh(&wl->lock); 5715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 5725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 5735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5745b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) 5755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 5765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 5775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 5785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_scan_start(wl->wlc); 5795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 5805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 5815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 5825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5835b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) 5845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 5855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 5865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 5875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_scan_stop(wl->wlc); 5885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 5895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 5905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 5915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5925b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 5935b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, 5945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const struct ieee80211_tx_queue_params *params) 5955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 5965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 5975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 5995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_wme_setparams(wl->wlc, queue, params, true); 6005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 6015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 6035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6055b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 6065b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 6075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_sta *sta) 6085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 6105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct scb *scb = &wl->wlc->pri_scb; 6115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_init_scb(scb); 6135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub->global_ampdu = &(scb->scb_ampdu); 6155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub->global_ampdu->scb = scb; 6165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub->global_ampdu->max_pdu = 16; 6175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 6195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * minstrel_ht initiates addBA on our behalf by calling 6205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * ieee80211_start_tx_ba_session() 6215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 6225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 6235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6255b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 6265b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcms_ops_ampdu_action(struct ieee80211_hw *hw, 6275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_vif *vif, 6285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel enum ieee80211_ampdu_mlme_action action, 6295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_sta *sta, u16 tid, u16 *ssn, 6305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 buf_size) 6315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 6335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct scb *scb = &wl->wlc->pri_scb; 6345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int status; 6355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (WARN_ON(scb->magic != SCB_MAGIC)) 6375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EIDRM; 6385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel switch (action) { 6395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case IEEE80211_AMPDU_RX_START: 6405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 6415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case IEEE80211_AMPDU_RX_STOP: 6425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 6435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case IEEE80211_AMPDU_TX_START: 6445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 6455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel status = brcms_c_aggregatable(wl->wlc, tid); 6465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 6475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!status) { 6485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n", 6495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tid); 6505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EINVAL; 6515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 6525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 6535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 6545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case IEEE80211_AMPDU_TX_STOP: 6565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 6575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_ampdu_flush(wl->wlc, sta, tid); 6585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 6595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 6605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 6615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case IEEE80211_AMPDU_TX_OPERATIONAL: 6625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 6635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * BA window size from ADDBA response ('buf_size') defines how 6645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * many outstanding MPDUs are allowed for the BA stream by 6655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * recipient and traffic class. 'ampdu_factor' gives maximum 6665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * AMPDU size. 6675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 6685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 6695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size, 6705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 6715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sta->ht_cap.ampdu_factor)) - 1); 6725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 6735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Power save wakeup */ 6745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 6755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel default: 6765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n", 6775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__); 6785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 6795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 6815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6835b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) 6845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 6865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool blocked; 6875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 6895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel blocked = brcms_c_check_radio_disabled(wl->wlc); 6905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 6915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); 6935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6955b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) 6965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 6985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); 7005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* wait for packet queue and dma fifos to run empty */ 7025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 7035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_wait_for_tx_completion(wl->wlc, drop); 7045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 7055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 7065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const struct ieee80211_ops brcms_ops = { 7085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .tx = brcms_ops_tx, 7095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .start = brcms_ops_start, 7105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .stop = brcms_ops_stop, 7115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .add_interface = brcms_ops_add_interface, 7125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .remove_interface = brcms_ops_remove_interface, 7135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .config = brcms_ops_config, 7145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .bss_info_changed = brcms_ops_bss_info_changed, 7155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .configure_filter = brcms_ops_configure_filter, 7165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .sw_scan_start = brcms_ops_sw_scan_start, 7175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .sw_scan_complete = brcms_ops_sw_scan_complete, 7185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .conf_tx = brcms_ops_conf_tx, 7195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .sta_add = brcms_ops_sta_add, 7205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .ampdu_action = brcms_ops_ampdu_action, 7215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .rfkill_poll = brcms_ops_rfkill_poll, 7225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .flush = brcms_ops_flush, 7235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 7245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 7262e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * is called in brcms_bcma_probe() context, therefore no locking required. 7275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 7285b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcms_set_hint(struct brcms_info *wl, char *abbrev) 7295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 7305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); 7315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 7325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7335b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_dpc(unsigned long data) 7345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 7355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl; 7365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl = (struct brcms_info *) data; 7385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 7405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* call the common second level interrupt handler */ 7425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->pub->up) { 7435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->resched) { 7445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long flags; 7455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_irqsave(&wl->isr_lock, flags); 7475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_intrsupd(wl->wlc); 7485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_irqrestore(&wl->isr_lock, flags); 7495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->resched = brcms_c_dpc(wl->wlc, true); 7525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* brcms_c_dpc() may bring the driver down */ 7555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wl->pub->up) 7565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 7575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* re-schedule dpc */ 7595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->resched) 7605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tasklet_schedule(&wl->tasklet); 7615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 7625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* re-enable interrupts */ 7635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_intrson(wl); 7645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel done: 7665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 7675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 7685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 7705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Precondition: Since this function is called in brcms_pci_probe() context, 7715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * no locking is required. 7725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 7735b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev) 7745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 7755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int status; 7765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct device *device = &pdev->dev; 7775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char fw_name[100]; 7785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i; 7795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memset(&wl->fw, 0, sizeof(struct brcms_firmware)); 7815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < MAX_FW_IMAGES; i++) { 7825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcms_firmwares[i] == NULL) 7835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 7845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], 7855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel UCODE_LOADER_API_VER); 7865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); 7875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (status) { 7885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", 7895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel KBUILD_MODNAME, fw_name); 7905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return status; 7915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], 7935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel UCODE_LOADER_API_VER); 7945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); 7955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (status) { 7965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", 7975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel KBUILD_MODNAME, fw_name); 7985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return status; 7995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->fw.hdr_num_entries[i] = 8015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); 8025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->fw.fw_cnt = i; 8045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return brcms_ucode_data_init(wl, &wl->ucode); 8055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 8085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Precondition: Since this function is called in brcms_pci_probe() context, 8095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * no locking is required. 8105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 8115b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_release_fw(struct brcms_info *wl) 8125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i; 8145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < MAX_FW_IMAGES; i++) { 8155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel release_firmware(wl->fw.fw_bin[i]); 8165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel release_firmware(wl->fw.fw_hdr[i]); 8175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/** 8215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * This function frees the WL per-device resources. 8225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 8235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * This function frees resources owned by the WL device pointed to 8245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * by the wl parameter. 8255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 8265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: can both be called locked and unlocked 8275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 8285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 8295b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void brcms_free(struct brcms_info *wl) 8305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_timer *t, *next; 8325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* free ucode data */ 8345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->fw.fw_cnt) 8355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_ucode_data_free(&wl->ucode); 8365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->irq) 8375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel free_irq(wl->irq, wl); 8385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* kill dpc */ 8405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tasklet_kill(&wl->tasklet); 8415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->pub) 8435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_module_unregister(wl->pub, "linux", wl); 8445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* free common resources */ 8465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->wlc) { 8475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_detach(wl->wlc); 8485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->wlc = NULL; 8495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub = NULL; 8505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* virtual interface deletion is deferred so we cannot spinwait */ 8535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* wait for all pending callbacks to complete */ 8555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (atomic_read(&wl->callbacks) > 0) 8565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel schedule(); 8575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* free timers */ 8595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (t = wl->timers; t; t = next) { 8605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel next = t->next; 8618ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 8625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t->name); 8635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 8645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t); 8655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 8692646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen* called from both kernel as from this kernel module (error flow on attach) 8705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel* precondition: perimeter lock is not acquired. 8715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel*/ 8722e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic void brcms_remove(struct bcma_device *pdev) 8735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8742e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel struct ieee80211_hw *hw = bcma_get_drvdata(pdev); 8752646c46d56792bdb370784d1cd6e696a7b3bbf67Roland Vossen struct brcms_info *wl = hw->priv; 8765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->wlc) { 8785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); 8795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); 8805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_unregister_hw(hw); 8815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_free(wl); 8845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8852e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel bcma_set_drvdata(pdev, NULL); 8865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ieee80211_free_hw(hw); 8875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8895b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic irqreturn_t brcms_isr(int irq, void *dev_id) 8905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl; 8925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool ours, wantdpc; 8935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl = (struct brcms_info *) dev_id; 8955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock(&wl->isr_lock); 8975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* call common first level interrupt handler */ 8995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ours = brcms_c_isr(wl->wlc, &wantdpc); 9005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ours) { 9015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* if more to do... */ 9025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wantdpc) { 9035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* ...and call the second level interrupt handler */ 9055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* schedule dpc */ 9065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tasklet_schedule(&wl->tasklet); 9075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock(&wl->isr_lock); 9115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return IRQ_RETVAL(ours); 9135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 9145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 9165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * is called in brcms_pci_probe() context, therefore no locking required. 9175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 9185b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int ieee_hw_rate_init(struct ieee80211_hw *hw) 9195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 9205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = hw->priv; 9215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_c_info *wlc = wl->wlc; 9225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_supported_band *band; 9235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int has_5g = 0; 9245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 phy_type; 9255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; 9275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; 9285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel phy_type = brcms_c_get_phy_type(wl->wlc, 0); 9305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { 9315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel band = &wlc->bandstate[BAND_2G_INDEX]->band; 9325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *band = brcms_band_2GHz_nphy_template; 9335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (phy_type == PHY_TYPE_LCN) { 9345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Single stream */ 9355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel band->ht_cap.mcs.rx_mask[1] = 0; 936df4492f89499fa5ba45f8fdfe1f100b4112f5368Arend van Spriel band->ht_cap.mcs.rx_highest = cpu_to_le16(72); 9375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; 9395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 9405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EPERM; 9415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Assume all bands use the same phy. True for 11n devices. */ 9445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->pub->_nbands > 1) { 9455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel has_5g++; 9465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { 9475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel band = &wlc->bandstate[BAND_5G_INDEX]->band; 9485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *band = brcms_band_5GHz_nphy_template; 9495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band; 9505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 9515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EPERM; 9525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 9555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 9565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 9585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * is called in brcms_pci_probe() context, therefore no locking required. 9595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 9605b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int ieee_hw_init(struct ieee80211_hw *hw) 9615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 9625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->flags = IEEE80211_HW_SIGNAL_DBM 9635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */ 9645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel | IEEE80211_HW_REPORTS_TX_ACK_STATUS 9655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel | IEEE80211_HW_AMPDU_AGGREGATION; 9665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->extra_tx_headroom = brcms_c_get_header_len(); 9685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->queues = N_TX_QUEUES; 9695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->max_rates = 2; /* Primary rate and 1 fallback rate */ 9705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* channel change time is dependent on chip and band */ 9725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->channel_change_time = 7 * 1000; 9735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 9745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->rate_control_algorithm = "minstrel_ht"; 9765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw->sta_data_size = 0; 9785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ieee_hw_rate_init(hw); 9795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 9805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/** 9825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * attach to the WL device. 9835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 9845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Attach to the WL device identified by vendor and device parameters. 9855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * regs is a host accessible memory address pointing to WL device registers. 9865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 9875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * brcms_attach is not defined as static because in the case where no bus 9885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * is defined, wl_attach will never be called, and thus, gcc will issue 9895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * a warning that this function is defined but not used if we declare 9905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * it as static. 9915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 9925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 9932e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * is called in brcms_bcma_probe() context, therefore no locking required. 9945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 9952e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic struct brcms_info *brcms_attach(struct bcma_device *pdev) 9965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 9975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl = NULL; 9985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int unit, err; 9995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_hw *hw; 10005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 perm[ETH_ALEN]; 10015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unit = n_adapters_found; 10035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = 0; 10045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (unit < 0) 10065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 10075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* allocate private info */ 10092e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel hw = bcma_get_drvdata(pdev); 10105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hw != NULL) 10115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl = hw->priv; 10125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) 10135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 10145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->wiphy = hw->wiphy; 10155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel atomic_set(&wl->callbacks, 0); 10175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* setup the bottom half handler */ 10195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); 10205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_init(&wl->lock); 10225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_init(&wl->isr_lock); 10235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* prepare ucode */ 10252e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) { 10265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " 10275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); 10285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_release_fw(wl); 10292e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel brcms_remove(pdev); 10305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 10315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* common load-time initialization */ 1034b63337a0344d7ebf3c8d710b1327d0b61c0f6f03Arend van Spriel wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); 10355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_release_fw(wl); 10365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wl->wlc) { 10375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", 10385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel KBUILD_MODNAME, err); 10395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 10405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub = brcms_c_pub(wl->wlc); 10425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub->ieee_hw = hw; 10445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* register our interrupt handler */ 10462e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel if (request_irq(pdev->bus->host_pci->irq, brcms_isr, 10472e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel IRQF_SHARED, KBUILD_MODNAME, wl)) { 10485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); 10495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 10505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10512e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel wl->irq = pdev->bus->host_pci->irq; 10525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* register module */ 10545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_module_register(wl->pub, "linux", wl, NULL); 10555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ieee_hw_init(hw)) { 10575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, 10585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__); 10595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 10605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); 10635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (WARN_ON(!is_valid_ether_addr(perm))) 10645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 10655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SET_IEEE80211_PERM_ADDR(hw, perm); 10665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = ieee80211_register_hw(hw); 10685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) 10695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" 10705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "%d\n", __func__, err); 10715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->pub->srom_ccode[0]) 10735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = brcms_set_hint(wl, wl->pub->srom_ccode); 10745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 10755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err = brcms_set_hint(wl, "US"); 10765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) 10775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", 10785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__, err); 10795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel n_adapters_found++; 10815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return wl; 10825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10835b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 10845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_free(wl); 10855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 10865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 10875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/** 10915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * determines if a device is a WL device, and if so, attaches it. 10925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 10935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * This function determines if a device pointed to by pdev is a WL device, 10945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * and if so, performs a brcms_attach() on it. 10955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 10965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Perimeter lock is initialized in the course of this function. 10975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 10982e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic int __devinit brcms_bcma_probe(struct bcma_device *pdev) 10995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 11005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl; 11015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_hw *hw; 11025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11032e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n", 11042e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class, 11052e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel pdev->bus->host_pci->irq); 11065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11072e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel if ((pdev->id.manuf != BCMA_MANUF_BCM) || 11082e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel (pdev->id.id != BCMA_CORE_80211)) 11095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENODEV; 11105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops); 11125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!hw) { 11135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pr_err("%s: ieee80211_alloc_hw failed\n", __func__); 11145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMEM; 11155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SET_IEEE80211_DEV(hw, &pdev->dev); 11185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11192e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel bcma_set_drvdata(pdev, hw); 11205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memset(hw->priv, 0, sizeof(*wl)); 11225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11232e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel wl = brcms_attach(pdev); 11245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wl) { 112502f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches pr_err("%s: brcms_attach failed!\n", __func__); 11265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENODEV; 11275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 11295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 11305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11317d5869e78f4c9d32f834dadefbb7dcb3c9d4d85fLinus Torvaldsstatic int brcms_suspend(struct bcma_device *pdev) 11325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 11335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_info *wl; 11345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct ieee80211_hw *hw; 11355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11362e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel hw = bcma_get_drvdata(pdev); 11375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl = hw->priv; 11385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wl) { 1139137dabed34a13f90e068327b98329331367c9b46Arend van Spriel pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME, 1140137dabed34a13f90e068327b98329331367c9b46Arend van Spriel __func__); 11415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENODEV; 11425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* only need to flag hw is down for proper resume */ 11455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 11465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->pub->hw_up = false; 11475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 11485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11497e9e7fa414e47fccc6127f23bc866cbcc7e27dcbLinus Torvalds pr_debug("brcms_suspend ok\n"); 11505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11512e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel return 0; 11522e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel} 11532e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel 11542e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic int brcms_resume(struct bcma_device *pdev) 11552e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel{ 11567e9e7fa414e47fccc6127f23bc866cbcc7e27dcbLinus Torvalds pr_debug("brcms_resume ok\n"); 11577e9e7fa414e47fccc6127f23bc866cbcc7e27dcbLinus Torvalds return 0; 11585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 11595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11602e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Sprielstatic struct bcma_driver brcms_bcma_driver = { 11615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .name = KBUILD_MODNAME, 11622e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel .probe = brcms_bcma_probe, 11635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .suspend = brcms_suspend, 11645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .resume = brcms_resume, 11655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel .remove = __devexit_p(brcms_remove), 11662e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel .id_table = brcms_coreid_table, 11675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 11685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/** 11702e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * This is the main entry point for the brcmsmac driver. 11715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 1172b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel * This function is scheduled upon module initialization and 1173b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel * does the driver registration, which result in brcms_bcma_probe() 1174b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel * call resulting in the driver bringup. 11755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 1176b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Sprielstatic void brcms_driver_init(struct work_struct *work) 11775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 1178b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel int error; 1179b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel 1180b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel error = bcma_driver_register(&brcms_bcma_driver); 1181b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel if (error) 1182b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel pr_err("%s: register returned %d\n", __func__, error); 1183b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel} 1184b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel 1185b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Sprielstatic DECLARE_WORK(brcms_driver_work, brcms_driver_init); 11865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1187b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Sprielstatic int __init brcms_module_init(void) 1188b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel{ 11898ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 11905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (msglevel != 0xdeadbeef) 11915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcm_msg_level = msglevel; 1192b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel#endif 1193b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel if (!schedule_work(&brcms_driver_work)) 1194b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel return -EBUSY; 11955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1196b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel return 0; 11975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 11985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/** 12002e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * This function unloads the brcmsmac driver from the system. 12015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 12022e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * This function unconditionally unloads the brcmsmac driver module from the 12035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * system. 12045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 12055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12065b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void __exit brcms_module_exit(void) 12075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 1208b0c359b2f68e982ac9334a5f2c04c3a67dee4d50Arend van Spriel cancel_work_sync(&brcms_driver_work); 12092e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel bcma_driver_unregister(&brcms_bcma_driver); 12105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12125b435de0d786869c95d1962121af0d7df2542009Arend van Sprielmodule_init(brcms_module_init); 12135b435de0d786869c95d1962121af0d7df2542009Arend van Sprielmodule_exit(brcms_module_exit); 12145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 12165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 12175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12185b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, 12195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool state, int prio) 12205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__); 12225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 12255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 12265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12275b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_init(struct brcms_info *wl) 12285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); 12305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_reset(wl); 1231dc460127898cab9014fb06281e0bad37b198bd83Roland Vossen brcms_c_init(wl->wlc, wl->mute_tx); 12325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 12355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 12365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12375b435de0d786869c95d1962121af0d7df2542009Arend van Sprieluint brcms_reset(struct brcms_info *wl) 12385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); 12405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_reset(wl->wlc); 12415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* dpc will not be rescheduled */ 12433db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell wl->resched = false; 12445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 12465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1248c261bdf8acad56717cae233709808d8d9291ce36Roland Vossenvoid brcms_fatal_error(struct brcms_info *wl) 1249c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen{ 1250c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n", 1251c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen wl->wlc->pub->unit); 1252c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen brcms_reset(wl); 1253c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen ieee80211_restart_hw(wl->pub->ieee_hw); 1254c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen} 1255c261bdf8acad56717cae233709808d8d9291ce36Roland Vossen 12565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 12575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * These are interrupt on/off entry points. Disable interrupts 12585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * during interrupt state transition. 12595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12605b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_intrson(struct brcms_info *wl) 12615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long flags; 12635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_irqsave(&wl->isr_lock, flags); 12655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_intrson(wl->wlc); 12665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_irqrestore(&wl->isr_lock, flags); 12675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12695b435de0d786869c95d1962121af0d7df2542009Arend van Sprielu32 brcms_intrsoff(struct brcms_info *wl) 12705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long flags; 12725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 status; 12735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_irqsave(&wl->isr_lock, flags); 12755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel status = brcms_c_intrsoff(wl->wlc); 12765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_irqrestore(&wl->isr_lock, flags); 12775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return status; 12785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12805b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_intrsrestore(struct brcms_info *wl, u32 macintmask) 12815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long flags; 12835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_irqsave(&wl->isr_lock, flags); 12855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcms_c_intrsrestore(wl->wlc, macintmask); 12865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_irqrestore(&wl->isr_lock, flags); 12875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 12885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 12905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 12915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12925b435de0d786869c95d1962121af0d7df2542009Arend van Sprielint brcms_up(struct brcms_info *wl) 12935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 12945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int error = 0; 12955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->pub->up) 12975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 12985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel error = brcms_c_up(wl->wlc); 13005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return error; 13025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 13035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 13055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 13065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 13075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_down(struct brcms_info *wl) 13085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 13095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint callbacks, ret_val = 0; 13105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* call common down function */ 13125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret_val = brcms_c_down(wl->wlc); 13135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel callbacks = atomic_read(&wl->callbacks) - ret_val; 13145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* wait for down callbacks to complete */ 13165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 13175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* For HIGH_only driver, it's important to actually schedule other work, 13195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * not just spin wait since everything runs at schedule level 13205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 13215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); 13225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 13245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 13255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 13275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel* precondition: perimeter lock is not acquired 13285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 13292a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossenstatic void _brcms_timer(struct work_struct *work) 13305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 13312a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen struct brcms_timer *t = container_of(work, struct brcms_timer, 13322a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen dly_wrk.work); 13332a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen 13345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&t->wl->lock); 13355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (t->set) { 13375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (t->periodic) { 13385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel atomic_inc(&t->wl->callbacks); 13392a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen ieee80211_queue_delayed_work(t->wl->pub->ieee_hw, 13402a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen &t->dly_wrk, 13412a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen msecs_to_jiffies(t->ms)); 13422a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen } else { 13435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->set = false; 13442a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen } 13455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->fn(t->arg); 13475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 13485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel atomic_dec(&t->wl->callbacks); 13505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&t->wl->lock); 13525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 13535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 13555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Adds a timer to the list. Caller supplies a timer function. 13565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Is called from wlc. 13575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 13585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 13595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 13605b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct brcms_timer *brcms_init_timer(struct brcms_info *wl, 13615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel void (*fn) (void *arg), 13625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel void *arg, const char *name) 13635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 13645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_timer *t; 13655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC); 13675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!t) 13685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 13695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13702a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer); 13715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->wl = wl; 13725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->fn = fn; 13735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->arg = arg; 13745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->next = wl->timers; 13755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->timers = t; 13765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13778ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 13785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); 13795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (t->name) 13805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel strcpy(t->name, name); 13815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 13825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return t; 13845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 13855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 13875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * adds only the kernel timer since it's going to be more accurate 13885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * as well as it's easier to make it periodic 13895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 13905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 13915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 13922a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossenvoid brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) 13935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 13942a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen struct ieee80211_hw *hw = t->wl->pub->ieee_hw; 13952a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen 13968ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 13975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (t->set) 13982a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n", 13995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__, t->name, periodic); 14005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 14015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->ms = ms; 14025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->periodic = (bool) periodic; 14035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->set = true; 14045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1405be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossen atomic_inc(&t->wl->callbacks); 14062a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen 14072a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); 14085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 14115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * return true if timer successfully deleted, false if still pending 14125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 14135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 14145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 1415be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossenbool brcms_del_timer(struct brcms_timer *t) 14165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 14175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (t->set) { 14185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel t->set = false; 14192a7fc5b1c17a6055fe2753ebacaf43b5780bcf99Roland Vossen if (!cancel_delayed_work(&t->dly_wrk)) 14205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return false; 14215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1422be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossen atomic_dec(&t->wl->callbacks); 14235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return true; 14265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 14295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 14305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 1431be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossenvoid brcms_free_timer(struct brcms_timer *t) 14325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 1433be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossen struct brcms_info *wl = t->wl; 14345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcms_timer *tmp; 14355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* delete the timer in case it is active */ 1437be69c4ef462a476523f89c74e7db29f6ad207a1aRoland Vossen brcms_del_timer(t); 14385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wl->timers == t) { 14405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->timers = wl->timers->next; 14418ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 14425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t->name); 14435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 14445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t); 14455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 14465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tmp = wl->timers; 14505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (tmp) { 14515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (tmp->next == t) { 14525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tmp->next = t->next; 14538ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 14545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t->name); 14555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 14565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(t); 14575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 14585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tmp = tmp->next; 14605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 14655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 14665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 14675b435de0d786869c95d1962121af0d7df2542009Arend van Sprielint brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) 14685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 14695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i, entry; 14705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const u8 *pdata; 14715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct firmware_hdr *hdr; 14725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < wl->fw.fw_cnt; i++) { 14735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; 14745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (entry = 0; entry < wl->fw.hdr_num_entries[i]; 14755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel entry++, hdr++) { 14765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 len = le32_to_cpu(hdr->len); 14775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (le32_to_cpu(hdr->idx) == idx) { 14785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pdata = wl->fw.fw_bin[i]->data + 14795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel le32_to_cpu(hdr->offset); 14801f1d528977162a1a04aaecdc7f08a5b715a58810Thomas Meyer *pbuf = kmemdup(pdata, len, GFP_ATOMIC); 14815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*pbuf == NULL) 14825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 14835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 14855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n", 14895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel idx); 14905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *pbuf = NULL; 14915b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 14925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENODATA; 14935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 14962e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * Precondition: Since this function is called in brcms_bcma_probe() context, 14975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * no locking is required. 14985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 14995b435de0d786869c95d1962121af0d7df2542009Arend van Sprielint brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) 15005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i, entry; 15025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const u8 *pdata; 15035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct firmware_hdr *hdr; 15045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < wl->fw.fw_cnt; i++) { 15055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; 15065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (entry = 0; entry < wl->fw.hdr_num_entries[i]; 15075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel entry++, hdr++) { 15085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (le32_to_cpu(hdr->idx) == idx) { 15095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pdata = wl->fw.fw_bin[i]->data + 15105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel le32_to_cpu(hdr->offset); 15115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (le32_to_cpu(hdr->len) != 4) { 15125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, 15135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "ERROR: fw hdr len\n"); 15145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMSG; 15155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *n_bytes = le32_to_cpu(*((__le32 *) pdata)); 15175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 15185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx); 15225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMSG; 15235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 15265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: can both be called locked and unlocked 15275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 15285b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_ucode_free_buf(void *p) 15295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(p); 15315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 15345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * checks validity of all firmware images loaded from user space 15355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 15362e756560a8a47ce754b852d0bc1ff7549433d0ebArend van Spriel * Precondition: Since this function is called in brcms_bcma_probe() context, 15375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * no locking is required. 15385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 15395b435de0d786869c95d1962121af0d7df2542009Arend van Sprielint brcms_check_firmwares(struct brcms_info *wl) 15405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i; 15425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int entry; 15435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int rc = 0; 15445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const struct firmware *fw; 15455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const struct firmware *fw_hdr; 15465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct firmware_hdr *ucode_hdr; 15475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < MAX_FW_IMAGES && rc == 0; i++) { 15485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fw = wl->fw.fw_bin[i]; 15495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fw_hdr = wl->fw.fw_hdr[i]; 15505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (fw == NULL && fw_hdr == NULL) { 15515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 15525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (fw == NULL || fw_hdr == NULL) { 15535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n", 15545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__); 15555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rc = -EBADF; 15565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (fw_hdr->size % sizeof(struct firmware_hdr)) { 15575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: non integral fw hdr file " 15585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "size %zu/%zu\n", __func__, fw_hdr->size, 15595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sizeof(struct firmware_hdr)); 15605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rc = -EBADF; 15615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { 15625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: out of bounds fw file size " 15635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "%zu\n", __func__, fw->size); 15645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rc = -EBADF; 15655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 15665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* check if ucode section overruns firmware image */ 15675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ucode_hdr = (struct firmware_hdr *)fw_hdr->data; 15685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (entry = 0; entry < wl->fw.hdr_num_entries[i] && 15695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel !rc; entry++, ucode_hdr++) { 15705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (le32_to_cpu(ucode_hdr->offset) + 15715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel le32_to_cpu(ucode_hdr->len) > 15725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fw->size) { 15735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, 15745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "%s: conflicting bin/hdr\n", 15755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __func__); 15765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rc = -EBADF; 15775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rc == 0 && wl->fw.fw_cnt != i) { 15825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__, 15835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wl->fw.fw_cnt); 15845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rc = -EBADF; 15855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return rc; 15875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 15905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 15915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 15925b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbool brcms_rfkill_set_hw_state(struct brcms_info *wl) 15935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool blocked = brcms_c_check_radio_disabled(wl->wlc); 15955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 15975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); 15985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (blocked) 15995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy); 16005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 16015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return blocked; 16025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 16035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 16055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * precondition: perimeter lock has been acquired 16065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 16075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcms_msleep(struct brcms_info *wl, uint ms) 16085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 16095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&wl->lock); 16105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel msleep(ms); 16115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&wl->lock); 16125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 1613