carl9170usb: PHY/RF and MAC routines
Christian Lamparter
maintainerPATCH 3/6 carl9170usb: PHY/RF and MAC routines
Signed-off-by Christian Lamparter <[email protected]>
--- drivers/net/wireless/ath/carl9170/mac.c | 611 +++++++++++ drivers/net/wireless/ath/carl9170/phy.c | 1802 +++++++++++++++++++++++++++++++ 2 files changed, 2413 insertions(+), 0 deletions(-) create mode 100644 drivers/net/wireless/ath/carl9170/mac.c create mode 100644 drivers/net/wireless/ath/carl9170/phy.c
drivers/net/wireless/ath/carl9170/mac.c new file +611 -0
@@ -0,0 +1,611 @@ +/* +* Atheros CARL9170 driver +* +* MAC programming +* +* Copyright 2008, Johannes Berg <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; see the file COPYING. If not, see +* http://www.gnu.org/licenses/. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* Copyright (c) 2007-2008 Atheros Communications, Inc. +* +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include <asm/unaligned.h> + +#include "carl9170.h" +#include "cmd.h" + +int carl9170_set_dyn_sifs_ack (struct ar9170 *ar) +{ +u32 val; + +if (conf_is_ht40 (&ar->hw->conf)) + val =0x010a ; +else { +if (ar->hw->conf.channel->band ==IEEE80211_BAND_2GHZ ) + val =0x105 ; +else + val =0x104 ; + } + +return carl9170_write_reg (ar,AR9170_MAC_REG_DYNAMIC_SIFS_ACK , val); +} + +int carl9170_set_rts_cts_rate (struct ar9170 *ar) +{ +u32 rts_rate, cts_rate; + +if (conf_is_ht (&ar->hw->conf)) { +/* 12 mbit OFDM */ + rts_rate =0x1da ; + cts_rate =0x10a ; + }else { +if (ar->hw->conf.channel->band ==IEEE80211_BAND_2GHZ ) { +/* 11 mbit CCK */ + rts_rate =033 ; + cts_rate =003 ; + }else { +/* 6 mbit OFDM */ + rts_rate =0x1bb ; + cts_rate =0x10b ; + } + } + +return carl9170_write_reg (ar,AR9170_MAC_REG_RTS_CTS_RATE , + rts_rate | (cts_rate) <<16 ); +} + +int carl9170_set_slot_time (struct ar9170 *ar) +{ +struct ieee80211_vif *vif; +u32 slottime =20 ; + +rcu_read_lock (); + vif =carl9170_get_main_vif (ar); +if (!vif) { +rcu_read_unlock (); +return 0 ; + } + +if ((ar->hw->conf.channel->band ==IEEE80211_BAND_5GHZ ) || + vif->bss_conf.use_short_slot) + slottime =9 ; + +rcu_read_unlock (); + +return carl9170_write_reg (ar,AR9170_MAC_REG_SLOT_TIME , + slottime <<10 ); +} + +int carl9170_set_mac_rates (struct ar9170 *ar) +{ +struct ieee80211_vif *vif; +u32 basic, mandatory; + +rcu_read_lock (); + vif =carl9170_get_main_vif (ar); + +if (!vif) { +rcu_read_unlock (); +return 0 ; + } + + basic = (vif->bss_conf.basic_rates &0xf ); + basic |= (vif->bss_conf.basic_rates &0xff0 ) <<4 ; +rcu_read_unlock (); + +if (ar->hw->conf.channel->band ==IEEE80211_BAND_5GHZ ) + mandatory =0xff00 ;/* OFDM 6/9/12/18/24/36/48/54 */ +else + mandatory =0xff0f ;/* OFDM (6/9../54) + CCK (1/2/5.5/11) */ + +carl9170_regwrite_begin (ar); +carl9170_regwrite (AR9170_MAC_REG_BASIC_RATE , basic); +carl9170_regwrite (AR9170_MAC_REG_MANDATORY_RATE , mandatory); +carl9170_regwrite_finish (); + +return carl9170_regwrite_result (); +} + +int carl9170_set_qos (struct ar9170 *ar) +{ +carl9170_regwrite_begin (ar); + +carl9170_regwrite (AR9170_MAC_REG_AC0_CW , ar->edcf[0 ].cw_min | + (ar->edcf[0 ].cw_max <<16 )); +carl9170_regwrite (AR9170_MAC_REG_AC1_CW , ar->edcf[1 ].cw_min | + (ar->edcf[1 ].cw_max <<16 )); +carl9170_regwrite (AR9170_MAC_REG_AC2_CW , ar->edcf[2 ].cw_min | + (ar->edcf[2 ].cw_max <<16 )); +carl9170_regwrite (AR9170_MAC_REG_AC3_CW , ar->edcf[3 ].cw_min | + (ar->edcf[3 ].cw_max <<16 )); +carl9170_regwrite (AR9170_MAC_REG_AC4_CW , ar->edcf[4 ].cw_min | + (ar->edcf[4 ].cw_max <<16 )); + +carl9170_regwrite (AR9170_MAC_REG_AC2_AC1_AC0_AIFS , + ((ar->edcf[0 ].aifs *9 +10 )) | + ((ar->edcf[1 ].aifs *9 +10 ) <<12 ) | + ((ar->edcf[2 ].aifs *9 +10 ) <<24 )); +carl9170_regwrite (AR9170_MAC_REG_AC4_AC3_AC2_AIFS , + ((ar->edcf[2 ].aifs *9 +10 ) >>8 ) | + ((ar->edcf[3 ].aifs *9 +10 ) <<4 ) | + ((ar->edcf[4 ].aifs *9 +10 ) <<16 )); + +carl9170_regwrite (AR9170_MAC_REG_AC1_AC0_TXOP , + ar->edcf[0 ].txop | ar->edcf[1 ].txop <<16 ); +carl9170_regwrite (AR9170_MAC_REG_AC3_AC2_TXOP , + ar->edcf[2 ].txop | ar->edcf[3 ].txop <<16 | + ar->edcf[4 ].txop <<24 ); + +carl9170_regwrite_finish (); + +return carl9170_regwrite_result (); +} + +int carl9170_init_mac (struct ar9170 *ar) +{ +carl9170_regwrite_begin (ar); + +/* switch MAC to OTUS interface */ +carl9170_regwrite (0x1c3600 ,0x3 ); + +carl9170_regwrite (AR9170_MAC_REG_ACK_EXTENSION ,0x40 ); + +carl9170_regwrite (AR9170_MAC_REG_RETRY_MAX ,0x0 ); + +/* enable MMIC */ +carl9170_regwrite (AR9170_MAC_REG_SNIFFER , +AR9170_MAC_SNIFFER_DEFAULTS ); + +carl9170_regwrite (AR9170_MAC_REG_RX_THRESHOLD ,0xc1f80 ); + +carl9170_regwrite (AR9170_MAC_REG_RX_PE_DELAY ,0x70 ); +carl9170_regwrite (AR9170_MAC_REG_EIFS_AND_SIFS ,0xa144000 ); +carl9170_regwrite (AR9170_MAC_REG_SLOT_TIME ,9 <<10 ); + +/* CF-END & CF-ACK rate => 24M OFDM */ +carl9170_regwrite (AR9170_MAC_REG_TID_CFACK_CFEND_RATE ,0x59900000 ); + +/* NAV protects ACK only (in TXOP) */ +carl9170_regwrite (AR9170_MAC_REG_TXOP_DURATION ,0x201 ); + +/* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ +/* OTUS set AM to 0x1 */ +carl9170_regwrite (AR9170_MAC_REG_BCN_HT1 ,0x8000170 ); + +carl9170_regwrite (AR9170_MAC_REG_BACKOFF_PROTECT ,0x105 ); + +/* Aggregation MAX number and timeout */ +carl9170_regwrite (AR9170_MAC_REG_AMPDU_FACTOR ,0xa ); +carl9170_regwrite (AR9170_MAC_REG_AMPDU_DENSITY ,0x140a00 ); + +carl9170_regwrite (AR9170_MAC_REG_FRAMETYPE_FILTER , +AR9170_MAC_FTF_DEFAULTS ); + +carl9170_regwrite (AR9170_MAC_REG_RX_CONTROL , +AR9170_MAC_RX_CTRL_DEAGG | +AR9170_MAC_RX_CTRL_SHORT_FILTER ); + +/* rate sets */ +carl9170_regwrite (AR9170_MAC_REG_BASIC_RATE ,0x150f ); +carl9170_regwrite (AR9170_MAC_REG_MANDATORY_RATE ,0x150f ); +carl9170_regwrite (AR9170_MAC_REG_RTS_CTS_RATE ,0x0030033 ); + +/* MIMO response control */ +carl9170_regwrite (AR9170_MAC_REG_ACK_TPC ,0x4003c1e ); + +carl9170_regwrite (AR9170_MAC_REG_AMPDU_RX_THRESH ,0xffff ); + +/* set PHY register read timeout (??) */ +carl9170_regwrite (AR9170_MAC_REG_MISC_680 ,0xf00008 ); + +/* Disable Rx TimeOut, workaround for BB. */ +carl9170_regwrite (AR9170_MAC_REG_RX_TIMEOUT ,0x0 ); + +/* Set WLAN DMA interrupt mode: generate int per packet */ +carl9170_regwrite (AR9170_MAC_REG_TXRX_MPI ,0x110011 ); + +carl9170_regwrite (AR9170_MAC_REG_FCS_SELECT , +AR9170_MAC_FCS_FIFO_PROT ); + +/* Disables the CF_END frame, undocumented register */ +carl9170_regwrite (AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND , +0x141e0f48 ); + +/* reset group hash table */ +carl9170_regwrite (AR9170_MAC_REG_GROUP_HASH_TBL_L ,0xffffffff ); +carl9170_regwrite (AR9170_MAC_REG_GROUP_HASH_TBL_H ,0xffffffff ); + +/* disable PRETBTT interrupt */ +carl9170_regwrite (AR9170_MAC_REG_PRETBTT ,0x0 ); +carl9170_regwrite (AR9170_MAC_REG_BCN_PERIOD ,0x0 ); + +carl9170_regwrite_finish (); + +return carl9170_regwrite_result (); +} + +static int carl9170_set_mac_reg (struct ar9170 *ar, +const u32 reg,const u8 *mac) +{ +static const u8 zero[ETH_ALEN ] = {0 }; + +if (!mac) + mac = zero; + +carl9170_regwrite_begin (ar); + +carl9170_regwrite (reg,get_unaligned_le32 (mac)); +carl9170_regwrite (reg +4 ,get_unaligned_le16 (mac +4 )); + +carl9170_regwrite_finish (); + +return carl9170_regwrite_result (); +} + +int carl9170_mod_virtual_mac (struct ar9170 *ar,unsigned int id,const u8 *mac) +{ +if (WARN_ON (id >= ar->fw_vif_num)) +return -EINVAL ; + +return carl9170_set_mac_reg (ar, +AR9170_MAC_REG_ACK_TABLE + (id -1 ) *8 , mac); +} + +int carl9170_update_multicast (struct ar9170 *ar,const u64 mc_hash) +{ +int err; + +carl9170_regwrite_begin (ar); +carl9170_regwrite (AR9170_MAC_REG_GROUP_HASH_TBL_H , mc_hash >>32 ); +carl9170_regwrite (AR9170_MAC_REG_GROUP_HASH_TBL_L , mc_hash); +carl9170_regwrite_finish (); + err =carl9170_regwrite_result (); +if (err) +return err; + + ar->cur_mc_hash = mc_hash; +return 0 ; +} + +int carl9170_update_frame_filter (struct ar9170 *ar,const u32 filter) +{ +int err; + + err =carl9170_write_reg (ar,AR9170_MAC_REG_FRAMETYPE_FILTER , filter); +if (err) +return err; + + ar->cur_filter = filter; +return 0 ; +} + +int carl9170_set_operating_mode (struct ar9170 *ar) +{ +struct ieee80211_vif *vif; +struct ath_common *common = &ar->common; +u8 *mac_addr, *bssid; +u32 cam_mode =AR9170_MAC_CAM_DEFAULTS ; +u32 enc_mode =AR9170_MAC_ENCRYPTION_DEFAULTS ; +u32 rx_ctrl =AR9170_MAC_RX_CTRL_DEAGG | +AR9170_MAC_RX_CTRL_SHORT_FILTER ; +u32 sniffer =AR9170_MAC_SNIFFER_DEFAULTS ; +int err =0 ; + +rcu_read_lock (); + vif =carl9170_get_main_vif (ar); + +if (vif) { + mac_addr = common->macaddr; + bssid = common->curbssid; + +switch (vif->type) { +case NL80211_IFTYPE_MESH_POINT : +case NL80211_IFTYPE_ADHOC : + cam_mode |=AR9170_MAC_CAM_IBSS ; +break ; +case NL80211_IFTYPE_AP : + cam_mode |=AR9170_MAC_CAM_AP ; + +/* iwlagn 802.11n STA Workaround */ + rx_ctrl |=AR9170_MAC_RX_CTRL_PASS_TO_HOST ; +break ; +case NL80211_IFTYPE_WDS : + cam_mode |=AR9170_MAC_CAM_AP_WDS ; + rx_ctrl |=AR9170_MAC_RX_CTRL_PASS_TO_HOST ; +break ; +case NL80211_IFTYPE_STATION : + cam_mode |=AR9170_MAC_CAM_STA ; + rx_ctrl |=AR9170_MAC_RX_CTRL_PASS_TO_HOST ; +break ; +default : +WARN (1 ,"Unsupported operation mode %x\n" , vif->type); + err = -EOPNOTSUPP ; +break ; + } + }else { + mac_addr =NULL ; + bssid =NULL ; + } +rcu_read_unlock (); + +if (err) +return err; + +if (ar->rx_software_decryption) + enc_mode |=AR9170_MAC_ENCRYPTION_RX_SOFTWARE ; + +if (ar->sniffer_enabled) { + rx_ctrl |=AR9170_MAC_RX_CTRL_ACK_IN_SNIFFER ; + sniffer |=AR9170_MAC_SNIFFER_ENABLE_PROMISC ; + enc_mode |=AR9170_MAC_ENCRYPTION_RX_SOFTWARE ; + } + + err =carl9170_set_mac_reg (ar,AR9170_MAC_REG_MAC_ADDR_L , mac_addr); +if (err) +return err; + + err =carl9170_set_mac_reg (ar,AR9170_MAC_REG_BSSID_L , bssid); +if (err) +return err; + +carl9170_regwrite_begin (ar); +carl9170_regwrite (AR9170_MAC_REG_SNIFFER , sniffer); +carl9170_regwrite (AR9170_MAC_REG_CAM_MODE , cam_mode); +carl9170_regwrite (AR9170_MAC_REG_ENCRYPTION , enc_mode); +carl9170_regwrite (AR9170_MAC_REG_RX_CONTROL , rx_ctrl); +carl9170_regwrite_finish (); + +return carl9170_regwrite_result (); +} + +int carl9170_set_hwretry_limit (struct ar9170 *ar,unsigned int max_retry) +{ +u32 tmp =min_t (u32,0x33333 , max_retry *0x11111 ); + +return carl9170_write_reg (ar,AR9170_MAC_REG_RETRY_MAX , tmp); +} + +int carl9170_set_beacon_timers (struct ar9170 *ar) +{ +struct ieee80211_vif *vif; +u32 v =0 ; +u32 pretbtt =0 ; + +rcu_read_lock (); + vif =carl9170_get_main_vif (ar); + +if (vif) { +struct carl9170_vif_info *mvif; + mvif = (void *) vif->drv_priv; + +if (mvif->enable_beacon && !WARN_ON (!ar->beacon_enabled)) { + ar->global_beacon_int = vif->bss_conf.beacon_int / + ar->beacon_enabled; + +SET_VAL (AR9170_MAC_BCN_DTIM , v, + vif->bss_conf.dtim_period); + +switch (vif->type) { +case NL80211_IFTYPE_MESH_POINT : +case NL80211_IFTYPE_ADHOC : + v |=AR9170_MAC_BCN_IBSS_MODE ; +break ; +case NL80211_IFTYPE_AP : + v |=AR9170_MAC_BCN_AP_MODE ; +break ; +default : +WARN_ON_ONCE (1 ); +break ; + } + }else if (vif->type ==NL80211_IFTYPE_STATION ) { + ar->global_beacon_int = vif->bss_conf.beacon_int; + +SET_VAL (AR9170_MAC_BCN_DTIM , v, + ar->hw->conf.ps_dtim_period); + + v |=AR9170_MAC_BCN_STA_PS | +AR9170_MAC_BCN_PWR_MGT ; + } + +if (ar->global_beacon_int) { +if (ar->global_beacon_int <15 ) { +rcu_read_unlock (); +return -ERANGE ; + } + + ar->global_pretbtt = ar->global_beacon_int - +CARL9170_PRETBTT_KUS ; + }else { + ar->global_pretbtt =0 ; + } + }else { + ar->global_beacon_int =0 ; + ar->global_pretbtt =0 ; + } + +rcu_read_unlock (); + +SET_VAL (AR9170_MAC_BCN_PERIOD , v, ar->global_beacon_int); +SET_VAL (AR9170_MAC_PRETBTT , pretbtt, ar->global_pretbtt); +SET_VAL (AR9170_MAC_PRETBTT2 , pretbtt, ar->global_pretbtt); + +carl9170_regwrite_begin (ar); +carl9170_regwrite (AR9170_MAC_REG_PRETBTT , pretbtt); +carl9170_regwrite (AR9170_MAC_REG_BCN_PERIOD , v); +carl9170_regwrite_finish (); +return carl9170_regwrite_result (); +} + +int carl9170_update_beacon (struct ar9170 *ar,bool submit) +{ +struct sk_buff *skb; +struct carl9170_vif_info *cvif; +__le32 *data, *old =NULL ; +u32 word, off, addr, len; +int i =0 , err =0 ; + +rcu_read_lock (); + cvif =rcu_dereference (ar->beacon_iter); +retry: +if (ar->vifs ==0 ) + goto out_unlock; + +list_for_each_entry_continue_rcu (cvif, &ar->vif_list, list) { +if (cvif && cvif->active && cvif->enable_beacon) + goto found; + } + +if (!ar->beacon_enabled || i++) + goto out_unlock; + + goto retry; + +found: +rcu_assign_pointer (ar->beacon_iter, cvif); + + skb =ieee80211_beacon_get_tim (ar->hw,carl9170_get_vif (cvif), + cvif->tim_offset, cvif->tim_length); + +if (!skb) { + err = -ENOMEM ; + goto out_unlock; + } + +spin_lock_bh (&ar->beacon_lock); + data = (__le32 *)skb->data; +if (cvif->beacon) + old = (__le32 *)cvif->beacon->data; + + off = cvif->id *AR9170_MAC_BCN_LENGTH_MAX ; + addr = ar->beacon_addr + off; + len =roundup (skb->len +FCS_LEN ,4 ); + +if ((off + len) > ar->max_beacon_len) { +if (net_ratelimit ()) { +wiphy_err (ar->hw->wiphy,"beacon does not " +"fit into device memory!\n" ); + } + +spin_unlock_bh (&ar->beacon_lock); +dev_kfree_skb_any (skb); + err = -EINVAL ; + goto out_unlock; + } + +if (len >AR9170_MAC_BCN_LENGTH_MAX ) { +if (net_ratelimit ()) { +wiphy_err (ar->hw->wiphy,"no support for beacons " +"bigger than %d (yours:%d).\n" , +AR9170_MAC_BCN_LENGTH_MAX , len); + } + +spin_unlock_bh (&ar->beacon_lock); +dev_kfree_skb_any (skb); + err = -EMSGSIZE ; + goto out_unlock; + } + +carl9170_async_regwrite_begin (ar); + +/* XXX: use skb->cb info */ +if (ar->hw->conf.channel->band ==IEEE80211_BAND_2GHZ ) { +carl9170_async_regwrite (AR9170_MAC_REG_BCN_PLCP , + ((skb->len +FCS_LEN ) << (3 +16 )) +0x0400 ); + }else { +carl9170_async_regwrite (AR9170_MAC_REG_BCN_PLCP , + ((skb->len +FCS_LEN ) <<16 ) +0x001b ); + } + +for (i =0 ; i <DIV_ROUND_UP (skb->len,4 ); i++) { +/* +* XXX: This accesses beyond skb data for up +* to the last 3 bytes!! +*/ + +if (old && (data[i] == old[i])) +continue ; + + word =le32_to_cpu (data[i]); +carl9170_async_regwrite (addr +4 * i, word); + } +carl9170_async_regwrite_finish (); + +dev_kfree_skb_any (cvif->beacon); + cvif->beacon =NULL ; + + err =carl9170_async_regwrite_result (); +if (!err) + cvif->beacon = skb; +spin_unlock_bh (&ar->beacon_lock); +if (err) + goto out_unlock; + +if (submit) { + err =carl9170_bcn_ctrl (ar, cvif->id, +CARL9170_BCN_CTRL_CAB_TRIGGER , + addr, skb->len +FCS_LEN ); + +if (err) + goto out_unlock; + } +out_unlock: +rcu_read_unlock (); +return err; +} + +int carl9170_upload_key (struct ar9170 *ar,u8 id,const u8 *mac,u8 ktype, +u8 keyidx,u8 *keydata,int keylen) +{ +struct carl9170_set_key_cmd key = { }; +static const u8 bcast[ETH_ALEN ] = { +0xff ,0xff ,0xff ,0xff ,0xff ,0xff }; + + mac = mac ? : bcast; + + key.user =cpu_to_le16 (id); + key.keyId =cpu_to_le16 (keyidx); + key.type =cpu_to_le16 (ktype); +memcpy (&key.macAddr, mac,ETH_ALEN ); +if (keydata) +memcpy (&key.key, keydata, keylen); + +return carl9170_exec_cmd (ar,CARL9170_CMD_EKEY , +sizeof (key), (u8 *)&key,0 ,NULL ); +} + +int carl9170_disable_key (struct ar9170 *ar,u8 id) +{ +struct carl9170_disable_key_cmd key = { }; + + key.user =cpu_to_le16 (id); + +return carl9170_exec_cmd (ar,CARL9170_CMD_DKEY , +sizeof (key), (u8 *)&key,0 ,NULL ); +}
drivers/net/wireless/ath/carl9170/phy.c new file +1802 -0
1,802 lines not on this page · raw message
Signature · 1 line
1.7.1