Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: drivers/net/wireless/libertas/if_sdio.c
This commit is contained in:
commit
e569aa78ba
158 changed files with 4645 additions and 2858 deletions
496
Documentation/DocBook/80211.tmpl
Normal file
496
Documentation/DocBook/80211.tmpl
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||||
|
<set>
|
||||||
|
<setinfo>
|
||||||
|
<title>The 802.11 subsystems – for kernel developers</title>
|
||||||
|
<subtitle>
|
||||||
|
Explaining wireless 802.11 networking in the Linux kernel
|
||||||
|
</subtitle>
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2007-2009</year>
|
||||||
|
<holder>Johannes Berg</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<firstname>Johannes</firstname>
|
||||||
|
<surname>Berg</surname>
|
||||||
|
<affiliation>
|
||||||
|
<address><email>johannes@sipsolutions.net</email></address>
|
||||||
|
</affiliation>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
<legalnotice>
|
||||||
|
<para>
|
||||||
|
This documentation is free software; you can redistribute
|
||||||
|
it and/or modify it under the terms of the GNU General Public
|
||||||
|
License version 2 as published by the Free Software Foundation.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This documentation 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.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You should have received a copy of the GNU General Public
|
||||||
|
License along with this documentation; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
MA 02111-1307 USA
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
For more details see the file COPYING in the source
|
||||||
|
distribution of Linux.
|
||||||
|
</para>
|
||||||
|
</legalnotice>
|
||||||
|
|
||||||
|
<abstract>
|
||||||
|
<para>
|
||||||
|
These books attempt to give a description of the
|
||||||
|
various subsystems that play a role in 802.11 wireless
|
||||||
|
networking in Linux. Since these books are for kernel
|
||||||
|
developers they attempts to document the structures
|
||||||
|
and functions used in the kernel as well as giving a
|
||||||
|
higher-level overview.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The reader is expected to be familiar with the 802.11
|
||||||
|
standard as published by the IEEE in 802.11-2007 (or
|
||||||
|
possibly later versions). References to this standard
|
||||||
|
will be given as "802.11-2007 8.1.5".
|
||||||
|
</para>
|
||||||
|
</abstract>
|
||||||
|
</setinfo>
|
||||||
|
<book id="cfg80211-developers-guide">
|
||||||
|
!Ainclude/net/cfg80211.h
|
||||||
|
<bookinfo>
|
||||||
|
<title>The cfg80211 subsystem</title>
|
||||||
|
|
||||||
|
<abstract>
|
||||||
|
!Pinclude/net/cfg80211.h Introduction
|
||||||
|
</abstract>
|
||||||
|
</bookinfo>
|
||||||
|
<chapter>
|
||||||
|
<title>Device registration</title>
|
||||||
|
!Pinclude/net/cfg80211.h Device registration
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_band
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_channel_flags
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_channel
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_rate_flags
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_rate
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_sta_ht_cap
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_supported_band
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_signal_type
|
||||||
|
!Finclude/net/cfg80211.h wiphy_params_flags
|
||||||
|
!Finclude/net/cfg80211.h wiphy_flags
|
||||||
|
!Finclude/net/cfg80211.h wiphy
|
||||||
|
!Finclude/net/cfg80211.h wireless_dev
|
||||||
|
!Finclude/net/cfg80211.h wiphy_new
|
||||||
|
!Finclude/net/cfg80211.h wiphy_register
|
||||||
|
!Finclude/net/cfg80211.h wiphy_unregister
|
||||||
|
!Finclude/net/cfg80211.h wiphy_free
|
||||||
|
|
||||||
|
!Finclude/net/cfg80211.h wiphy_name
|
||||||
|
!Finclude/net/cfg80211.h wiphy_dev
|
||||||
|
!Finclude/net/cfg80211.h wiphy_priv
|
||||||
|
!Finclude/net/cfg80211.h priv_to_wiphy
|
||||||
|
!Finclude/net/cfg80211.h set_wiphy_dev
|
||||||
|
!Finclude/net/cfg80211.h wdev_priv
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Actions and configuration</title>
|
||||||
|
!Pinclude/net/cfg80211.h Actions and configuration
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_ops
|
||||||
|
!Finclude/net/cfg80211.h vif_params
|
||||||
|
!Finclude/net/cfg80211.h key_params
|
||||||
|
!Finclude/net/cfg80211.h survey_info_flags
|
||||||
|
!Finclude/net/cfg80211.h survey_info
|
||||||
|
!Finclude/net/cfg80211.h beacon_parameters
|
||||||
|
!Finclude/net/cfg80211.h plink_actions
|
||||||
|
!Finclude/net/cfg80211.h station_parameters
|
||||||
|
!Finclude/net/cfg80211.h station_info_flags
|
||||||
|
!Finclude/net/cfg80211.h rate_info_flags
|
||||||
|
!Finclude/net/cfg80211.h rate_info
|
||||||
|
!Finclude/net/cfg80211.h station_info
|
||||||
|
!Finclude/net/cfg80211.h monitor_flags
|
||||||
|
!Finclude/net/cfg80211.h mpath_info_flags
|
||||||
|
!Finclude/net/cfg80211.h mpath_info
|
||||||
|
!Finclude/net/cfg80211.h bss_parameters
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_txq_params
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_crypto_settings
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_auth_request
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_assoc_request
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_deauth_request
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_disassoc_request
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_ibss_params
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_connect_params
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_pmksa
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_rx_auth
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
|
||||||
|
!Finclude/net/cfg80211.h __cfg80211_auth_canceled
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_deauth
|
||||||
|
!Finclude/net/cfg80211.h __cfg80211_send_deauth
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_send_disassoc
|
||||||
|
!Finclude/net/cfg80211.h __cfg80211_send_disassoc
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_ibss_joined
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_connect_result
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_roamed
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_disconnected
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_ready_on_channel
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_remain_on_channel_expired
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_new_sta
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_rx_mgmt
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_mgmt_tx_status
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_michael_mic_failure
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Scanning and BSS list handling</title>
|
||||||
|
!Pinclude/net/cfg80211.h Scanning and BSS list handling
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_ssid
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_scan_request
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_scan_done
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_bss
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_inform_bss_frame
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_inform_bss
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_unlink_bss
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_find_ie
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_bss_get_ie
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Utility functions</title>
|
||||||
|
!Pinclude/net/cfg80211.h Utility functions
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_channel_to_frequency
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_frequency_to_channel
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_get_channel
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_get_response_rate
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_hdrlen
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_get_hdrlen_from_skb
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_radiotap_iterator
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Data path helpers</title>
|
||||||
|
!Pinclude/net/cfg80211.h Data path helpers
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_data_to_8023
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_data_from_8023
|
||||||
|
!Finclude/net/cfg80211.h ieee80211_amsdu_to_8023s
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_classify8021d
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Regulatory enforcement infrastructure</title>
|
||||||
|
!Pinclude/net/cfg80211.h Regulatory enforcement infrastructure
|
||||||
|
!Finclude/net/cfg80211.h regulatory_hint
|
||||||
|
!Finclude/net/cfg80211.h wiphy_apply_custom_regulatory
|
||||||
|
!Finclude/net/cfg80211.h freq_reg_info
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>RFkill integration</title>
|
||||||
|
!Pinclude/net/cfg80211.h RFkill integration
|
||||||
|
!Finclude/net/cfg80211.h wiphy_rfkill_set_hw_state
|
||||||
|
!Finclude/net/cfg80211.h wiphy_rfkill_start_polling
|
||||||
|
!Finclude/net/cfg80211.h wiphy_rfkill_stop_polling
|
||||||
|
</chapter>
|
||||||
|
<chapter>
|
||||||
|
<title>Test mode</title>
|
||||||
|
!Pinclude/net/cfg80211.h Test mode
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_testmode_alloc_reply_skb
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_testmode_reply
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_testmode_alloc_event_skb
|
||||||
|
!Finclude/net/cfg80211.h cfg80211_testmode_event
|
||||||
|
</chapter>
|
||||||
|
</book>
|
||||||
|
<book id="mac80211-developers-guide">
|
||||||
|
<bookinfo>
|
||||||
|
<title>The mac80211 subsystem</title>
|
||||||
|
<abstract>
|
||||||
|
!Pinclude/net/mac80211.h Introduction
|
||||||
|
!Pinclude/net/mac80211.h Warning
|
||||||
|
</abstract>
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<toc></toc>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Generally, this document shall be ordered by increasing complexity.
|
||||||
|
It is important to note that readers should be able to read only
|
||||||
|
the first few sections to get a working driver and only advanced
|
||||||
|
usage should require reading the full document.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>The basic mac80211 driver interface</title>
|
||||||
|
<partintro>
|
||||||
|
<para>
|
||||||
|
You should read and understand the information contained
|
||||||
|
within this part of the book while implementing a driver.
|
||||||
|
In some chapters, advanced usage is noted, that may be
|
||||||
|
skipped at first.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This part of the book only covers station and monitor mode
|
||||||
|
functionality, additional information required to implement
|
||||||
|
the other modes is covered in the second part of the book.
|
||||||
|
</para>
|
||||||
|
</partintro>
|
||||||
|
|
||||||
|
<chapter id="basics">
|
||||||
|
<title>Basic hardware handling</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This chapter shall contain information on getting a hw
|
||||||
|
struct allocated and registered with mac80211.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Since it is required to allocate rates/modes before registering
|
||||||
|
a hw struct, this chapter shall also contain information on setting
|
||||||
|
up the rate/mode structs.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Additionally, some discussion about the callbacks and
|
||||||
|
the general programming model should be in here, including
|
||||||
|
the definition of ieee80211_ops which will be referred to
|
||||||
|
a lot.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Finally, a discussion of hardware capabilities should be done
|
||||||
|
with references to other parts of the book.
|
||||||
|
</para>
|
||||||
|
<!-- intentionally multiple !F lines to get proper order -->
|
||||||
|
!Finclude/net/mac80211.h ieee80211_hw
|
||||||
|
!Finclude/net/mac80211.h ieee80211_hw_flags
|
||||||
|
!Finclude/net/mac80211.h SET_IEEE80211_DEV
|
||||||
|
!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
|
||||||
|
!Finclude/net/mac80211.h ieee80211_ops
|
||||||
|
!Finclude/net/mac80211.h ieee80211_alloc_hw
|
||||||
|
!Finclude/net/mac80211.h ieee80211_register_hw
|
||||||
|
!Finclude/net/mac80211.h ieee80211_get_tx_led_name
|
||||||
|
!Finclude/net/mac80211.h ieee80211_get_rx_led_name
|
||||||
|
!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
|
||||||
|
!Finclude/net/mac80211.h ieee80211_get_radio_led_name
|
||||||
|
!Finclude/net/mac80211.h ieee80211_unregister_hw
|
||||||
|
!Finclude/net/mac80211.h ieee80211_free_hw
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="phy-handling">
|
||||||
|
<title>PHY configuration</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This chapter should describe PHY handling including
|
||||||
|
start/stop callbacks and the various structures used.
|
||||||
|
</para>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_conf
|
||||||
|
!Finclude/net/mac80211.h ieee80211_conf_flags
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="iface-handling">
|
||||||
|
<title>Virtual interfaces</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This chapter should describe virtual interface basics
|
||||||
|
that are relevant to the driver (VLANs, MGMT etc are not.)
|
||||||
|
It should explain the use of the add_iface/remove_iface
|
||||||
|
callbacks as well as the interface configuration callbacks.
|
||||||
|
</para>
|
||||||
|
<para>Things related to AP mode should be discussed there.</para>
|
||||||
|
<para>
|
||||||
|
Things related to supporting multiple interfaces should be
|
||||||
|
in the appropriate chapter, a BIG FAT note should be here about
|
||||||
|
this though and the recommendation to allow only a single
|
||||||
|
interface in STA mode at first!
|
||||||
|
</para>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_vif
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="rx-tx">
|
||||||
|
<title>Receive and transmit processing</title>
|
||||||
|
<sect1>
|
||||||
|
<title>what should be here</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This should describe the receive and transmit
|
||||||
|
paths in mac80211/the drivers as well as
|
||||||
|
transmit status handling.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>Frame format</title>
|
||||||
|
!Pinclude/net/mac80211.h Frame format
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>Packet alignment</title>
|
||||||
|
!Pnet/mac80211/rx.c Packet alignment
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>Calling into mac80211 from interrupts</title>
|
||||||
|
!Pinclude/net/mac80211.h Calling mac80211 from interrupts
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>functions/definitions</title>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_rx_status
|
||||||
|
!Finclude/net/mac80211.h mac80211_rx_flags
|
||||||
|
!Finclude/net/mac80211.h ieee80211_tx_info
|
||||||
|
!Finclude/net/mac80211.h ieee80211_rx
|
||||||
|
!Finclude/net/mac80211.h ieee80211_rx_irqsafe
|
||||||
|
!Finclude/net/mac80211.h ieee80211_tx_status
|
||||||
|
!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
|
||||||
|
!Finclude/net/mac80211.h ieee80211_rts_get
|
||||||
|
!Finclude/net/mac80211.h ieee80211_rts_duration
|
||||||
|
!Finclude/net/mac80211.h ieee80211_ctstoself_get
|
||||||
|
!Finclude/net/mac80211.h ieee80211_ctstoself_duration
|
||||||
|
!Finclude/net/mac80211.h ieee80211_generic_frame_duration
|
||||||
|
!Finclude/net/mac80211.h ieee80211_wake_queue
|
||||||
|
!Finclude/net/mac80211.h ieee80211_stop_queue
|
||||||
|
!Finclude/net/mac80211.h ieee80211_wake_queues
|
||||||
|
!Finclude/net/mac80211.h ieee80211_stop_queues
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="filters">
|
||||||
|
<title>Frame filtering</title>
|
||||||
|
!Pinclude/net/mac80211.h Frame filtering
|
||||||
|
!Finclude/net/mac80211.h ieee80211_filter_flags
|
||||||
|
</chapter>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part id="advanced">
|
||||||
|
<title>Advanced driver interface</title>
|
||||||
|
<partintro>
|
||||||
|
<para>
|
||||||
|
Information contained within this part of the book is
|
||||||
|
of interest only for advanced interaction of mac80211
|
||||||
|
with drivers to exploit more hardware capabilities and
|
||||||
|
improve performance.
|
||||||
|
</para>
|
||||||
|
</partintro>
|
||||||
|
|
||||||
|
<chapter id="hardware-crypto-offload">
|
||||||
|
<title>Hardware crypto acceleration</title>
|
||||||
|
!Pinclude/net/mac80211.h Hardware crypto acceleration
|
||||||
|
<!-- intentionally multiple !F lines to get proper order -->
|
||||||
|
!Finclude/net/mac80211.h set_key_cmd
|
||||||
|
!Finclude/net/mac80211.h ieee80211_key_conf
|
||||||
|
!Finclude/net/mac80211.h ieee80211_key_flags
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="powersave">
|
||||||
|
<title>Powersave support</title>
|
||||||
|
!Pinclude/net/mac80211.h Powersave support
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="beacon-filter">
|
||||||
|
<title>Beacon filter support</title>
|
||||||
|
!Pinclude/net/mac80211.h Beacon filter support
|
||||||
|
!Finclude/net/mac80211.h ieee80211_beacon_loss
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="qos">
|
||||||
|
<title>Multiple queues and QoS support</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_tx_queue_params
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="AP">
|
||||||
|
<title>Access point mode support</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>Some parts of the if_conf should be discussed here instead</para>
|
||||||
|
<para>
|
||||||
|
Insert notes about VLAN interfaces with hw crypto here or
|
||||||
|
in the hw crypto chapter.
|
||||||
|
</para>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_get_buffered_bc
|
||||||
|
!Finclude/net/mac80211.h ieee80211_beacon_get
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="multi-iface">
|
||||||
|
<title>Supporting multiple virtual interfaces</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
Note: WDS with identical MAC address should almost always be OK
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Insert notes about having multiple virtual interfaces with
|
||||||
|
different MAC addresses here, note which configurations are
|
||||||
|
supported by mac80211, add notes about supporting hw crypto
|
||||||
|
with it.
|
||||||
|
</para>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="hardware-scan-offload">
|
||||||
|
<title>Hardware scan offload</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
!Finclude/net/mac80211.h ieee80211_scan_completed
|
||||||
|
</chapter>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part id="rate-control">
|
||||||
|
<title>Rate control interface</title>
|
||||||
|
<partintro>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This part of the book describes the rate control algorithm
|
||||||
|
interface and how it relates to mac80211 and drivers.
|
||||||
|
</para>
|
||||||
|
</partintro>
|
||||||
|
<chapter id="dummy">
|
||||||
|
<title>dummy chapter</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
</chapter>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part id="internal">
|
||||||
|
<title>Internals</title>
|
||||||
|
<partintro>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>
|
||||||
|
This part of the book describes mac80211 internals.
|
||||||
|
</para>
|
||||||
|
</partintro>
|
||||||
|
|
||||||
|
<chapter id="key-handling">
|
||||||
|
<title>Key handling</title>
|
||||||
|
<sect1>
|
||||||
|
<title>Key handling basics</title>
|
||||||
|
!Pnet/mac80211/key.c Key handling basics
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>MORE TBD</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="rx-processing">
|
||||||
|
<title>Receive processing</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="tx-processing">
|
||||||
|
<title>Transmit processing</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="sta-info">
|
||||||
|
<title>Station info handling</title>
|
||||||
|
<sect1>
|
||||||
|
<title>Programming information</title>
|
||||||
|
!Fnet/mac80211/sta_info.h sta_info
|
||||||
|
!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
|
||||||
|
</sect1>
|
||||||
|
<sect1>
|
||||||
|
<title>STA information lifetime rules</title>
|
||||||
|
!Pnet/mac80211/sta_info.c STA information lifetime rules
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="synchronisation">
|
||||||
|
<title>Synchronisation</title>
|
||||||
|
<para>TBD</para>
|
||||||
|
<para>Locking, lots of RCU</para>
|
||||||
|
</chapter>
|
||||||
|
</part>
|
||||||
|
</book>
|
||||||
|
</set>
|
|
@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
|
||||||
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
||||||
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
|
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
|
||||||
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
|
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
|
||||||
mac80211.xml debugobjects.xml sh.xml regulator.xml \
|
80211.xml debugobjects.xml sh.xml regulator.xml \
|
||||||
alsa-driver-api.xml writing-an-alsa-driver.xml \
|
alsa-driver-api.xml writing-an-alsa-driver.xml \
|
||||||
tracepoint.xml media.xml drm.xml
|
tracepoint.xml media.xml drm.xml
|
||||||
|
|
||||||
|
|
|
@ -1,337 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
|
||||||
|
|
||||||
<book id="mac80211-developers-guide">
|
|
||||||
<bookinfo>
|
|
||||||
<title>The mac80211 subsystem for kernel developers</title>
|
|
||||||
|
|
||||||
<authorgroup>
|
|
||||||
<author>
|
|
||||||
<firstname>Johannes</firstname>
|
|
||||||
<surname>Berg</surname>
|
|
||||||
<affiliation>
|
|
||||||
<address><email>johannes@sipsolutions.net</email></address>
|
|
||||||
</affiliation>
|
|
||||||
</author>
|
|
||||||
</authorgroup>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2007-2009</year>
|
|
||||||
<holder>Johannes Berg</holder>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>
|
|
||||||
This documentation is free software; you can redistribute
|
|
||||||
it and/or modify it under the terms of the GNU General Public
|
|
||||||
License version 2 as published by the Free Software Foundation.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This documentation 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.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You should have received a copy of the GNU General Public
|
|
||||||
License along with this documentation; if not, write to the Free
|
|
||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
||||||
MA 02111-1307 USA
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
For more details see the file COPYING in the source
|
|
||||||
distribution of Linux.
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
|
|
||||||
<abstract>
|
|
||||||
!Pinclude/net/mac80211.h Introduction
|
|
||||||
!Pinclude/net/mac80211.h Warning
|
|
||||||
</abstract>
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<toc></toc>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Generally, this document shall be ordered by increasing complexity.
|
|
||||||
It is important to note that readers should be able to read only
|
|
||||||
the first few sections to get a working driver and only advanced
|
|
||||||
usage should require reading the full document.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<part>
|
|
||||||
<title>The basic mac80211 driver interface</title>
|
|
||||||
<partintro>
|
|
||||||
<para>
|
|
||||||
You should read and understand the information contained
|
|
||||||
within this part of the book while implementing a driver.
|
|
||||||
In some chapters, advanced usage is noted, that may be
|
|
||||||
skipped at first.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This part of the book only covers station and monitor mode
|
|
||||||
functionality, additional information required to implement
|
|
||||||
the other modes is covered in the second part of the book.
|
|
||||||
</para>
|
|
||||||
</partintro>
|
|
||||||
|
|
||||||
<chapter id="basics">
|
|
||||||
<title>Basic hardware handling</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This chapter shall contain information on getting a hw
|
|
||||||
struct allocated and registered with mac80211.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Since it is required to allocate rates/modes before registering
|
|
||||||
a hw struct, this chapter shall also contain information on setting
|
|
||||||
up the rate/mode structs.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Additionally, some discussion about the callbacks and
|
|
||||||
the general programming model should be in here, including
|
|
||||||
the definition of ieee80211_ops which will be referred to
|
|
||||||
a lot.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Finally, a discussion of hardware capabilities should be done
|
|
||||||
with references to other parts of the book.
|
|
||||||
</para>
|
|
||||||
<!-- intentionally multiple !F lines to get proper order -->
|
|
||||||
!Finclude/net/mac80211.h ieee80211_hw
|
|
||||||
!Finclude/net/mac80211.h ieee80211_hw_flags
|
|
||||||
!Finclude/net/mac80211.h SET_IEEE80211_DEV
|
|
||||||
!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
|
|
||||||
!Finclude/net/mac80211.h ieee80211_ops
|
|
||||||
!Finclude/net/mac80211.h ieee80211_alloc_hw
|
|
||||||
!Finclude/net/mac80211.h ieee80211_register_hw
|
|
||||||
!Finclude/net/mac80211.h ieee80211_get_tx_led_name
|
|
||||||
!Finclude/net/mac80211.h ieee80211_get_rx_led_name
|
|
||||||
!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
|
|
||||||
!Finclude/net/mac80211.h ieee80211_get_radio_led_name
|
|
||||||
!Finclude/net/mac80211.h ieee80211_unregister_hw
|
|
||||||
!Finclude/net/mac80211.h ieee80211_free_hw
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="phy-handling">
|
|
||||||
<title>PHY configuration</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This chapter should describe PHY handling including
|
|
||||||
start/stop callbacks and the various structures used.
|
|
||||||
</para>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_conf
|
|
||||||
!Finclude/net/mac80211.h ieee80211_conf_flags
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="iface-handling">
|
|
||||||
<title>Virtual interfaces</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This chapter should describe virtual interface basics
|
|
||||||
that are relevant to the driver (VLANs, MGMT etc are not.)
|
|
||||||
It should explain the use of the add_iface/remove_iface
|
|
||||||
callbacks as well as the interface configuration callbacks.
|
|
||||||
</para>
|
|
||||||
<para>Things related to AP mode should be discussed there.</para>
|
|
||||||
<para>
|
|
||||||
Things related to supporting multiple interfaces should be
|
|
||||||
in the appropriate chapter, a BIG FAT note should be here about
|
|
||||||
this though and the recommendation to allow only a single
|
|
||||||
interface in STA mode at first!
|
|
||||||
</para>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_vif
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="rx-tx">
|
|
||||||
<title>Receive and transmit processing</title>
|
|
||||||
<sect1>
|
|
||||||
<title>what should be here</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This should describe the receive and transmit
|
|
||||||
paths in mac80211/the drivers as well as
|
|
||||||
transmit status handling.
|
|
||||||
</para>
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>Frame format</title>
|
|
||||||
!Pinclude/net/mac80211.h Frame format
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>Packet alignment</title>
|
|
||||||
!Pnet/mac80211/rx.c Packet alignment
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>Calling into mac80211 from interrupts</title>
|
|
||||||
!Pinclude/net/mac80211.h Calling mac80211 from interrupts
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>functions/definitions</title>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_rx_status
|
|
||||||
!Finclude/net/mac80211.h mac80211_rx_flags
|
|
||||||
!Finclude/net/mac80211.h ieee80211_tx_info
|
|
||||||
!Finclude/net/mac80211.h ieee80211_rx
|
|
||||||
!Finclude/net/mac80211.h ieee80211_rx_irqsafe
|
|
||||||
!Finclude/net/mac80211.h ieee80211_tx_status
|
|
||||||
!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
|
|
||||||
!Finclude/net/mac80211.h ieee80211_rts_get
|
|
||||||
!Finclude/net/mac80211.h ieee80211_rts_duration
|
|
||||||
!Finclude/net/mac80211.h ieee80211_ctstoself_get
|
|
||||||
!Finclude/net/mac80211.h ieee80211_ctstoself_duration
|
|
||||||
!Finclude/net/mac80211.h ieee80211_generic_frame_duration
|
|
||||||
!Finclude/net/mac80211.h ieee80211_wake_queue
|
|
||||||
!Finclude/net/mac80211.h ieee80211_stop_queue
|
|
||||||
!Finclude/net/mac80211.h ieee80211_wake_queues
|
|
||||||
!Finclude/net/mac80211.h ieee80211_stop_queues
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="filters">
|
|
||||||
<title>Frame filtering</title>
|
|
||||||
!Pinclude/net/mac80211.h Frame filtering
|
|
||||||
!Finclude/net/mac80211.h ieee80211_filter_flags
|
|
||||||
</chapter>
|
|
||||||
</part>
|
|
||||||
|
|
||||||
<part id="advanced">
|
|
||||||
<title>Advanced driver interface</title>
|
|
||||||
<partintro>
|
|
||||||
<para>
|
|
||||||
Information contained within this part of the book is
|
|
||||||
of interest only for advanced interaction of mac80211
|
|
||||||
with drivers to exploit more hardware capabilities and
|
|
||||||
improve performance.
|
|
||||||
</para>
|
|
||||||
</partintro>
|
|
||||||
|
|
||||||
<chapter id="hardware-crypto-offload">
|
|
||||||
<title>Hardware crypto acceleration</title>
|
|
||||||
!Pinclude/net/mac80211.h Hardware crypto acceleration
|
|
||||||
<!-- intentionally multiple !F lines to get proper order -->
|
|
||||||
!Finclude/net/mac80211.h set_key_cmd
|
|
||||||
!Finclude/net/mac80211.h ieee80211_key_conf
|
|
||||||
!Finclude/net/mac80211.h ieee80211_key_alg
|
|
||||||
!Finclude/net/mac80211.h ieee80211_key_flags
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="powersave">
|
|
||||||
<title>Powersave support</title>
|
|
||||||
!Pinclude/net/mac80211.h Powersave support
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="beacon-filter">
|
|
||||||
<title>Beacon filter support</title>
|
|
||||||
!Pinclude/net/mac80211.h Beacon filter support
|
|
||||||
!Finclude/net/mac80211.h ieee80211_beacon_loss
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="qos">
|
|
||||||
<title>Multiple queues and QoS support</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_tx_queue_params
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="AP">
|
|
||||||
<title>Access point mode support</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>Some parts of the if_conf should be discussed here instead</para>
|
|
||||||
<para>
|
|
||||||
Insert notes about VLAN interfaces with hw crypto here or
|
|
||||||
in the hw crypto chapter.
|
|
||||||
</para>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_get_buffered_bc
|
|
||||||
!Finclude/net/mac80211.h ieee80211_beacon_get
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="multi-iface">
|
|
||||||
<title>Supporting multiple virtual interfaces</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
Note: WDS with identical MAC address should almost always be OK
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Insert notes about having multiple virtual interfaces with
|
|
||||||
different MAC addresses here, note which configurations are
|
|
||||||
supported by mac80211, add notes about supporting hw crypto
|
|
||||||
with it.
|
|
||||||
</para>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="hardware-scan-offload">
|
|
||||||
<title>Hardware scan offload</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
!Finclude/net/mac80211.h ieee80211_scan_completed
|
|
||||||
</chapter>
|
|
||||||
</part>
|
|
||||||
|
|
||||||
<part id="rate-control">
|
|
||||||
<title>Rate control interface</title>
|
|
||||||
<partintro>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This part of the book describes the rate control algorithm
|
|
||||||
interface and how it relates to mac80211 and drivers.
|
|
||||||
</para>
|
|
||||||
</partintro>
|
|
||||||
<chapter id="dummy">
|
|
||||||
<title>dummy chapter</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
</chapter>
|
|
||||||
</part>
|
|
||||||
|
|
||||||
<part id="internal">
|
|
||||||
<title>Internals</title>
|
|
||||||
<partintro>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>
|
|
||||||
This part of the book describes mac80211 internals.
|
|
||||||
</para>
|
|
||||||
</partintro>
|
|
||||||
|
|
||||||
<chapter id="key-handling">
|
|
||||||
<title>Key handling</title>
|
|
||||||
<sect1>
|
|
||||||
<title>Key handling basics</title>
|
|
||||||
!Pnet/mac80211/key.c Key handling basics
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>MORE TBD</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="rx-processing">
|
|
||||||
<title>Receive processing</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="tx-processing">
|
|
||||||
<title>Transmit processing</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="sta-info">
|
|
||||||
<title>Station info handling</title>
|
|
||||||
<sect1>
|
|
||||||
<title>Programming information</title>
|
|
||||||
!Fnet/mac80211/sta_info.h sta_info
|
|
||||||
!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
|
|
||||||
</sect1>
|
|
||||||
<sect1>
|
|
||||||
<title>STA information lifetime rules</title>
|
|
||||||
!Pnet/mac80211/sta_info.c STA information lifetime rules
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
<chapter id="synchronisation">
|
|
||||||
<title>Synchronisation</title>
|
|
||||||
<para>TBD</para>
|
|
||||||
<para>Locking, lots of RCU</para>
|
|
||||||
</chapter>
|
|
||||||
</part>
|
|
||||||
</book>
|
|
|
@ -2061,11 +2061,12 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
|
at76_dbg(DBG_MAC80211, "%s(): cmd %d key->cipher %d key->keyidx %d "
|
||||||
"key->keylen %d",
|
"key->keylen %d",
|
||||||
__func__, cmd, key->alg, key->keyidx, key->keylen);
|
__func__, cmd, key->cipher, key->keyidx, key->keylen);
|
||||||
|
|
||||||
if (key->alg != ALG_WEP)
|
if ((key->cipher != WLAN_CIPHER_SUITE_WEP40) &&
|
||||||
|
(key->cipher != WLAN_CIPHER_SUITE_WEP104))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
key->hw_key_idx = key->keyidx;
|
key->hw_key_idx = key->keyidx;
|
||||||
|
|
|
@ -1190,14 +1190,13 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
|
||||||
if (info->control.hw_key) {
|
if (info->control.hw_key) {
|
||||||
icv = info->control.hw_key->icv_len;
|
icv = info->control.hw_key->icv_len;
|
||||||
|
|
||||||
switch (info->control.hw_key->alg) {
|
switch (info->control.hw_key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
keytype = AR9170_TX_MAC_ENCR_RC4;
|
keytype = AR9170_TX_MAC_ENCR_RC4;
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
keytype = AR9170_TX_MAC_ENCR_RC4;
|
|
||||||
break;
|
|
||||||
case ALG_CCMP:
|
|
||||||
keytype = AR9170_TX_MAC_ENCR_AES;
|
keytype = AR9170_TX_MAC_ENCR_AES;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1778,17 +1777,17 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
if ((!ar->vif) || (ar->disable_offload))
|
if ((!ar->vif) || (ar->disable_offload))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
if (key->keylen == WLAN_KEY_LEN_WEP40)
|
ktype = AR9170_ENC_ALG_WEP64;
|
||||||
ktype = AR9170_ENC_ALG_WEP64;
|
|
||||||
else
|
|
||||||
ktype = AR9170_ENC_ALG_WEP128;
|
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
|
ktype = AR9170_ENC_ALG_WEP128;
|
||||||
|
break;
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
ktype = AR9170_ENC_ALG_TKIP;
|
ktype = AR9170_ENC_ALG_TKIP;
|
||||||
break;
|
break;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
ktype = AR9170_ENC_ALG_AESCCMP;
|
ktype = AR9170_ENC_ALG_AESCCMP;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1827,7 +1826,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (key->alg == ALG_TKIP) {
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||||
err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
|
err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
|
||||||
ktype, 1, key->key + 16, 16);
|
ktype, 1, key->key + 16, 16);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1864,7 +1863,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (key->alg == ALG_TKIP) {
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||||
err = ar9170_upload_key(ar, key->hw_key_idx,
|
err = ar9170_upload_key(ar, key->hw_key_idx,
|
||||||
NULL,
|
NULL,
|
||||||
AR9170_ENC_ALG_NONE, 1,
|
AR9170_ENC_ALG_NONE, 1,
|
||||||
|
|
|
@ -552,9 +552,9 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah)
|
||||||
if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
|
if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* if one of the errors triggered, we can get a superfluous second
|
/* If one of the errors triggered, we can get a superfluous second
|
||||||
* interrupt, even though we have already reset the register. the
|
* interrupt, even though we have already reset the register. The
|
||||||
* function detects that so we can return early */
|
* function detects that so we can return early. */
|
||||||
if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
|
if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@
|
||||||
#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0
|
#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0
|
||||||
#define AR5K_TUNE_RADAR_ALERT false
|
#define AR5K_TUNE_RADAR_ALERT false
|
||||||
#define AR5K_TUNE_MIN_TX_FIFO_THRES 1
|
#define AR5K_TUNE_MIN_TX_FIFO_THRES 1
|
||||||
#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1)
|
#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1)
|
||||||
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
|
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
|
||||||
/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
|
/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
|
||||||
* be the max value. */
|
* be the max value. */
|
||||||
|
@ -343,9 +343,6 @@ struct ath5k_srev_name {
|
||||||
#define AR5K_SREV_PHY_5413 0x61
|
#define AR5K_SREV_PHY_5413 0x61
|
||||||
#define AR5K_SREV_PHY_2425 0x70
|
#define AR5K_SREV_PHY_2425 0x70
|
||||||
|
|
||||||
/* IEEE defs */
|
|
||||||
#define IEEE80211_MAX_LEN 2500
|
|
||||||
|
|
||||||
/* TODO add support to mac80211 for vendor-specific rates and modes */
|
/* TODO add support to mac80211 for vendor-specific rates and modes */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1190,7 +1187,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
|
||||||
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
|
void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
|
||||||
/* BSSID Functions */
|
/* BSSID Functions */
|
||||||
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
|
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
|
||||||
void ath5k_hw_set_associd(struct ath5k_hw *ah);
|
void ath5k_hw_set_bssid(struct ath5k_hw *ah);
|
||||||
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
|
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
|
||||||
/* Receive start/stop functions */
|
/* Receive start/stop functions */
|
||||||
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
|
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
|
||||||
|
|
|
@ -139,12 +139,12 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
|
||||||
else
|
else
|
||||||
ah->ah_version = AR5K_AR5212;
|
ah->ah_version = AR5K_AR5212;
|
||||||
|
|
||||||
/*Fill the ath5k_hw struct with the needed functions*/
|
/* Fill the ath5k_hw struct with the needed functions */
|
||||||
ret = ath5k_hw_init_desc_functions(ah);
|
ret = ath5k_hw_init_desc_functions(ah);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
|
||||||
/* Bring device out of sleep and reset it's units */
|
/* Bring device out of sleep and reset its units */
|
||||||
ret = ath5k_hw_nic_wakeup(ah, 0, true);
|
ret = ath5k_hw_nic_wakeup(ah, 0, true);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
@ -158,7 +158,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
|
||||||
CHANNEL_5GHZ);
|
CHANNEL_5GHZ);
|
||||||
ah->ah_phy = AR5K_PHY(0);
|
ah->ah_phy = AR5K_PHY(0);
|
||||||
|
|
||||||
/* Try to identify radio chip based on it's srev */
|
/* Try to identify radio chip based on its srev */
|
||||||
switch (ah->ah_radio_5ghz_revision & 0xf0) {
|
switch (ah->ah_radio_5ghz_revision & 0xf0) {
|
||||||
case AR5K_SREV_RAD_5111:
|
case AR5K_SREV_RAD_5111:
|
||||||
ah->ah_radio = AR5K_RF5111;
|
ah->ah_radio = AR5K_RF5111;
|
||||||
|
@ -329,7 +329,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
|
||||||
|
|
||||||
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
|
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
|
||||||
memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
|
memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
|
||||||
ath5k_hw_set_associd(ah);
|
ath5k_hw_set_bssid(ah);
|
||||||
ath5k_hw_set_opmode(ah, sc->opmode);
|
ath5k_hw_set_opmode(ah, sc->opmode);
|
||||||
|
|
||||||
ath5k_hw_rfgain_opt_init(ah);
|
ath5k_hw_rfgain_opt_init(ah);
|
||||||
|
|
|
@ -612,7 +612,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*If we passed the test malloc a ath5k_hw struct*/
|
/* If we passed the test, malloc an ath5k_hw struct */
|
||||||
sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
|
sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
|
||||||
if (!sc->ah) {
|
if (!sc->ah) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -786,8 +786,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
||||||
/*
|
/*
|
||||||
* Check if the MAC has multi-rate retry support.
|
* Check if the MAC has multi-rate retry support.
|
||||||
* We do this by trying to setup a fake extended
|
* We do this by trying to setup a fake extended
|
||||||
* descriptor. MAC's that don't have support will
|
* descriptor. MACs that don't have support will
|
||||||
* return false w/o doing anything. MAC's that do
|
* return false w/o doing anything. MACs that do
|
||||||
* support it will return true w/o doing anything.
|
* support it will return true w/o doing anything.
|
||||||
*/
|
*/
|
||||||
ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
|
ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
|
||||||
|
@ -827,7 +827,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
||||||
/*
|
/*
|
||||||
* Allocate hardware transmit queues: one queue for
|
* Allocate hardware transmit queues: one queue for
|
||||||
* beacon frames and one data queue for each QoS
|
* beacon frames and one data queue for each QoS
|
||||||
* priority. Note that hw functions handle reseting
|
* priority. Note that hw functions handle resetting
|
||||||
* these queues at the needed time.
|
* these queues at the needed time.
|
||||||
*/
|
*/
|
||||||
ret = ath5k_beaconq_setup(ah);
|
ret = ath5k_beaconq_setup(ah);
|
||||||
|
@ -909,7 +909,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
||||||
/*
|
/*
|
||||||
* NB: the order of these is important:
|
* NB: the order of these is important:
|
||||||
* o call the 802.11 layer before detaching ath5k_hw to
|
* o call the 802.11 layer before detaching ath5k_hw to
|
||||||
* insure callbacks into the driver to delete global
|
* ensure callbacks into the driver to delete global
|
||||||
* key cache entries can be handled
|
* key cache entries can be handled
|
||||||
* o reclaim the tx queue data structures after calling
|
* o reclaim the tx queue data structures after calling
|
||||||
* the 802.11 layer as we'll get called back to reclaim
|
* the 802.11 layer as we'll get called back to reclaim
|
||||||
|
@ -1514,7 +1514,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
|
||||||
/*
|
/*
|
||||||
* Enable interrupts only for EOL and DESC conditions.
|
* Enable interrupts only for EOL and DESC conditions.
|
||||||
* We mark tx descriptors to receive a DESC interrupt
|
* We mark tx descriptors to receive a DESC interrupt
|
||||||
* when a tx queue gets deep; otherwise waiting for the
|
* when a tx queue gets deep; otherwise we wait for the
|
||||||
* EOL to reap descriptors. Note that this is done to
|
* EOL to reap descriptors. Note that this is done to
|
||||||
* reduce interrupt load and this only defers reaping
|
* reduce interrupt load and this only defers reaping
|
||||||
* descriptors, never transmitting frames. Aside from
|
* descriptors, never transmitting frames. Aside from
|
||||||
|
@ -1709,7 +1709,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
|
||||||
struct ath5k_buf *bf;
|
struct ath5k_buf *bf;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
|
common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz);
|
||||||
|
|
||||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
|
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
|
||||||
common->cachelsz, common->rx_bufsize);
|
common->cachelsz, common->rx_bufsize);
|
||||||
|
@ -1859,7 +1859,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute padding position. skb must contains an IEEE 802.11 frame
|
* Compute padding position. skb must contain an IEEE 802.11 frame
|
||||||
*/
|
*/
|
||||||
static int ath5k_common_padpos(struct sk_buff *skb)
|
static int ath5k_common_padpos(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -1878,10 +1878,9 @@ static int ath5k_common_padpos(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function expects a 802.11 frame and returns the number of
|
* This function expects an 802.11 frame and returns the number of
|
||||||
* bytes added, or -1 if we don't have enought header room.
|
* bytes added, or -1 if we don't have enough header room.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ath5k_add_padding(struct sk_buff *skb)
|
static int ath5k_add_padding(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int padpos = ath5k_common_padpos(skb);
|
int padpos = ath5k_common_padpos(skb);
|
||||||
|
@ -1901,10 +1900,18 @@ static int ath5k_add_padding(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function expects a 802.11 frame and returns the number of
|
* The MAC header is padded to have 32-bit boundary if the
|
||||||
* bytes removed
|
* packet payload is non-zero. The general calculation for
|
||||||
|
* padsize would take into account odd header lengths:
|
||||||
|
* padsize = 4 - (hdrlen & 3); however, since only
|
||||||
|
* even-length headers are used, padding can only be 0 or 2
|
||||||
|
* bytes and we can optimize this a bit. We must not try to
|
||||||
|
* remove padding from short control frames that do not have a
|
||||||
|
* payload.
|
||||||
|
*
|
||||||
|
* This function expects an 802.11 frame and returns the number of
|
||||||
|
* bytes removed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ath5k_remove_padding(struct sk_buff *skb)
|
static int ath5k_remove_padding(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int padpos = ath5k_common_padpos(skb);
|
int padpos = ath5k_common_padpos(skb);
|
||||||
|
@ -1925,14 +1932,6 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
|
||||||
{
|
{
|
||||||
struct ieee80211_rx_status *rxs;
|
struct ieee80211_rx_status *rxs;
|
||||||
|
|
||||||
/* The MAC header is padded to have 32-bit boundary if the
|
|
||||||
* packet payload is non-zero. The general calculation for
|
|
||||||
* padsize would take into account odd header lengths:
|
|
||||||
* padsize = (4 - hdrlen % 4) % 4; However, since only
|
|
||||||
* even-length headers are used, padding can only be 0 or 2
|
|
||||||
* bytes and we can optimize this a bit. In addition, we must
|
|
||||||
* not try to remove padding from short control frames that do
|
|
||||||
* not have payload. */
|
|
||||||
ath5k_remove_padding(skb);
|
ath5k_remove_padding(skb);
|
||||||
|
|
||||||
rxs = IEEE80211_SKB_RXCB(skb);
|
rxs = IEEE80211_SKB_RXCB(skb);
|
||||||
|
@ -2036,9 +2035,8 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* let crypto-error packets fall through in MNTR */
|
/* reject any frames with non-crypto errors */
|
||||||
if ((rs->rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
|
if (rs->rs_status & ~(AR5K_RXERR_DECRYPT))
|
||||||
sc->opmode != NL80211_IFTYPE_MONITOR)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2281,10 +2279,11 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||||
* default antenna which is supposed to be an omni.
|
* default antenna which is supposed to be an omni.
|
||||||
*
|
*
|
||||||
* Note2: On sectored scenarios it's possible to have
|
* Note2: On sectored scenarios it's possible to have
|
||||||
* multiple antennas (1omni -the default- and 14 sectors)
|
* multiple antennas (1 omni -- the default -- and 14
|
||||||
* so if we choose to actually support this mode we need
|
* sectors), so if we choose to actually support this
|
||||||
* to allow user to set how many antennas we have and tweak
|
* mode, we need to allow the user to set how many antennas
|
||||||
* the code below to send beacons on all of them.
|
* we have and tweak the code below to send beacons
|
||||||
|
* on all of them.
|
||||||
*/
|
*/
|
||||||
if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
|
if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
|
||||||
antenna = sc->bsent & 4 ? 2 : 1;
|
antenna = sc->bsent & 4 ? 2 : 1;
|
||||||
|
@ -2326,14 +2325,13 @@ ath5k_beacon_send(struct ath5k_softc *sc)
|
||||||
|
|
||||||
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
|
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
|
||||||
|
|
||||||
if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
|
if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) {
|
||||||
sc->opmode == NL80211_IFTYPE_MONITOR)) {
|
|
||||||
ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
|
ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Check if the previous beacon has gone out. If
|
* Check if the previous beacon has gone out. If
|
||||||
* not don't don't try to post another, skip this
|
* not, don't don't try to post another: skip this
|
||||||
* period and wait for the next. Missed beacons
|
* period and wait for the next. Missed beacons
|
||||||
* indicate a problem and should not occur. If we
|
* indicate a problem and should not occur. If we
|
||||||
* miss too many consecutive beacons reset the device.
|
* miss too many consecutive beacons reset the device.
|
||||||
|
@ -2901,12 +2899,9 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||||
|
|
||||||
ath5k_debug_dump_skb(sc, skb, "TX ", 1);
|
ath5k_debug_dump_skb(sc, skb, "TX ", 1);
|
||||||
|
|
||||||
if (sc->opmode == NL80211_IFTYPE_MONITOR)
|
|
||||||
ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the hardware expects the header padded to 4 byte boundaries
|
* The hardware expects the header padded to 4 byte boundaries.
|
||||||
* if this is not the case we add the padding after the header
|
* If this is not the case, we add the padding after the header.
|
||||||
*/
|
*/
|
||||||
padsize = ath5k_add_padding(skb);
|
padsize = ath5k_add_padding(skb);
|
||||||
if (padsize < 0) {
|
if (padsize < 0) {
|
||||||
|
@ -3049,7 +3044,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
case NL80211_IFTYPE_MONITOR:
|
|
||||||
sc->opmode = vif->type;
|
sc->opmode = vif->type;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -3233,9 +3227,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||||
rfilt |= AR5K_RX_FILTER_PHYERR;
|
rfilt |= AR5K_RX_FILTER_PHYERR;
|
||||||
|
|
||||||
/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
|
/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
|
||||||
* and probes for any BSSID, this needs testing */
|
* and probes for any BSSID */
|
||||||
if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
|
if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
|
||||||
rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
|
rfilt |= AR5K_RX_FILTER_BEACON;
|
||||||
|
|
||||||
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
|
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
|
||||||
* set we should only pass on control frames for this
|
* set we should only pass on control frames for this
|
||||||
|
@ -3251,7 +3245,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
switch (sc->opmode) {
|
switch (sc->opmode) {
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
case NL80211_IFTYPE_MONITOR:
|
|
||||||
rfilt |= AR5K_RX_FILTER_CONTROL |
|
rfilt |= AR5K_RX_FILTER_CONTROL |
|
||||||
AR5K_RX_FILTER_BEACON |
|
AR5K_RX_FILTER_BEACON |
|
||||||
AR5K_RX_FILTER_PROBEREQ |
|
AR5K_RX_FILTER_PROBEREQ |
|
||||||
|
@ -3274,7 +3267,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
/* Set multicast bits */
|
/* Set multicast bits */
|
||||||
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
|
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
|
||||||
/* Set the cached hw filter flags, this will alter actually
|
/* Set the cached hw filter flags, this will later actually
|
||||||
* be set in HW */
|
* be set in HW */
|
||||||
sc->filter_flags = rfilt;
|
sc->filter_flags = rfilt;
|
||||||
|
|
||||||
|
@ -3297,11 +3290,12 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
if (sc->opmode == NL80211_IFTYPE_AP)
|
if (sc->opmode == NL80211_IFTYPE_AP)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
break;
|
break;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
if (sc->ah->ah_aes_support)
|
if (sc->ah->ah_aes_support)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3475,7 +3469,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
/* Cache for later use during resets */
|
/* Cache for later use during resets */
|
||||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||||
common->curaid = 0;
|
common->curaid = 0;
|
||||||
ath5k_hw_set_associd(ah);
|
ath5k_hw_set_bssid(ah);
|
||||||
mmiowb();
|
mmiowb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3493,7 +3487,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
"Bss Info ASSOC %d, bssid: %pM\n",
|
"Bss Info ASSOC %d, bssid: %pM\n",
|
||||||
bss_conf->aid, common->curbssid);
|
bss_conf->aid, common->curbssid);
|
||||||
common->curaid = bss_conf->aid;
|
common->curaid = bss_conf->aid;
|
||||||
ath5k_hw_set_associd(ah);
|
ath5k_hw_set_bssid(ah);
|
||||||
/* Once ANI is available you would start it here */
|
/* Once ANI is available you would start it here */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,11 +377,11 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
|
||||||
*
|
*
|
||||||
* This function increases/decreases the tx trigger level for the tx fifo
|
* This function increases/decreases the tx trigger level for the tx fifo
|
||||||
* buffer (aka FIFO threshold) that is used to indicate when PCU flushes
|
* buffer (aka FIFO threshold) that is used to indicate when PCU flushes
|
||||||
* the buffer and transmits it's data. Lowering this results sending small
|
* the buffer and transmits its data. Lowering this results sending small
|
||||||
* frames more quickly but can lead to tx underruns, raising it a lot can
|
* frames more quickly but can lead to tx underruns, raising it a lot can
|
||||||
* result other problems (i think bmiss is related). Right now we start with
|
* result other problems (i think bmiss is related). Right now we start with
|
||||||
* the lowest possible (64Bytes) and if we get tx underrun we increase it using
|
* the lowest possible (64Bytes) and if we get tx underrun we increase it using
|
||||||
* the increase flag. Returns -EIO if we have have reached maximum/minimum.
|
* the increase flag. Returns -EIO if we have reached maximum/minimum.
|
||||||
*
|
*
|
||||||
* XXX: Link this with tx DMA size ?
|
* XXX: Link this with tx DMA size ?
|
||||||
* XXX: Use it to save interrupts ?
|
* XXX: Use it to save interrupts ?
|
||||||
|
|
|
@ -661,7 +661,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
|
||||||
* (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
|
* (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
|
||||||
* steps that match with the power values we read from eeprom. On
|
* steps that match with the power values we read from eeprom. On
|
||||||
* older eeprom versions (< 3.2) these steps are equaly spaced at
|
* older eeprom versions (< 3.2) these steps are equaly spaced at
|
||||||
* 10% of the pcdac curve -until the curve reaches it's maximum-
|
* 10% of the pcdac curve -until the curve reaches its maximum-
|
||||||
* (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
|
* (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
|
||||||
* these 11 steps are spaced in a different way. This function returns
|
* these 11 steps are spaced in a different way. This function returns
|
||||||
* the pcdac steps based on eeprom version and curve min/max so that we
|
* the pcdac steps based on eeprom version and curve min/max so that we
|
||||||
|
@ -1113,7 +1113,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* For RF2413 power calibration data doesn't start on a fixed location and
|
/* For RF2413 power calibration data doesn't start on a fixed location and
|
||||||
* if a mode is not supported, it's section is missing -not zeroed-.
|
* if a mode is not supported, its section is missing -not zeroed-.
|
||||||
* So we need to calculate the starting offset for each section by using
|
* So we need to calculate the starting offset for each section by using
|
||||||
* these two functions */
|
* these two functions */
|
||||||
|
|
||||||
|
|
|
@ -308,27 +308,26 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ath5k_hw_set_associd - Set BSSID for association
|
* ath5k_hw_set_bssid - Set current BSSID on hw
|
||||||
*
|
*
|
||||||
* @ah: The &struct ath5k_hw
|
* @ah: The &struct ath5k_hw
|
||||||
* @bssid: BSSID
|
|
||||||
* @assoc_id: Assoc id
|
|
||||||
*
|
*
|
||||||
* Sets the BSSID which trigers the "SME Join" operation
|
* Sets the current BSSID and BSSID mask we have from the
|
||||||
|
* common struct into the hardware
|
||||||
*/
|
*/
|
||||||
void ath5k_hw_set_associd(struct ath5k_hw *ah)
|
void ath5k_hw_set_bssid(struct ath5k_hw *ah)
|
||||||
{
|
{
|
||||||
struct ath_common *common = ath5k_hw_common(ah);
|
struct ath_common *common = ath5k_hw_common(ah);
|
||||||
u16 tim_offset = 0;
|
u16 tim_offset = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set simple BSSID mask on 5212
|
* Set BSSID mask on 5212
|
||||||
*/
|
*/
|
||||||
if (ah->ah_version == AR5K_AR5212)
|
if (ah->ah_version == AR5K_AR5212)
|
||||||
ath_hw_setbssidmask(common);
|
ath_hw_setbssidmask(common);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set BSSID which triggers the "SME Join" operation
|
* Set BSSID
|
||||||
*/
|
*/
|
||||||
ath5k_hw_reg_write(ah,
|
ath5k_hw_reg_write(ah,
|
||||||
get_unaligned_le32(common->curbssid),
|
get_unaligned_le32(common->curbssid),
|
||||||
|
@ -695,21 +694,18 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
|
||||||
static
|
static
|
||||||
int ath5k_keycache_type(const struct ieee80211_key_conf *key)
|
int ath5k_keycache_type(const struct ieee80211_key_conf *key)
|
||||||
{
|
{
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
return AR5K_KEYTABLE_TYPE_TKIP;
|
return AR5K_KEYTABLE_TYPE_TKIP;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
return AR5K_KEYTABLE_TYPE_CCM;
|
return AR5K_KEYTABLE_TYPE_CCM;
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
if (key->keylen == WLAN_KEY_LEN_WEP40)
|
return AR5K_KEYTABLE_TYPE_40;
|
||||||
return AR5K_KEYTABLE_TYPE_40;
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
else if (key->keylen == WLAN_KEY_LEN_WEP104)
|
return AR5K_KEYTABLE_TYPE_104;
|
||||||
return AR5K_KEYTABLE_TYPE_104;
|
|
||||||
return -EINVAL;
|
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -728,7 +724,7 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
|
||||||
bool is_tkip;
|
bool is_tkip;
|
||||||
const u8 *key_ptr;
|
const u8 *key_ptr;
|
||||||
|
|
||||||
is_tkip = (key->alg == ALG_TKIP);
|
is_tkip = (key->cipher == WLAN_CIPHER_SUITE_TKIP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* key->keylen comes in from mac80211 in bytes.
|
* key->keylen comes in from mac80211 in bytes.
|
||||||
|
|
|
@ -115,7 +115,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
|
||||||
\**********************/
|
\**********************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This code is used to optimize rf gain on different environments
|
* This code is used to optimize RF gain on different environments
|
||||||
* (temperature mostly) based on feedback from a power detector.
|
* (temperature mostly) based on feedback from a power detector.
|
||||||
*
|
*
|
||||||
* It's only used on RF5111 and RF5112, later RF chips seem to have
|
* It's only used on RF5111 and RF5112, later RF chips seem to have
|
||||||
|
@ -302,7 +302,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform gain_F adjustment by choosing the right set
|
/* Perform gain_F adjustment by choosing the right set
|
||||||
* of parameters from rf gain optimization ladder */
|
* of parameters from RF gain optimization ladder */
|
||||||
static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
|
static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
|
||||||
{
|
{
|
||||||
const struct ath5k_gain_opt *go;
|
const struct ath5k_gain_opt *go;
|
||||||
|
@ -367,7 +367,7 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main callback for thermal rf gain calibration engine
|
/* Main callback for thermal RF gain calibration engine
|
||||||
* Check for a new gain reading and schedule an adjustment
|
* Check for a new gain reading and schedule an adjustment
|
||||||
* if needed.
|
* if needed.
|
||||||
*
|
*
|
||||||
|
@ -433,7 +433,7 @@ done:
|
||||||
return ah->ah_gain.g_state;
|
return ah->ah_gain.g_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write initial rf gain table to set the RF sensitivity
|
/* Write initial RF gain table to set the RF sensitivity
|
||||||
* this one works on all RF chips and has nothing to do
|
* this one works on all RF chips and has nothing to do
|
||||||
* with gain_F calibration */
|
* with gain_F calibration */
|
||||||
int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
|
int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
|
||||||
|
@ -496,7 +496,7 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup RF registers by writing rf buffer on hw
|
* Setup RF registers by writing RF buffer on hw
|
||||||
*/
|
*/
|
||||||
int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
||||||
unsigned int mode)
|
unsigned int mode)
|
||||||
|
@ -571,7 +571,7 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it's the first time we set rf buffer, allocate
|
/* If it's the first time we set RF buffer, allocate
|
||||||
* ah->ah_rf_banks based on ah->ah_rf_banks_size
|
* ah->ah_rf_banks based on ah->ah_rf_banks_size
|
||||||
* we set above */
|
* we set above */
|
||||||
if (ah->ah_rf_banks == NULL) {
|
if (ah->ah_rf_banks == NULL) {
|
||||||
|
@ -3035,9 +3035,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
||||||
/* Limit max power if we have a CTL available */
|
/* Limit max power if we have a CTL available */
|
||||||
ath5k_get_max_ctl_power(ah, channel);
|
ath5k_get_max_ctl_power(ah, channel);
|
||||||
|
|
||||||
/* FIXME: Tx power limit for this regdomain
|
|
||||||
* XXX: Mac80211/CRDA will do that anyway ? */
|
|
||||||
|
|
||||||
/* FIXME: Antenna reduction stuff */
|
/* FIXME: Antenna reduction stuff */
|
||||||
|
|
||||||
/* FIXME: Limit power on turbo modes */
|
/* FIXME: Limit power on turbo modes */
|
||||||
|
|
|
@ -1911,7 +1911,7 @@
|
||||||
#define AR5K_PHY_TURBO 0x9804 /* Register Address */
|
#define AR5K_PHY_TURBO 0x9804 /* Register Address */
|
||||||
#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */
|
#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */
|
||||||
#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */
|
#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */
|
||||||
#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */
|
#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PHY agility command register
|
* PHY agility command register
|
||||||
|
|
|
@ -959,7 +959,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
AR5K_QUEUE_DCU_SEQNUM(0));
|
AR5K_QUEUE_DCU_SEQNUM(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TSF accelerates on AR5211 durring reset
|
/* TSF accelerates on AR5211 during reset
|
||||||
* As a workaround save it here and restore
|
* As a workaround save it here and restore
|
||||||
* it later so that it's back in time after
|
* it later so that it's back in time after
|
||||||
* reset. This way it'll get re-synced on the
|
* reset. This way it'll get re-synced on the
|
||||||
|
@ -1080,7 +1080,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Spur info is available only from EEPROM versions
|
/* Spur info is available only from EEPROM versions
|
||||||
* bigger than 5.3 but but the EEPOM routines will use
|
* greater than 5.3, but the EEPROM routines will use
|
||||||
* static values for older versions */
|
* static values for older versions */
|
||||||
if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
|
if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
|
||||||
ath5k_hw_set_spur_mitigation_filter(ah,
|
ath5k_hw_set_spur_mitigation_filter(ah,
|
||||||
|
@ -1160,7 +1160,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Restore bssid and bssid mask */
|
/* Restore bssid and bssid mask */
|
||||||
ath5k_hw_set_associd(ah);
|
ath5k_hw_set_bssid(ah);
|
||||||
|
|
||||||
/* Set PCU config */
|
/* Set PCU config */
|
||||||
ath5k_hw_set_opmode(ah, op_mode);
|
ath5k_hw_set_opmode(ah, op_mode);
|
||||||
|
@ -1173,11 +1173,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
/* Set RSSI/BRSSI thresholds
|
/* Set RSSI/BRSSI thresholds
|
||||||
*
|
*
|
||||||
* Note: If we decide to set this value
|
* Note: If we decide to set this value
|
||||||
* dynamicaly, have in mind that when AR5K_RSSI_THR
|
* dynamically, keep in mind that when AR5K_RSSI_THR
|
||||||
* register is read it might return 0x40 if we haven't
|
* register is read, it might return 0x40 if we haven't
|
||||||
* wrote anything to it plus BMISS RSSI threshold is zeroed.
|
* written anything to it. Also, BMISS RSSI threshold is zeroed.
|
||||||
* So doing a save/restore procedure here isn't the right
|
* So doing a save/restore procedure here isn't the right
|
||||||
* choice. Instead store it on ath5k_hw */
|
* choice. Instead, store it in ath5k_hw */
|
||||||
ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
|
ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
|
||||||
AR5K_TUNE_BMISS_THRES <<
|
AR5K_TUNE_BMISS_THRES <<
|
||||||
AR5K_RSSI_THR_BMISS_S),
|
AR5K_RSSI_THR_BMISS_S),
|
||||||
|
@ -1235,7 +1235,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform ADC test to see if baseband is ready
|
* Perform ADC test to see if baseband is ready
|
||||||
* Set tx hold and check adc test register
|
* Set TX hold and check ADC test register
|
||||||
*/
|
*/
|
||||||
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
|
phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
|
||||||
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
|
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
|
||||||
|
@ -1254,15 +1254,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||||
*
|
*
|
||||||
* This method is used to calibrate some static offsets
|
* This method is used to calibrate some static offsets
|
||||||
* used together with on-the fly I/Q calibration (the
|
* used together with on-the fly I/Q calibration (the
|
||||||
* one performed via ath5k_hw_phy_calibrate), that doesn't
|
* one performed via ath5k_hw_phy_calibrate), which doesn't
|
||||||
* interrupt rx path.
|
* interrupt rx path.
|
||||||
*
|
*
|
||||||
* While rx path is re-routed to the power detector we also
|
* While rx path is re-routed to the power detector we also
|
||||||
* start a noise floor calibration, to measure the
|
* start a noise floor calibration to measure the
|
||||||
* card's noise floor (the noise we measure when we are not
|
* card's noise floor (the noise we measure when we are not
|
||||||
* transmiting or receiving anything).
|
* transmitting or receiving anything).
|
||||||
*
|
*
|
||||||
* If we are in a noisy environment AGC calibration may time
|
* If we are in a noisy environment, AGC calibration may time
|
||||||
* out and/or noise floor calibration might timeout.
|
* out and/or noise floor calibration might timeout.
|
||||||
*/
|
*/
|
||||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
|
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
*
|
*
|
||||||
* We don't write on those registers directly but
|
* We don't write on those registers directly but
|
||||||
* we send a data packet on the chip, using a special register,
|
* we send a data packet on the chip, using a special register,
|
||||||
* that holds all the settings we need. After we 've sent the
|
* that holds all the settings we need. After we've sent the
|
||||||
* data packet, we write on another special register to notify hw
|
* data packet, we write on another special register to notify hw
|
||||||
* to apply the settings. This is done so that control registers
|
* to apply the settings. This is done so that control registers
|
||||||
* can be dynamicaly programmed during operation and the settings
|
* can be dynamically programmed during operation and the settings
|
||||||
* are applied faster on the hw.
|
* are applied faster on the hw.
|
||||||
*
|
*
|
||||||
* We call each data packet an "RF Bank" and all the data we write
|
* We call each data packet an "RF Bank" and all the data we write
|
||||||
|
|
|
@ -46,6 +46,7 @@ ath9k_htc-y += htc_hst.o \
|
||||||
htc_drv_txrx.o \
|
htc_drv_txrx.o \
|
||||||
htc_drv_main.o \
|
htc_drv_main.o \
|
||||||
htc_drv_beacon.o \
|
htc_drv_beacon.o \
|
||||||
htc_drv_init.o
|
htc_drv_init.o \
|
||||||
|
htc_drv_gpio.o
|
||||||
|
|
||||||
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
|
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
|
||||||
|
|
|
@ -185,7 +185,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
||||||
ath_print(common, ATH_DBG_INTERRUPT,
|
ath_print(common, ATH_DBG_INTERRUPT,
|
||||||
"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
|
"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
|
||||||
|
|
||||||
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
|
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
|
||||||
(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
|
(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -423,6 +423,7 @@ int ath_beaconq_config(struct ath_softc *sc);
|
||||||
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
|
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
|
||||||
#define ATH_ANI_POLLINTERVAL_OLD 100 /* 100 ms */
|
#define ATH_ANI_POLLINTERVAL_OLD 100 /* 100 ms */
|
||||||
#define ATH_ANI_POLLINTERVAL_NEW 1000 /* 1000 ms */
|
#define ATH_ANI_POLLINTERVAL_NEW 1000 /* 1000 ms */
|
||||||
|
#define ATH_LONG_CALINTERVAL_INT 1000 /* 1000 ms */
|
||||||
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
|
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
|
||||||
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
|
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
|
||||||
|
|
||||||
|
@ -436,14 +437,6 @@ void ath_ani_calibrate(unsigned long data);
|
||||||
/* BTCOEX */
|
/* BTCOEX */
|
||||||
/**********/
|
/**********/
|
||||||
|
|
||||||
/* Defines the BT AR_BT_COEX_WGHT used */
|
|
||||||
enum ath_stomp_type {
|
|
||||||
ATH_BTCOEX_NO_STOMP,
|
|
||||||
ATH_BTCOEX_STOMP_ALL,
|
|
||||||
ATH_BTCOEX_STOMP_LOW,
|
|
||||||
ATH_BTCOEX_STOMP_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ath_btcoex {
|
struct ath_btcoex {
|
||||||
bool hw_timer_enabled;
|
bool hw_timer_enabled;
|
||||||
spinlock_t btcoex_lock;
|
spinlock_t btcoex_lock;
|
||||||
|
|
|
@ -359,11 +359,12 @@ void ath_beacon_tasklet(unsigned long data)
|
||||||
sc->beacon.bmisscnt++;
|
sc->beacon.bmisscnt++;
|
||||||
|
|
||||||
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
|
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
|
||||||
ath_print(common, ATH_DBG_BEACON,
|
ath_print(common, ATH_DBG_BSTUCK,
|
||||||
"missed %u consecutive beacons\n",
|
"missed %u consecutive beacons\n",
|
||||||
sc->beacon.bmisscnt);
|
sc->beacon.bmisscnt);
|
||||||
|
ath9k_hw_bstuck_nfcal(ah);
|
||||||
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
||||||
ath_print(common, ATH_DBG_BEACON,
|
ath_print(common, ATH_DBG_BSTUCK,
|
||||||
"beacon is officially stuck\n");
|
"beacon is officially stuck\n");
|
||||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||||
ath_reset(sc, false);
|
ath_reset(sc, false);
|
||||||
|
@ -373,7 +374,7 @@ void ath_beacon_tasklet(unsigned long data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->beacon.bmisscnt != 0) {
|
if (sc->beacon.bmisscnt != 0) {
|
||||||
ath_print(common, ATH_DBG_BEACON,
|
ath_print(common, ATH_DBG_BSTUCK,
|
||||||
"resume beacon xmit after %u misses\n",
|
"resume beacon xmit after %u misses\n",
|
||||||
sc->beacon.bmisscnt);
|
sc->beacon.bmisscnt);
|
||||||
sc->beacon.bmisscnt = 0;
|
sc->beacon.bmisscnt = 0;
|
||||||
|
|
|
@ -168,6 +168,7 @@ EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
|
||||||
static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program coex mode and weight registers to
|
* Program coex mode and weight registers to
|
||||||
|
@ -177,6 +178,12 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
|
||||||
REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
|
REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
|
||||||
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
|
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
|
||||||
|
|
||||||
|
if (AR_SREV_9271(ah)) {
|
||||||
|
val = REG_READ(ah, 0x50040);
|
||||||
|
val &= 0xFFFFFEFF;
|
||||||
|
REG_WRITE(ah, 0x50040, val);
|
||||||
|
}
|
||||||
|
|
||||||
REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
|
REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
|
||||||
REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
|
REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
|
|
||||||
/* Common calibration code */
|
/* Common calibration code */
|
||||||
|
|
||||||
/* We can tune this as we go by monitoring really low values */
|
#define ATH9K_NF_TOO_HIGH -60
|
||||||
#define ATH9K_NF_TOO_LOW -60
|
|
||||||
|
|
||||||
static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
|
static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
|
||||||
{
|
{
|
||||||
|
@ -45,11 +44,39 @@ static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
|
||||||
return nfval;
|
return nfval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
|
static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
|
||||||
|
struct ath9k_channel *chan)
|
||||||
|
{
|
||||||
|
struct ath_nf_limits *limit;
|
||||||
|
|
||||||
|
if (!chan || IS_CHAN_2GHZ(chan))
|
||||||
|
limit = &ah->nf_2g;
|
||||||
|
else
|
||||||
|
limit = &ah->nf_5g;
|
||||||
|
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
|
||||||
|
struct ath9k_channel *chan)
|
||||||
|
{
|
||||||
|
return ath9k_hw_get_nf_limits(ah, chan)->nominal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
|
||||||
|
struct ath9k_hw_cal_data *cal,
|
||||||
int16_t *nfarray)
|
int16_t *nfarray)
|
||||||
{
|
{
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
struct ath_nf_limits *limit;
|
||||||
|
struct ath9k_nfcal_hist *h;
|
||||||
|
bool high_nf_mid = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
h = cal->nfCalHist;
|
||||||
|
limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
|
||||||
|
|
||||||
for (i = 0; i < NUM_NF_READINGS; i++) {
|
for (i = 0; i < NUM_NF_READINGS; i++) {
|
||||||
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
|
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
|
||||||
|
|
||||||
|
@ -63,7 +90,39 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
|
||||||
h[i].privNF =
|
h[i].privNF =
|
||||||
ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
|
ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!h[i].privNF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (h[i].privNF > limit->max) {
|
||||||
|
high_nf_mid = true;
|
||||||
|
|
||||||
|
ath_print(common, ATH_DBG_CALIBRATE,
|
||||||
|
"NFmid[%d] (%d) > MAX (%d), %s\n",
|
||||||
|
i, h[i].privNF, limit->max,
|
||||||
|
(cal->nfcal_interference ?
|
||||||
|
"not corrected (due to interference)" :
|
||||||
|
"correcting to MAX"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Normally we limit the average noise floor by the
|
||||||
|
* hardware specific maximum here. However if we have
|
||||||
|
* encountered stuck beacons because of interference,
|
||||||
|
* we bypass this limit here in order to better deal
|
||||||
|
* with our environment.
|
||||||
|
*/
|
||||||
|
if (!cal->nfcal_interference)
|
||||||
|
h[i].privNF = limit->max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the noise floor seems normal for all chains, assume that
|
||||||
|
* there is no significant interference in the environment anymore.
|
||||||
|
* Re-enable the enforcement of the NF maximum again.
|
||||||
|
*/
|
||||||
|
if (!high_nf_mid)
|
||||||
|
cal->nfcal_interference = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
|
static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
|
||||||
|
@ -104,19 +163,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||||
ah->cal_samples = 0;
|
ah->cal_samples = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
|
|
||||||
struct ath9k_channel *chan)
|
|
||||||
{
|
|
||||||
struct ath_nf_limits *limit;
|
|
||||||
|
|
||||||
if (!chan || IS_CHAN_2GHZ(chan))
|
|
||||||
limit = &ah->nf_2g;
|
|
||||||
else
|
|
||||||
limit = &ah->nf_5g;
|
|
||||||
|
|
||||||
return limit->nominal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is done for the currently configured channel */
|
/* This is done for the currently configured channel */
|
||||||
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
|
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
|
@ -277,10 +323,10 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
|
||||||
"NF calibrated [%s] [chain %d] is %d\n",
|
"NF calibrated [%s] [chain %d] is %d\n",
|
||||||
(i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
|
(i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
|
||||||
|
|
||||||
if (nf[i] > limit->max) {
|
if (nf[i] > ATH9K_NF_TOO_HIGH) {
|
||||||
ath_print(common, ATH_DBG_CALIBRATE,
|
ath_print(common, ATH_DBG_CALIBRATE,
|
||||||
"NF[%d] (%d) > MAX (%d), correcting to MAX",
|
"NF[%d] (%d) > MAX (%d), correcting to MAX",
|
||||||
i, nf[i], limit->max);
|
i, nf[i], ATH9K_NF_TOO_HIGH);
|
||||||
nf[i] = limit->max;
|
nf[i] = limit->max;
|
||||||
} else if (nf[i] < limit->min) {
|
} else if (nf[i] < limit->min) {
|
||||||
ath_print(common, ATH_DBG_CALIBRATE,
|
ath_print(common, ATH_DBG_CALIBRATE,
|
||||||
|
@ -326,7 +372,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
|
|
||||||
h = caldata->nfCalHist;
|
h = caldata->nfCalHist;
|
||||||
caldata->nfcal_pending = false;
|
caldata->nfcal_pending = false;
|
||||||
ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
|
ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
|
||||||
caldata->rawNoiseFloor = h[0].privNF;
|
caldata->rawNoiseFloor = h[0].privNF;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -361,3 +407,28 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
return ah->caldata->rawNoiseFloor;
|
return ah->caldata->rawNoiseFloor;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
|
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
|
||||||
|
|
||||||
|
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
|
||||||
|
{
|
||||||
|
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||||
|
|
||||||
|
if (unlikely(!caldata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If beacons are stuck, the most likely cause is interference.
|
||||||
|
* Triggering a noise floor calibration at this point helps the
|
||||||
|
* hardware adapt to a noisy environment much faster.
|
||||||
|
* To ensure that we recover from stuck beacons quickly, let
|
||||||
|
* the baseband update the internal NF value itself, similar to
|
||||||
|
* what is being done after a full reset.
|
||||||
|
*/
|
||||||
|
if (!caldata->nfcal_pending)
|
||||||
|
ath9k_hw_start_nfcal(ah, true);
|
||||||
|
else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
|
||||||
|
ath9k_hw_getnf(ah, ah->curchan);
|
||||||
|
|
||||||
|
caldata->nfcal_interference = true;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||||
bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
|
bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||||
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
||||||
struct ath9k_channel *chan);
|
struct ath9k_channel *chan);
|
||||||
|
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
|
||||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
|
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||||
void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||||
struct ath9k_cal_list *currCal);
|
struct ath9k_cal_list *currCal);
|
||||||
|
|
|
@ -46,12 +46,17 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
|
|
||||||
if (tx_info->control.hw_key) {
|
if (tx_info->control.hw_key) {
|
||||||
if (tx_info->control.hw_key->alg == ALG_WEP)
|
switch (tx_info->control.hw_key->cipher) {
|
||||||
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
return ATH9K_KEY_TYPE_WEP;
|
return ATH9K_KEY_TYPE_WEP;
|
||||||
else if (tx_info->control.hw_key->alg == ALG_TKIP)
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
return ATH9K_KEY_TYPE_TKIP;
|
return ATH9K_KEY_TYPE_TKIP;
|
||||||
else if (tx_info->control.hw_key->alg == ALG_CCMP)
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
return ATH9K_KEY_TYPE_AES;
|
return ATH9K_KEY_TYPE_AES;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ATH9K_KEY_TYPE_CLEAR;
|
return ATH9K_KEY_TYPE_CLEAR;
|
||||||
|
@ -212,11 +217,11 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath_reserve_key_cache_slot(struct ath_common *common,
|
static int ath_reserve_key_cache_slot(struct ath_common *common,
|
||||||
enum ieee80211_key_alg alg)
|
u32 cipher)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (alg == ALG_TKIP)
|
if (cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||||
return ath_reserve_key_cache_slot_tkip(common);
|
return ath_reserve_key_cache_slot_tkip(common);
|
||||||
|
|
||||||
/* First, try to find slots that would not be available for TKIP. */
|
/* First, try to find slots that would not be available for TKIP. */
|
||||||
|
@ -293,14 +298,15 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
|
|
||||||
memset(&hk, 0, sizeof(hk));
|
memset(&hk, 0, sizeof(hk));
|
||||||
|
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
hk.kv_type = ATH9K_CIPHER_WEP;
|
hk.kv_type = ATH9K_CIPHER_WEP;
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
hk.kv_type = ATH9K_CIPHER_TKIP;
|
hk.kv_type = ATH9K_CIPHER_TKIP;
|
||||||
break;
|
break;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
hk.kv_type = ATH9K_CIPHER_AES_CCM;
|
hk.kv_type = ATH9K_CIPHER_AES_CCM;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -316,7 +322,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
memcpy(gmac, vif->addr, ETH_ALEN);
|
memcpy(gmac, vif->addr, ETH_ALEN);
|
||||||
gmac[0] |= 0x01;
|
gmac[0] |= 0x01;
|
||||||
mac = gmac;
|
mac = gmac;
|
||||||
idx = ath_reserve_key_cache_slot(common, key->alg);
|
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
if (!sta) {
|
if (!sta) {
|
||||||
|
@ -326,7 +332,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
memcpy(gmac, sta->addr, ETH_ALEN);
|
memcpy(gmac, sta->addr, ETH_ALEN);
|
||||||
gmac[0] |= 0x01;
|
gmac[0] |= 0x01;
|
||||||
mac = gmac;
|
mac = gmac;
|
||||||
idx = ath_reserve_key_cache_slot(common, key->alg);
|
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
idx = key->keyidx;
|
idx = key->keyidx;
|
||||||
|
@ -348,13 +354,13 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
mac = sta->addr;
|
mac = sta->addr;
|
||||||
|
|
||||||
idx = ath_reserve_key_cache_slot(common, key->alg);
|
idx = ath_reserve_key_cache_slot(common, key->cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
return -ENOSPC; /* no free key cache entries */
|
return -ENOSPC; /* no free key cache entries */
|
||||||
|
|
||||||
if (key->alg == ALG_TKIP)
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||||
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
|
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
|
||||||
vif->type == NL80211_IFTYPE_AP);
|
vif->type == NL80211_IFTYPE_AP);
|
||||||
else
|
else
|
||||||
|
@ -364,7 +370,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
set_bit(idx, common->keymap);
|
set_bit(idx, common->keymap);
|
||||||
if (key->alg == ALG_TKIP) {
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||||
set_bit(idx + 64, common->keymap);
|
set_bit(idx + 64, common->keymap);
|
||||||
if (common->splitmic) {
|
if (common->splitmic) {
|
||||||
set_bit(idx + 32, common->keymap);
|
set_bit(idx + 32, common->keymap);
|
||||||
|
@ -389,7 +395,7 @@ void ath9k_cmn_key_delete(struct ath_common *common,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear_bit(key->hw_key_idx, common->keymap);
|
clear_bit(key->hw_key_idx, common->keymap);
|
||||||
if (key->alg != ALG_TKIP)
|
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clear_bit(key->hw_key_idx + 64, common->keymap);
|
clear_bit(key->hw_key_idx + 64, common->keymap);
|
||||||
|
@ -414,6 +420,37 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ath9k_cmn_count_streams);
|
EXPORT_SYMBOL(ath9k_cmn_count_streams);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configures appropriate weight based on stomp type.
|
||||||
|
*/
|
||||||
|
void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
|
||||||
|
enum ath_stomp_type stomp_type)
|
||||||
|
{
|
||||||
|
struct ath_hw *ah = common->ah;
|
||||||
|
|
||||||
|
switch (stomp_type) {
|
||||||
|
case ATH_BTCOEX_STOMP_ALL:
|
||||||
|
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||||
|
AR_STOMP_ALL_WLAN_WGHT);
|
||||||
|
break;
|
||||||
|
case ATH_BTCOEX_STOMP_LOW:
|
||||||
|
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||||
|
AR_STOMP_LOW_WLAN_WGHT);
|
||||||
|
break;
|
||||||
|
case ATH_BTCOEX_STOMP_NONE:
|
||||||
|
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||||
|
AR_STOMP_NONE_WLAN_WGHT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ath_print(common, ATH_DBG_BTCOEX,
|
||||||
|
"Invalid Stomptype\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath9k_hw_btcoex_enable(ah);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp);
|
||||||
|
|
||||||
static int __init ath9k_cmn_init(void)
|
static int __init ath9k_cmn_init(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -52,6 +52,14 @@
|
||||||
#define ATH_EP_RND(x, mul) \
|
#define ATH_EP_RND(x, mul) \
|
||||||
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
|
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
|
||||||
|
|
||||||
|
/* Defines the BT AR_BT_COEX_WGHT used */
|
||||||
|
enum ath_stomp_type {
|
||||||
|
ATH_BTCOEX_NO_STOMP,
|
||||||
|
ATH_BTCOEX_STOMP_ALL,
|
||||||
|
ATH_BTCOEX_STOMP_LOW,
|
||||||
|
ATH_BTCOEX_STOMP_NONE
|
||||||
|
};
|
||||||
|
|
||||||
int ath9k_cmn_padpos(__le16 frame_control);
|
int ath9k_cmn_padpos(__le16 frame_control);
|
||||||
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
|
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
|
||||||
void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
|
void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
|
||||||
|
@ -65,3 +73,5 @@ int ath9k_cmn_key_config(struct ath_common *common,
|
||||||
void ath9k_cmn_key_delete(struct ath_common *common,
|
void ath9k_cmn_key_delete(struct ath_common *common,
|
||||||
struct ieee80211_key_conf *key);
|
struct ieee80211_key_conf *key);
|
||||||
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
|
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
|
||||||
|
void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
|
||||||
|
enum ath_stomp_type stomp_type);
|
||||||
|
|
|
@ -251,36 +251,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Configures appropriate weight based on stomp type.
|
|
||||||
*/
|
|
||||||
static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
|
|
||||||
enum ath_stomp_type stomp_type)
|
|
||||||
{
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
|
|
||||||
switch (stomp_type) {
|
|
||||||
case ATH_BTCOEX_STOMP_ALL:
|
|
||||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
|
||||||
AR_STOMP_ALL_WLAN_WGHT);
|
|
||||||
break;
|
|
||||||
case ATH_BTCOEX_STOMP_LOW:
|
|
||||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
|
||||||
AR_STOMP_LOW_WLAN_WGHT);
|
|
||||||
break;
|
|
||||||
case ATH_BTCOEX_STOMP_NONE:
|
|
||||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
|
||||||
AR_STOMP_NONE_WLAN_WGHT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
|
||||||
"Invalid Stomptype\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ath9k_hw_btcoex_enable(ah);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath9k_gen_timer_start(struct ath_hw *ah,
|
static void ath9k_gen_timer_start(struct ath_hw *ah,
|
||||||
struct ath_gen_timer *timer,
|
struct ath_gen_timer *timer,
|
||||||
u32 timer_next,
|
u32 timer_next,
|
||||||
|
@ -319,6 +289,7 @@ static void ath_btcoex_period_timer(unsigned long data)
|
||||||
struct ath_softc *sc = (struct ath_softc *) data;
|
struct ath_softc *sc = (struct ath_softc *) data;
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
u32 timer_period;
|
u32 timer_period;
|
||||||
bool is_btscan;
|
bool is_btscan;
|
||||||
|
|
||||||
|
@ -328,7 +299,7 @@ static void ath_btcoex_period_timer(unsigned long data)
|
||||||
|
|
||||||
spin_lock_bh(&btcoex->btcoex_lock);
|
spin_lock_bh(&btcoex->btcoex_lock);
|
||||||
|
|
||||||
ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL :
|
ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
|
||||||
btcoex->bt_stomp_type);
|
btcoex->bt_stomp_type);
|
||||||
|
|
||||||
spin_unlock_bh(&btcoex->btcoex_lock);
|
spin_unlock_bh(&btcoex->btcoex_lock);
|
||||||
|
@ -359,17 +330,18 @@ static void ath_btcoex_no_stomp_timer(void *arg)
|
||||||
struct ath_softc *sc = (struct ath_softc *)arg;
|
struct ath_softc *sc = (struct ath_softc *)arg;
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
|
bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
|
||||||
|
|
||||||
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
ath_print(common, ATH_DBG_BTCOEX,
|
||||||
"no stomp timer running\n");
|
"no stomp timer running\n");
|
||||||
|
|
||||||
spin_lock_bh(&btcoex->btcoex_lock);
|
spin_lock_bh(&btcoex->btcoex_lock);
|
||||||
|
|
||||||
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
|
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
|
||||||
ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
|
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
|
||||||
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
|
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
|
||||||
ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
|
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
|
||||||
|
|
||||||
spin_unlock_bh(&btcoex->btcoex_lock);
|
spin_unlock_bh(&btcoex->btcoex_lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -920,7 +920,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
|
ret = ath9k_htc_hw_init(hif_dev->htc_handle,
|
||||||
&hif_dev->udev->dev, hif_dev->device_id);
|
&hif_dev->udev->dev, hif_dev->device_id,
|
||||||
|
hif_dev->udev->product);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_htc_hw_init;
|
goto err_htc_hw_init;
|
||||||
|
|
|
@ -316,17 +316,32 @@ struct htc_beacon_config {
|
||||||
u8 dtim_count;
|
u8 dtim_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OP_INVALID BIT(0)
|
struct ath_btcoex {
|
||||||
#define OP_SCANNING BIT(1)
|
u32 bt_priority_cnt;
|
||||||
#define OP_FULL_RESET BIT(2)
|
unsigned long bt_priority_time;
|
||||||
#define OP_LED_ASSOCIATED BIT(3)
|
int bt_stomp_type; /* Types of BT stomping */
|
||||||
#define OP_LED_ON BIT(4)
|
u32 btcoex_no_stomp;
|
||||||
#define OP_PREAMBLE_SHORT BIT(5)
|
u32 btcoex_period;
|
||||||
#define OP_PROTECT_ENABLE BIT(6)
|
u32 btscan_no_stomp;
|
||||||
#define OP_ASSOCIATED BIT(7)
|
};
|
||||||
#define OP_ENABLE_BEACON BIT(8)
|
|
||||||
#define OP_LED_DEINIT BIT(9)
|
void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv);
|
||||||
#define OP_UNPLUGGED BIT(10)
|
void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv);
|
||||||
|
void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
|
||||||
|
|
||||||
|
#define OP_INVALID BIT(0)
|
||||||
|
#define OP_SCANNING BIT(1)
|
||||||
|
#define OP_FULL_RESET BIT(2)
|
||||||
|
#define OP_LED_ASSOCIATED BIT(3)
|
||||||
|
#define OP_LED_ON BIT(4)
|
||||||
|
#define OP_PREAMBLE_SHORT BIT(5)
|
||||||
|
#define OP_PROTECT_ENABLE BIT(6)
|
||||||
|
#define OP_ASSOCIATED BIT(7)
|
||||||
|
#define OP_ENABLE_BEACON BIT(8)
|
||||||
|
#define OP_LED_DEINIT BIT(9)
|
||||||
|
#define OP_UNPLUGGED BIT(10)
|
||||||
|
#define OP_BT_PRIORITY_DETECTED BIT(11)
|
||||||
|
#define OP_BT_SCAN BIT(12)
|
||||||
|
|
||||||
struct ath9k_htc_priv {
|
struct ath9k_htc_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -391,6 +406,9 @@ struct ath9k_htc_priv {
|
||||||
int cabq;
|
int cabq;
|
||||||
int hwq_map[WME_NUM_AC];
|
int hwq_map[WME_NUM_AC];
|
||||||
|
|
||||||
|
struct ath_btcoex btcoex;
|
||||||
|
struct delayed_work coex_period_work;
|
||||||
|
struct delayed_work duty_cycle_work;
|
||||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||||
struct ath9k_debug debug;
|
struct ath9k_debug debug;
|
||||||
#endif
|
#endif
|
||||||
|
@ -443,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv);
|
||||||
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
|
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
|
||||||
|
|
||||||
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
|
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
|
||||||
u16 devid);
|
u16 devid, char *product);
|
||||||
void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
|
void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
int ath9k_htc_resume(struct htc_target *htc_handle);
|
int ath9k_htc_resume(struct htc_target *htc_handle);
|
||||||
|
|
134
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
Normal file
134
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "htc.h"
|
||||||
|
|
||||||
|
/******************/
|
||||||
|
/* BTCOEX */
|
||||||
|
/******************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detects if there is any priority bt traffic
|
||||||
|
*/
|
||||||
|
static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
|
||||||
|
{
|
||||||
|
struct ath_btcoex *btcoex = &priv->btcoex;
|
||||||
|
struct ath_hw *ah = priv->ah;
|
||||||
|
|
||||||
|
if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
|
||||||
|
btcoex->bt_priority_cnt++;
|
||||||
|
|
||||||
|
if (time_after(jiffies, btcoex->bt_priority_time +
|
||||||
|
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
|
||||||
|
priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
|
||||||
|
/* Detect if colocated bt started scanning */
|
||||||
|
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
|
||||||
|
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||||
|
"BT scan detected");
|
||||||
|
priv->op_flags |= (OP_BT_SCAN |
|
||||||
|
OP_BT_PRIORITY_DETECTED);
|
||||||
|
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
|
||||||
|
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||||
|
"BT priority traffic detected");
|
||||||
|
priv->op_flags |= OP_BT_PRIORITY_DETECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
btcoex->bt_priority_cnt = 0;
|
||||||
|
btcoex->bt_priority_time = jiffies;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the master bt coex work which runs for every
|
||||||
|
* 45ms, bt traffic will be given priority during 55% of this
|
||||||
|
* period while wlan gets remaining 45%
|
||||||
|
*/
|
||||||
|
static void ath_btcoex_period_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
|
||||||
|
coex_period_work.work);
|
||||||
|
struct ath_btcoex *btcoex = &priv->btcoex;
|
||||||
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||||
|
u32 timer_period;
|
||||||
|
bool is_btscan;
|
||||||
|
int ret;
|
||||||
|
u8 cmd_rsp, aggr;
|
||||||
|
|
||||||
|
ath_detect_bt_priority(priv);
|
||||||
|
|
||||||
|
is_btscan = !!(priv->op_flags & OP_BT_SCAN);
|
||||||
|
|
||||||
|
aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
|
||||||
|
|
||||||
|
WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
|
||||||
|
|
||||||
|
ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
|
||||||
|
btcoex->bt_stomp_type);
|
||||||
|
|
||||||
|
timer_period = is_btscan ? btcoex->btscan_no_stomp :
|
||||||
|
btcoex->btcoex_no_stomp;
|
||||||
|
ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
|
||||||
|
msecs_to_jiffies(timer_period));
|
||||||
|
ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
|
||||||
|
msecs_to_jiffies(btcoex->btcoex_period));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work to time slice between wlan and bt traffic and
|
||||||
|
* configure weight registers
|
||||||
|
*/
|
||||||
|
static void ath_btcoex_duty_cycle_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
|
||||||
|
duty_cycle_work.work);
|
||||||
|
struct ath_hw *ah = priv->ah;
|
||||||
|
struct ath_btcoex *btcoex = &priv->btcoex;
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
bool is_btscan = priv->op_flags & OP_BT_SCAN;
|
||||||
|
|
||||||
|
ath_print(common, ATH_DBG_BTCOEX,
|
||||||
|
"time slice work for bt and wlan\n");
|
||||||
|
|
||||||
|
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
|
||||||
|
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
|
||||||
|
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
|
||||||
|
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
|
||||||
|
{
|
||||||
|
struct ath_btcoex *btcoex = &priv->btcoex;
|
||||||
|
|
||||||
|
btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
|
||||||
|
btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
|
||||||
|
btcoex->btcoex_period / 100;
|
||||||
|
btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
|
||||||
|
btcoex->btcoex_period / 100;
|
||||||
|
INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
|
||||||
|
INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (Re)start btcoex work
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
|
||||||
|
{
|
||||||
|
struct ath_btcoex *btcoex = &priv->btcoex;
|
||||||
|
struct ath_hw *ah = priv->ah;
|
||||||
|
|
||||||
|
ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
|
||||||
|
"Starting btcoex work");
|
||||||
|
|
||||||
|
btcoex->bt_priority_cnt = 0;
|
||||||
|
btcoex->bt_priority_time = jiffies;
|
||||||
|
priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
|
||||||
|
ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cancel btcoex and bt duty cycle work.
|
||||||
|
*/
|
||||||
|
void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
|
||||||
|
{
|
||||||
|
cancel_delayed_work_sync(&priv->coex_period_work);
|
||||||
|
cancel_delayed_work_sync(&priv->duty_cycle_work);
|
||||||
|
}
|
|
@ -41,6 +41,8 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
|
||||||
.max_power = 20, \
|
.max_power = 20, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
|
||||||
|
|
||||||
static struct ieee80211_channel ath9k_2ghz_channels[] = {
|
static struct ieee80211_channel ath9k_2ghz_channels[] = {
|
||||||
CHAN2G(2412, 0), /* Channel 1 */
|
CHAN2G(2412, 0), /* Channel 1 */
|
||||||
CHAN2G(2417, 1), /* Channel 2 */
|
CHAN2G(2417, 1), /* Channel 2 */
|
||||||
|
@ -605,7 +607,31 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
|
||||||
priv->ah->opmode = NL80211_IFTYPE_STATION;
|
priv->ah->opmode = NL80211_IFTYPE_STATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
|
static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
|
||||||
|
{
|
||||||
|
int qnum;
|
||||||
|
|
||||||
|
switch (priv->ah->btcoex_hw.scheme) {
|
||||||
|
case ATH_BTCOEX_CFG_NONE:
|
||||||
|
break;
|
||||||
|
case ATH_BTCOEX_CFG_3WIRE:
|
||||||
|
priv->ah->btcoex_hw.btactive_gpio = 7;
|
||||||
|
priv->ah->btcoex_hw.btpriority_gpio = 6;
|
||||||
|
priv->ah->btcoex_hw.wlanactive_gpio = 8;
|
||||||
|
priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
|
||||||
|
ath9k_hw_btcoex_init_3wire(priv->ah);
|
||||||
|
ath_htc_init_btcoex_work(priv);
|
||||||
|
qnum = priv->hwq_map[WME_AC_BE];
|
||||||
|
ath9k_hw_init_btcoex_hw(priv->ah, qnum);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
||||||
|
u16 devid, char *product)
|
||||||
{
|
{
|
||||||
struct ath_hw *ah = NULL;
|
struct ath_hw *ah = NULL;
|
||||||
struct ath_common *common;
|
struct ath_common *common;
|
||||||
|
@ -672,6 +698,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
|
||||||
ath9k_init_channels_rates(priv);
|
ath9k_init_channels_rates(priv);
|
||||||
ath9k_init_misc(priv);
|
ath9k_init_misc(priv);
|
||||||
|
|
||||||
|
if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
|
||||||
|
ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
|
||||||
|
ath9k_init_btcoex(priv);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_queues:
|
err_queues:
|
||||||
|
@ -734,7 +765,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
||||||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
|
static int ath9k_init_device(struct ath9k_htc_priv *priv,
|
||||||
|
u16 devid, char *product)
|
||||||
{
|
{
|
||||||
struct ieee80211_hw *hw = priv->hw;
|
struct ieee80211_hw *hw = priv->hw;
|
||||||
struct ath_common *common;
|
struct ath_common *common;
|
||||||
|
@ -743,7 +775,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
|
||||||
struct ath_regulatory *reg;
|
struct ath_regulatory *reg;
|
||||||
|
|
||||||
/* Bring up device */
|
/* Bring up device */
|
||||||
error = ath9k_init_priv(priv, devid);
|
error = ath9k_init_priv(priv, devid, product);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto err_init;
|
goto err_init;
|
||||||
|
|
||||||
|
@ -801,7 +833,7 @@ err_init:
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
|
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
|
||||||
u16 devid)
|
u16 devid, char *product)
|
||||||
{
|
{
|
||||||
struct ieee80211_hw *hw;
|
struct ieee80211_hw *hw;
|
||||||
struct ath9k_htc_priv *priv;
|
struct ath9k_htc_priv *priv;
|
||||||
|
@ -835,7 +867,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
|
||||||
/* The device may have been unplugged earlier. */
|
/* The device may have been unplugged earlier. */
|
||||||
priv->op_flags &= ~OP_UNPLUGGED;
|
priv->op_flags &= ~OP_UNPLUGGED;
|
||||||
|
|
||||||
ret = ath9k_init_device(priv, devid);
|
ret = ath9k_init_device(priv, devid, product);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_init;
|
goto err_init;
|
||||||
|
|
||||||
|
|
|
@ -1210,6 +1210,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
|
||||||
|
|
||||||
ieee80211_wake_queues(hw);
|
ieee80211_wake_queues(hw);
|
||||||
|
|
||||||
|
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
|
||||||
|
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||||
|
AR_STOMP_LOW_WLAN_WGHT);
|
||||||
|
ath9k_hw_btcoex_enable(ah);
|
||||||
|
ath_htc_resume_btcoex_work(priv);
|
||||||
|
}
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1254,6 +1260,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
|
||||||
"Monitor interface removed\n");
|
"Monitor interface removed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ah->btcoex_hw.enabled) {
|
||||||
|
ath9k_hw_btcoex_disable(ah);
|
||||||
|
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
|
||||||
|
ath_htc_cancel_btcoex_work(priv);
|
||||||
|
}
|
||||||
|
|
||||||
ath9k_hw_phy_disable(ah);
|
ath9k_hw_phy_disable(ah);
|
||||||
ath9k_hw_disable(ah);
|
ath9k_hw_disable(ah);
|
||||||
ath9k_hw_configpcipowersave(ah, 1, 1);
|
ath9k_hw_configpcipowersave(ah, 1, 1);
|
||||||
|
@ -1585,9 +1597,10 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
|
||||||
key->hw_key_idx = ret;
|
key->hw_key_idx = ret;
|
||||||
/* push IV and Michael MIC generation to stack */
|
/* push IV and Michael MIC generation to stack */
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
if (key->alg == ALG_TKIP)
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||||
if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
|
if (priv->ah->sw_mgmt_crypto &&
|
||||||
|
key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,9 +462,9 @@ void ath9k_htc_hw_free(struct htc_target *htc)
|
||||||
}
|
}
|
||||||
|
|
||||||
int ath9k_htc_hw_init(struct htc_target *target,
|
int ath9k_htc_hw_init(struct htc_target *target,
|
||||||
struct device *dev, u16 devid)
|
struct device *dev, u16 devid, char *product)
|
||||||
{
|
{
|
||||||
if (ath9k_htc_probe_device(target, dev, devid)) {
|
if (ath9k_htc_probe_device(target, dev, devid, product)) {
|
||||||
printk(KERN_ERR "Failed to initialize the device\n");
|
printk(KERN_ERR "Failed to initialize the device\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
|
||||||
struct device *dev);
|
struct device *dev);
|
||||||
void ath9k_htc_hw_free(struct htc_target *htc);
|
void ath9k_htc_hw_free(struct htc_target *htc);
|
||||||
int ath9k_htc_hw_init(struct htc_target *target,
|
int ath9k_htc_hw_init(struct htc_target *target,
|
||||||
struct device *dev, u16 devid);
|
struct device *dev, u16 devid, char *product);
|
||||||
void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
|
void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
|
||||||
|
|
||||||
#endif /* HTC_HST_H */
|
#endif /* HTC_HST_H */
|
||||||
|
|
|
@ -355,6 +355,7 @@ struct ath9k_hw_cal_data {
|
||||||
int16_t rawNoiseFloor;
|
int16_t rawNoiseFloor;
|
||||||
bool paprd_done;
|
bool paprd_done;
|
||||||
bool nfcal_pending;
|
bool nfcal_pending;
|
||||||
|
bool nfcal_interference;
|
||||||
u16 small_signal_gain[AR9300_MAX_CHAINS];
|
u16 small_signal_gain[AR9300_MAX_CHAINS];
|
||||||
u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
|
u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
|
||||||
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
|
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
|
||||||
|
|
|
@ -226,9 +226,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||||
caldata = &aphy->caldata;
|
caldata = &aphy->caldata;
|
||||||
|
|
||||||
ath_print(common, ATH_DBG_CONFIG,
|
ath_print(common, ATH_DBG_CONFIG,
|
||||||
"(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
|
"(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
|
||||||
sc->sc_ah->curchan->channel,
|
sc->sc_ah->curchan->channel,
|
||||||
channel->center_freq, conf_is_ht40(conf));
|
channel->center_freq, conf_is_ht40(conf),
|
||||||
|
fastcc);
|
||||||
|
|
||||||
spin_lock_bh(&sc->sc_resetlock);
|
spin_lock_bh(&sc->sc_resetlock);
|
||||||
|
|
||||||
|
@ -395,7 +396,12 @@ void ath_ani_calibrate(unsigned long data)
|
||||||
bool shortcal = false;
|
bool shortcal = false;
|
||||||
bool aniflag = false;
|
bool aniflag = false;
|
||||||
unsigned int timestamp = jiffies_to_msecs(jiffies);
|
unsigned int timestamp = jiffies_to_msecs(jiffies);
|
||||||
u32 cal_interval, short_cal_interval;
|
u32 cal_interval, short_cal_interval, long_cal_interval;
|
||||||
|
|
||||||
|
if (ah->caldata && ah->caldata->nfcal_interference)
|
||||||
|
long_cal_interval = ATH_LONG_CALINTERVAL_INT;
|
||||||
|
else
|
||||||
|
long_cal_interval = ATH_LONG_CALINTERVAL;
|
||||||
|
|
||||||
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
||||||
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
||||||
|
@ -407,7 +413,7 @@ void ath_ani_calibrate(unsigned long data)
|
||||||
ath9k_ps_wakeup(sc);
|
ath9k_ps_wakeup(sc);
|
||||||
|
|
||||||
/* Long calibration runs independently of short calibration. */
|
/* Long calibration runs independently of short calibration. */
|
||||||
if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
|
if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
|
||||||
longcal = true;
|
longcal = true;
|
||||||
ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
|
ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
|
||||||
common->ani.longcal_timer = timestamp;
|
common->ani.longcal_timer = timestamp;
|
||||||
|
@ -1776,9 +1782,10 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
||||||
key->hw_key_idx = ret;
|
key->hw_key_idx = ret;
|
||||||
/* push IV and Michael MIC generation to stack */
|
/* push IV and Michael MIC generation to stack */
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
if (key->alg == ALG_TKIP)
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||||
if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
|
if (sc->sc_ah->sw_mgmt_crypto &&
|
||||||
|
key->cipher == WLAN_CIPHER_SUITE_CCMP)
|
||||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
|
||||||
return "WMI_TGT_DETACH_CMDID";
|
return "WMI_TGT_DETACH_CMDID";
|
||||||
case WMI_TGT_TXQ_ENABLE_CMDID:
|
case WMI_TGT_TXQ_ENABLE_CMDID:
|
||||||
return "WMI_TGT_TXQ_ENABLE_CMDID";
|
return "WMI_TGT_TXQ_ENABLE_CMDID";
|
||||||
|
case WMI_AGGR_LIMIT_CMD:
|
||||||
|
return "WMI_AGGR_LIMIT_CMD";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Bogus";
|
return "Bogus";
|
||||||
|
|
|
@ -71,6 +71,7 @@ enum wmi_cmd_id {
|
||||||
WMI_TX_AGGR_ENABLE_CMDID,
|
WMI_TX_AGGR_ENABLE_CMDID,
|
||||||
WMI_TGT_DETACH_CMDID,
|
WMI_TGT_DETACH_CMDID,
|
||||||
WMI_TGT_TXQ_ENABLE_CMDID,
|
WMI_TGT_TXQ_ENABLE_CMDID,
|
||||||
|
WMI_AGGR_LIMIT_CMD = 0x0026,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wmi_event_id {
|
enum wmi_event_id {
|
||||||
|
|
|
@ -1407,22 +1407,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
|
||||||
return htype;
|
return htype;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_hw_crypto_keytype(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
|
||||||
|
|
||||||
if (tx_info->control.hw_key) {
|
|
||||||
if (tx_info->control.hw_key->alg == ALG_WEP)
|
|
||||||
return ATH9K_KEY_TYPE_WEP;
|
|
||||||
else if (tx_info->control.hw_key->alg == ALG_TKIP)
|
|
||||||
return ATH9K_KEY_TYPE_TKIP;
|
|
||||||
else if (tx_info->control.hw_key->alg == ALG_CCMP)
|
|
||||||
return ATH9K_KEY_TYPE_AES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ATH9K_KEY_TYPE_CLEAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assign_aggr_tid_seqno(struct sk_buff *skb,
|
static void assign_aggr_tid_seqno(struct sk_buff *skb,
|
||||||
struct ath_buf *bf)
|
struct ath_buf *bf)
|
||||||
{
|
{
|
||||||
|
@ -1661,7 +1645,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
||||||
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
||||||
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
|
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
|
||||||
|
|
||||||
bf->bf_keytype = get_hw_crypto_keytype(skb);
|
bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
|
||||||
if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
|
if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
|
||||||
bf->bf_frmlen += tx_info->control.hw_key->icv_len;
|
bf->bf_frmlen += tx_info->control.hw_key->icv_len;
|
||||||
bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
|
bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
* @ATH_DBG_PS: power save processing
|
* @ATH_DBG_PS: power save processing
|
||||||
* @ATH_DBG_HWTIMER: hardware timer handling
|
* @ATH_DBG_HWTIMER: hardware timer handling
|
||||||
* @ATH_DBG_BTCOEX: bluetooth coexistance
|
* @ATH_DBG_BTCOEX: bluetooth coexistance
|
||||||
|
* @ATH_DBG_BSTUCK: stuck beacons
|
||||||
* @ATH_DBG_ANY: enable all debugging
|
* @ATH_DBG_ANY: enable all debugging
|
||||||
*
|
*
|
||||||
* The debug level is used to control the amount and type of debugging output
|
* The debug level is used to control the amount and type of debugging output
|
||||||
|
@ -60,6 +61,7 @@ enum ATH_DEBUG {
|
||||||
ATH_DBG_HWTIMER = 0x00001000,
|
ATH_DBG_HWTIMER = 0x00001000,
|
||||||
ATH_DBG_BTCOEX = 0x00002000,
|
ATH_DBG_BTCOEX = 0x00002000,
|
||||||
ATH_DBG_WMI = 0x00004000,
|
ATH_DBG_WMI = 0x00004000,
|
||||||
|
ATH_DBG_BSTUCK = 0x00008000,
|
||||||
ATH_DBG_ANY = 0xffffffff
|
ATH_DBG_ANY = 0xffffffff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2280,6 +2280,7 @@ out:
|
||||||
|
|
||||||
static int b43_upload_microcode(struct b43_wldev *dev)
|
static int b43_upload_microcode(struct b43_wldev *dev)
|
||||||
{
|
{
|
||||||
|
struct wiphy *wiphy = dev->wl->hw->wiphy;
|
||||||
const size_t hdr_len = sizeof(struct b43_fw_header);
|
const size_t hdr_len = sizeof(struct b43_fw_header);
|
||||||
const __be32 *data;
|
const __be32 *data;
|
||||||
unsigned int i, len;
|
unsigned int i, len;
|
||||||
|
@ -2405,6 +2406,10 @@ static int b43_upload_microcode(struct b43_wldev *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
|
||||||
|
dev->fw.rev, dev->fw.patch);
|
||||||
|
wiphy->hw_version = dev->dev->id.coreid;
|
||||||
|
|
||||||
if (b43_is_old_txhdr_format(dev)) {
|
if (b43_is_old_txhdr_format(dev)) {
|
||||||
/* We're over the deadline, but we keep support for old fw
|
/* We're over the deadline, but we keep support for old fw
|
||||||
* until it turns out to be in major conflict with something new. */
|
* until it turns out to be in major conflict with something new. */
|
||||||
|
@ -3754,17 +3759,17 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
if (key->keylen == WLAN_KEY_LEN_WEP40)
|
algorithm = B43_SEC_ALGO_WEP40;
|
||||||
algorithm = B43_SEC_ALGO_WEP40;
|
|
||||||
else
|
|
||||||
algorithm = B43_SEC_ALGO_WEP104;
|
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
|
algorithm = B43_SEC_ALGO_WEP104;
|
||||||
|
break;
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
algorithm = B43_SEC_ALGO_TKIP;
|
algorithm = B43_SEC_ALGO_TKIP;
|
||||||
break;
|
break;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
algorithm = B43_SEC_ALGO_AES;
|
algorithm = B43_SEC_ALGO_AES;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -4250,6 +4255,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
||||||
B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
|
B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
|
||||||
if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
|
if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Unregister HW RNG driver */
|
||||||
|
b43_rng_exit(dev->wl);
|
||||||
|
|
||||||
b43_set_status(dev, B43_STAT_UNINIT);
|
b43_set_status(dev, B43_STAT_UNINIT);
|
||||||
|
|
||||||
/* Stop the microcode PSM. */
|
/* Stop the microcode PSM. */
|
||||||
|
@ -4379,6 +4388,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
||||||
|
|
||||||
b43_set_status(dev, B43_STAT_INITIALIZED);
|
b43_set_status(dev, B43_STAT_INITIALIZED);
|
||||||
|
|
||||||
|
/* Register HW RNG driver */
|
||||||
|
b43_rng_init(dev->wl);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -4984,7 +4996,6 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
|
||||||
if (err)
|
if (err)
|
||||||
goto err_one_core_detach;
|
goto err_one_core_detach;
|
||||||
b43_leds_register(wl->current_dev);
|
b43_leds_register(wl->current_dev);
|
||||||
b43_rng_init(wl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -5020,7 +5031,6 @@ static void b43_remove(struct ssb_device *dev)
|
||||||
b43_one_core_detach(dev);
|
b43_one_core_detach(dev);
|
||||||
|
|
||||||
if (list_empty(&wl->devlist)) {
|
if (list_empty(&wl->devlist)) {
|
||||||
b43_rng_exit(wl);
|
|
||||||
b43_leds_unregister(wl);
|
b43_leds_unregister(wl);
|
||||||
/* Last core on the chip unregistered.
|
/* Last core on the chip unregistered.
|
||||||
* We can destroy common struct b43_wl.
|
* We can destroy common struct b43_wl.
|
||||||
|
|
|
@ -893,7 +893,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
|
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
|
||||||
static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
|
static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
|
||||||
{
|
{
|
||||||
struct b43_phy_n *nphy = dev->phy.n;
|
struct b43_phy_n *nphy = dev->phy.n;
|
||||||
u8 i, j;
|
u8 i, j;
|
||||||
|
@ -1094,11 +1094,12 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
|
||||||
b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
|
b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
|
||||||
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
|
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
|
||||||
|
|
||||||
b43_nphy_gain_crtl_workarounds(dev);
|
b43_nphy_gain_ctrl_workarounds(dev);
|
||||||
|
|
||||||
if (dev->phy.rev < 2) {
|
if (dev->phy.rev < 2) {
|
||||||
if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
|
if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
|
||||||
; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
|
b43_hf_write(dev, b43_hf_read(dev) |
|
||||||
|
B43_HF_MLADVW);
|
||||||
} else if (dev->phy.rev == 2) {
|
} else if (dev->phy.rev == 2) {
|
||||||
b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
|
b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
|
||||||
b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
|
b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
|
||||||
|
@ -3073,6 +3074,55 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
|
||||||
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
|
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
|
||||||
|
static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
|
||||||
|
{
|
||||||
|
u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
|
||||||
|
if (on)
|
||||||
|
tmslow |= SSB_TMSLOW_PHYCLK;
|
||||||
|
else
|
||||||
|
tmslow &= ~SSB_TMSLOW_PHYCLK;
|
||||||
|
ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
|
||||||
|
static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
|
||||||
|
{
|
||||||
|
struct b43_phy *phy = &dev->phy;
|
||||||
|
struct b43_phy_n *nphy = phy->n;
|
||||||
|
u16 buf[16];
|
||||||
|
|
||||||
|
if (0 /* FIXME clk */)
|
||||||
|
return;
|
||||||
|
|
||||||
|
b43_mac_suspend(dev);
|
||||||
|
|
||||||
|
if (nphy->hang_avoid)
|
||||||
|
b43_nphy_stay_in_carrier_search(dev, true);
|
||||||
|
|
||||||
|
b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
|
||||||
|
(mask & 0x3) << B43_NPHY_RFSEQCA_RXEN_SHIFT);
|
||||||
|
|
||||||
|
if (mask & 0x3 != 0x3) {
|
||||||
|
b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 1);
|
||||||
|
if (dev->phy.rev >= 3) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 0x1E);
|
||||||
|
if (dev->phy.rev >= 3) {
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
|
||||||
|
|
||||||
|
if (nphy->hang_avoid)
|
||||||
|
b43_nphy_stay_in_carrier_search(dev, false);
|
||||||
|
|
||||||
|
b43_mac_enable(dev);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init N-PHY
|
* Init N-PHY
|
||||||
* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
|
* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
|
||||||
|
@ -3173,7 +3223,7 @@ int b43_phy_initn(struct b43_wldev *dev)
|
||||||
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
|
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
|
||||||
b43_nphy_bmac_clock_fgc(dev, 0);
|
b43_nphy_bmac_clock_fgc(dev, 0);
|
||||||
|
|
||||||
/* TODO N PHY MAC PHY Clock Set with argument 1 */
|
b43_nphy_mac_phy_clock_set(dev, true);
|
||||||
|
|
||||||
b43_nphy_pa_override(dev, false);
|
b43_nphy_pa_override(dev, false);
|
||||||
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
|
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
|
||||||
|
@ -3199,7 +3249,7 @@ int b43_phy_initn(struct b43_wldev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nphy->phyrxchain != 3)
|
if (nphy->phyrxchain != 3)
|
||||||
;/* TODO N PHY RX Core Set State with phyrxchain as argument */
|
b43_nphy_set_rx_core_state(dev, nphy->phyrxchain);
|
||||||
if (nphy->mphase_cal_phase_id > 0)
|
if (nphy->mphase_cal_phase_id > 0)
|
||||||
;/* TODO PHY Periodic Calibration Multi-Phase Restart */
|
;/* TODO PHY Periodic Calibration Multi-Phase Restart */
|
||||||
|
|
||||||
|
|
|
@ -1623,6 +1623,7 @@ error:
|
||||||
|
|
||||||
static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
|
static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
|
||||||
{
|
{
|
||||||
|
struct wiphy *wiphy = dev->wl->hw->wiphy;
|
||||||
const size_t hdr_len = sizeof(struct b43legacy_fw_header);
|
const size_t hdr_len = sizeof(struct b43legacy_fw_header);
|
||||||
const __be32 *data;
|
const __be32 *data;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -1732,6 +1733,10 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
|
||||||
dev->fw.rev = fwrev;
|
dev->fw.rev = fwrev;
|
||||||
dev->fw.patch = fwpatch;
|
dev->fw.patch = fwpatch;
|
||||||
|
|
||||||
|
snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
|
||||||
|
dev->fw.rev, dev->fw.patch);
|
||||||
|
wiphy->hw_version = dev->dev->id.coreid;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
|
@ -1696,7 +1696,7 @@ static int prism2_request_scan(struct net_device *dev)
|
||||||
hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
|
hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
|
||||||
HFA384X_ROAMING_FIRMWARE);
|
HFA384X_ROAMING_FIRMWARE);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !PRISM2_NO_STATION_MODES */
|
#else /* !PRISM2_NO_STATION_MODES */
|
||||||
|
|
|
@ -3056,9 +3056,9 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
|
||||||
|
|
||||||
packet = list_entry(element, struct ipw2100_tx_packet, list);
|
packet = list_entry(element, struct ipw2100_tx_packet, list);
|
||||||
|
|
||||||
IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
|
IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
|
||||||
&txq->drv[txq->next],
|
&txq->drv[txq->next],
|
||||||
(void *)(txq->nic + txq->next *
|
(u32) (txq->nic + txq->next *
|
||||||
sizeof(struct ipw2100_bd)));
|
sizeof(struct ipw2100_bd)));
|
||||||
|
|
||||||
packet->index = txq->next;
|
packet->index = txq->next;
|
||||||
|
|
|
@ -3,6 +3,9 @@ config IWLWIFI
|
||||||
depends on PCI && MAC80211
|
depends on PCI && MAC80211
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
|
|
||||||
|
menu "Debugging Options"
|
||||||
|
depends on IWLWIFI
|
||||||
|
|
||||||
config IWLWIFI_DEBUG
|
config IWLWIFI_DEBUG
|
||||||
bool "Enable full debugging output in iwlagn and iwl3945 drivers"
|
bool "Enable full debugging output in iwlagn and iwl3945 drivers"
|
||||||
depends on IWLWIFI
|
depends on IWLWIFI
|
||||||
|
@ -36,6 +39,12 @@ config IWLWIFI_DEBUGFS
|
||||||
is a low-impact option that allows getting insight into the
|
is a low-impact option that allows getting insight into the
|
||||||
driver's state at runtime.
|
driver's state at runtime.
|
||||||
|
|
||||||
|
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||||
|
bool "Experimental uCode support"
|
||||||
|
depends on IWLWIFI && IWLWIFI_DEBUG
|
||||||
|
---help---
|
||||||
|
Enable use of experimental ucode for testing and debugging.
|
||||||
|
|
||||||
config IWLWIFI_DEVICE_TRACING
|
config IWLWIFI_DEVICE_TRACING
|
||||||
bool "iwlwifi device access tracing"
|
bool "iwlwifi device access tracing"
|
||||||
depends on IWLWIFI
|
depends on IWLWIFI
|
||||||
|
@ -53,6 +62,7 @@ config IWLWIFI_DEVICE_TRACING
|
||||||
|
|
||||||
If unsure, say Y so we can help you better when problems
|
If unsure, say Y so we can help you better when problems
|
||||||
occur.
|
occur.
|
||||||
|
endmenu
|
||||||
|
|
||||||
config IWLAGN
|
config IWLAGN
|
||||||
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
|
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
|
||||||
|
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o
|
||||||
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
|
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
|
||||||
iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
|
iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
|
||||||
iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
|
iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
|
||||||
|
iwlagn-objs += iwl-agn-tt.o
|
||||||
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
|
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
|
||||||
|
|
||||||
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
|
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
|
||||||
|
|
|
@ -229,6 +229,11 @@ static struct iwl_lib_ops iwl1000_lib = {
|
||||||
.check_ack_health = iwl_good_ack_health,
|
.check_ack_health = iwl_good_ack_health,
|
||||||
.txfifo_flush = iwlagn_txfifo_flush,
|
.txfifo_flush = iwlagn_txfifo_flush,
|
||||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||||
|
.tt_ops = {
|
||||||
|
.lower_power_detection = iwl_tt_is_low_power_state,
|
||||||
|
.tt_power_mode = iwl_tt_current_power_mode,
|
||||||
|
.ct_kill_check = iwl_check_for_ct_kill,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct iwl_ops iwl1000_ops = {
|
static const struct iwl_ops iwl1000_ops = {
|
||||||
|
|
|
@ -1470,7 +1470,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
|
||||||
|
|
||||||
cmd.band = band;
|
cmd.band = band;
|
||||||
cmd.expect_beacon = 0;
|
cmd.expect_beacon = 0;
|
||||||
ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
|
ch = ch_switch->channel->hw_value;
|
||||||
cmd.channel = cpu_to_le16(ch);
|
cmd.channel = cpu_to_le16(ch);
|
||||||
cmd.rxon_flags = priv->staging_rxon.flags;
|
cmd.rxon_flags = priv->staging_rxon.flags;
|
||||||
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
|
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
|
||||||
|
|
|
@ -291,7 +291,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||||
ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
|
ch = ch_switch->channel->hw_value;
|
||||||
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
|
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
|
||||||
priv->active_rxon.channel, ch);
|
priv->active_rxon.channel, ch);
|
||||||
cmd.channel = cpu_to_le16(ch);
|
cmd.channel = cpu_to_le16(ch);
|
||||||
|
@ -405,6 +405,11 @@ static struct iwl_lib_ops iwl5000_lib = {
|
||||||
.check_ack_health = iwl_good_ack_health,
|
.check_ack_health = iwl_good_ack_health,
|
||||||
.txfifo_flush = iwlagn_txfifo_flush,
|
.txfifo_flush = iwlagn_txfifo_flush,
|
||||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||||
|
.tt_ops = {
|
||||||
|
.lower_power_detection = iwl_tt_is_low_power_state,
|
||||||
|
.tt_power_mode = iwl_tt_current_power_mode,
|
||||||
|
.ct_kill_check = iwl_check_for_ct_kill,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwl_lib_ops iwl5150_lib = {
|
static struct iwl_lib_ops iwl5150_lib = {
|
||||||
|
@ -470,6 +475,11 @@ static struct iwl_lib_ops iwl5150_lib = {
|
||||||
.check_ack_health = iwl_good_ack_health,
|
.check_ack_health = iwl_good_ack_health,
|
||||||
.txfifo_flush = iwlagn_txfifo_flush,
|
.txfifo_flush = iwlagn_txfifo_flush,
|
||||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||||
|
.tt_ops = {
|
||||||
|
.lower_power_detection = iwl_tt_is_low_power_state,
|
||||||
|
.tt_power_mode = iwl_tt_current_power_mode,
|
||||||
|
.ct_kill_check = iwl_check_for_ct_kill,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct iwl_ops iwl5000_ops = {
|
static const struct iwl_ops iwl5000_ops = {
|
||||||
|
|
|
@ -214,7 +214,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
|
||||||
ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
|
ch = ch_switch->channel->hw_value;
|
||||||
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
|
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
|
||||||
priv->active_rxon.channel, ch);
|
priv->active_rxon.channel, ch);
|
||||||
cmd.channel = cpu_to_le16(ch);
|
cmd.channel = cpu_to_le16(ch);
|
||||||
|
@ -330,6 +330,11 @@ static struct iwl_lib_ops iwl6000_lib = {
|
||||||
.check_ack_health = iwl_good_ack_health,
|
.check_ack_health = iwl_good_ack_health,
|
||||||
.txfifo_flush = iwlagn_txfifo_flush,
|
.txfifo_flush = iwlagn_txfifo_flush,
|
||||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||||
|
.tt_ops = {
|
||||||
|
.lower_power_detection = iwl_tt_is_low_power_state,
|
||||||
|
.tt_power_mode = iwl_tt_current_power_mode,
|
||||||
|
.ct_kill_check = iwl_check_for_ct_kill,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct iwl_ops iwl6000_ops = {
|
static const struct iwl_ops iwl6000_ops = {
|
||||||
|
|
|
@ -235,13 +235,13 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
|
||||||
/* data from PHY/DSP regarding signal strength, etc.,
|
/* data from PHY/DSP regarding signal strength, etc.,
|
||||||
* contents are always there, not configurable by host
|
* contents are always there, not configurable by host
|
||||||
*/
|
*/
|
||||||
struct iwl5000_non_cfg_phy *ncphy =
|
struct iwlagn_non_cfg_phy *ncphy =
|
||||||
(struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
|
(struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
|
||||||
u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
|
u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
|
||||||
u8 agc;
|
u8 agc;
|
||||||
|
|
||||||
val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
|
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
|
||||||
agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
|
agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
|
||||||
|
|
||||||
/* Find max rssi among 3 possible receivers.
|
/* Find max rssi among 3 possible receivers.
|
||||||
* These values are measured by the digital signal processor (DSP).
|
* These values are measured by the digital signal processor (DSP).
|
||||||
|
@ -249,11 +249,14 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
|
||||||
* if the radio's automatic gain control (AGC) is working right.
|
* if the radio's automatic gain control (AGC) is working right.
|
||||||
* AGC value (see below) will provide the "interesting" info.
|
* AGC value (see below) will provide the "interesting" info.
|
||||||
*/
|
*/
|
||||||
val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
|
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
|
||||||
rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
|
rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
|
||||||
rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
|
IWLAGN_OFDM_RSSI_A_BIT_POS;
|
||||||
val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
|
rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
|
||||||
rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
|
IWLAGN_OFDM_RSSI_B_BIT_POS;
|
||||||
|
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
|
||||||
|
rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
|
||||||
|
IWLAGN_OFDM_RSSI_C_BIT_POS;
|
||||||
|
|
||||||
max_rssi = max_t(u32, rssi_a, rssi_b);
|
max_rssi = max_t(u32, rssi_a, rssi_b);
|
||||||
max_rssi = max_t(u32, max_rssi, rssi_c);
|
max_rssi = max_t(u32, max_rssi, rssi_c);
|
||||||
|
|
|
@ -1098,7 +1098,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
|
||||||
if (chan->band != band)
|
if (chan->band != band)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channel = ieee80211_frequency_to_channel(chan->center_freq);
|
channel = chan->hw_value;
|
||||||
scan_ch->channel = cpu_to_le16(channel);
|
scan_ch->channel = cpu_to_le16(channel);
|
||||||
|
|
||||||
ch_info = iwl_get_channel_info(priv, band, channel);
|
ch_info = iwl_get_channel_info(priv, band, channel);
|
||||||
|
|
|
@ -82,6 +82,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||||
struct iwl_lq_sta *lq_sta);
|
struct iwl_lq_sta *lq_sta);
|
||||||
static void rs_fill_link_cmd(struct iwl_priv *priv,
|
static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||||
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
|
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
|
||||||
|
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta);
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||||
|
@ -502,6 +503,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
|
||||||
u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
|
u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
|
||||||
u8 mcs;
|
u8 mcs;
|
||||||
|
|
||||||
|
memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
|
||||||
*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
|
*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
|
||||||
|
|
||||||
if (*rate_idx == IWL_RATE_INVALID) {
|
if (*rate_idx == IWL_RATE_INVALID) {
|
||||||
|
@ -848,7 +850,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
||||||
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
|
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
|
||||||
} else {
|
} else {
|
||||||
IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
|
IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
|
||||||
return;
|
tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
|
||||||
|
IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
|
||||||
|
tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
|
||||||
|
tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
|
||||||
|
IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
|
||||||
|
tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
|
||||||
|
IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
|
||||||
|
tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
|
||||||
|
/*
|
||||||
|
* no matching table found, let's by-pass the data collection
|
||||||
|
* and continue to perform rate scale to find the rate table
|
||||||
|
*/
|
||||||
|
rs_stay_in_table(lq_sta);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -909,7 +924,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
||||||
}
|
}
|
||||||
/* The last TX rate is cached in lq_sta; it's set in if/else above */
|
/* The last TX rate is cached in lq_sta; it's set in if/else above */
|
||||||
lq_sta->last_rate_n_flags = tx_rate;
|
lq_sta->last_rate_n_flags = tx_rate;
|
||||||
|
done:
|
||||||
/* See if there's a better rate or modulation mode to try. */
|
/* See if there's a better rate or modulation mode to try. */
|
||||||
if (sta && sta->supp_rates[sband->band])
|
if (sta && sta->supp_rates[sband->band])
|
||||||
rs_rate_scale_perform(priv, skb, sta, lq_sta);
|
rs_rate_scale_perform(priv, skb, sta, lq_sta);
|
||||||
|
@ -1265,7 +1280,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||||
struct iwl_rate_scale_data *window = &(tbl->win[index]);
|
struct iwl_rate_scale_data *window = &(tbl->win[index]);
|
||||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||||
u8 start_action = tbl->action;
|
u8 start_action;
|
||||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1277,6 +1292,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||||
else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
|
else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
|
||||||
tbl->action > IWL_LEGACY_SWITCH_SISO)
|
tbl->action > IWL_LEGACY_SWITCH_SISO)
|
||||||
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
tbl->action = IWL_LEGACY_SWITCH_SISO;
|
||||||
|
start_action = tbl->action;
|
||||||
for (; ;) {
|
for (; ;) {
|
||||||
lq_sta->action_counter++;
|
lq_sta->action_counter++;
|
||||||
switch (tbl->action) {
|
switch (tbl->action) {
|
||||||
|
@ -1403,7 +1419,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
||||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||||
u8 start_action = tbl->action;
|
u8 start_action;
|
||||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||||
u8 update_search_tbl_counter = 0;
|
u8 update_search_tbl_counter = 0;
|
||||||
|
@ -1414,6 +1430,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
|
||||||
/* stay in SISO */
|
/* stay in SISO */
|
||||||
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
|
||||||
}
|
}
|
||||||
|
start_action = tbl->action;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
lq_sta->action_counter++;
|
lq_sta->action_counter++;
|
||||||
switch (tbl->action) {
|
switch (tbl->action) {
|
||||||
|
@ -1541,7 +1558,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
||||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||||
u8 start_action = tbl->action;
|
u8 start_action;
|
||||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||||
u8 update_search_tbl_counter = 0;
|
u8 update_search_tbl_counter = 0;
|
||||||
|
@ -1553,6 +1570,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
|
||||||
/* switch in SISO */
|
/* switch in SISO */
|
||||||
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
|
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
|
||||||
}
|
}
|
||||||
|
start_action = tbl->action;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
lq_sta->action_counter++;
|
lq_sta->action_counter++;
|
||||||
switch (tbl->action) {
|
switch (tbl->action) {
|
||||||
|
@ -1682,7 +1700,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
||||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||||
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
|
||||||
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
|
||||||
u8 start_action = tbl->action;
|
u8 start_action;
|
||||||
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
|
||||||
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
u8 tx_chains_num = priv->hw_params.tx_chains_num;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1694,6 +1712,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
|
||||||
/* switch in SISO */
|
/* switch in SISO */
|
||||||
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
|
tbl->action = IWL_MIMO3_SWITCH_SISO_A;
|
||||||
}
|
}
|
||||||
|
start_action = tbl->action;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
lq_sta->action_counter++;
|
lq_sta->action_counter++;
|
||||||
switch (tbl->action) {
|
switch (tbl->action) {
|
||||||
|
@ -2594,7 +2613,6 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||||
rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
|
rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
|
||||||
|
|
||||||
/* Interpret new_rate (rate_n_flags) */
|
/* Interpret new_rate (rate_n_flags) */
|
||||||
memset(&tbl_type, 0, sizeof(tbl_type));
|
|
||||||
rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
|
rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
|
||||||
&tbl_type, &rate_idx);
|
&tbl_type, &rate_idx);
|
||||||
|
|
||||||
|
@ -2694,8 +2712,18 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||||
|
|
||||||
lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
|
lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
|
||||||
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
|
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||||
|
|
||||||
lq_cmd->agg_params.agg_time_limit =
|
lq_cmd->agg_params.agg_time_limit =
|
||||||
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||||
|
/*
|
||||||
|
* overwrite if needed, pass aggregation time limit
|
||||||
|
* to uCode in uSec
|
||||||
|
*/
|
||||||
|
if (priv && priv->cfg->agg_time_limit &&
|
||||||
|
priv->cfg->agg_time_limit >= LINK_QUAL_AGG_TIME_LIMIT_MIN &&
|
||||||
|
priv->cfg->agg_time_limit <= LINK_QUAL_AGG_TIME_LIMIT_MAX)
|
||||||
|
lq_cmd->agg_params.agg_time_limit =
|
||||||
|
cpu_to_le16(priv->cfg->agg_time_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||||
|
|
696
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
Normal file
696
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
Normal file
|
@ -0,0 +1,696 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Portions of this file are derived from the ipw3945 project, as well
|
||||||
|
* as portions of the ieee80211 subsystem header files.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||||
|
*
|
||||||
|
* The full GNU General Public License is included in this distribution in the
|
||||||
|
* file called LICENSE.
|
||||||
|
*
|
||||||
|
* Contact Information:
|
||||||
|
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||||
|
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
#include <net/mac80211.h>
|
||||||
|
|
||||||
|
#include "iwl-eeprom.h"
|
||||||
|
#include "iwl-dev.h"
|
||||||
|
#include "iwl-core.h"
|
||||||
|
#include "iwl-io.h"
|
||||||
|
#include "iwl-commands.h"
|
||||||
|
#include "iwl-debug.h"
|
||||||
|
#include "iwl-agn-tt.h"
|
||||||
|
|
||||||
|
/* default Thermal Throttling transaction table
|
||||||
|
* Current state | Throttling Down | Throttling Up
|
||||||
|
*=============================================================================
|
||||||
|
* Condition Nxt State Condition Nxt State Condition Nxt State
|
||||||
|
*-----------------------------------------------------------------------------
|
||||||
|
* IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
|
||||||
|
* IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
|
||||||
|
* IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
|
||||||
|
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
|
||||||
|
*=============================================================================
|
||||||
|
*/
|
||||||
|
static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
|
||||||
|
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
|
||||||
|
{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
||||||
|
};
|
||||||
|
static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
|
||||||
|
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
|
||||||
|
{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
||||||
|
};
|
||||||
|
static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
|
||||||
|
{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
||||||
|
};
|
||||||
|
static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
|
||||||
|
{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
|
||||||
|
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Advance Thermal Throttling default restriction table */
|
||||||
|
static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
|
||||||
|
{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
|
||||||
|
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
|
||||||
|
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
|
||||||
|
{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
if (tt->state >= IWL_TI_1)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
return tt->tt_power_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iwl_ht_enabled(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
struct iwl_tt_restriction *restriction;
|
||||||
|
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
return true;
|
||||||
|
restriction = tt->restriction + tt->state;
|
||||||
|
return restriction->is_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
s32 temp = priv->temperature; /* degrees CELSIUS except specified */
|
||||||
|
bool within_margin = false;
|
||||||
|
|
||||||
|
if (priv->cfg->temperature_kelvin)
|
||||||
|
temp = KELVIN_TO_CELSIUS(priv->temperature);
|
||||||
|
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
|
||||||
|
CT_KILL_THRESHOLD_LEGACY) ? true : false;
|
||||||
|
else
|
||||||
|
within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
|
||||||
|
CT_KILL_THRESHOLD) ? true : false;
|
||||||
|
return within_margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iwl_check_for_ct_kill(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
bool is_ct_kill = false;
|
||||||
|
|
||||||
|
if (iwl_within_ct_kill_margin(priv)) {
|
||||||
|
iwl_tt_enter_ct_kill(priv);
|
||||||
|
is_ct_kill = true;
|
||||||
|
}
|
||||||
|
return is_ct_kill;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
struct iwl_tt_restriction *restriction;
|
||||||
|
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
return IWL_ANT_OK_MULTI;
|
||||||
|
restriction = tt->restriction + tt->state;
|
||||||
|
return restriction->tx_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
struct iwl_tt_restriction *restriction;
|
||||||
|
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
return IWL_ANT_OK_MULTI;
|
||||||
|
restriction = tt->restriction + tt->state;
|
||||||
|
return restriction->rx_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
|
||||||
|
#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* toggle the bit to wake up uCode and check the temperature
|
||||||
|
* if the temperature is below CT, uCode will stay awake and send card
|
||||||
|
* state notification with CT_KILL bit clear to inform Thermal Throttling
|
||||||
|
* Management to change state. Otherwise, uCode will go back to sleep
|
||||||
|
* without doing anything, driver should continue the 5 seconds timer
|
||||||
|
* to wake up uCode for temperature check until temperature drop below CT
|
||||||
|
*/
|
||||||
|
static void iwl_tt_check_exit_ct_kill(unsigned long data)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tt->state == IWL_TI_CT_KILL) {
|
||||||
|
if (priv->thermal_throttle.ct_kill_toggle) {
|
||||||
|
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
||||||
|
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||||
|
priv->thermal_throttle.ct_kill_toggle = false;
|
||||||
|
} else {
|
||||||
|
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
||||||
|
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||||
|
priv->thermal_throttle.ct_kill_toggle = true;
|
||||||
|
}
|
||||||
|
iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
||||||
|
spin_lock_irqsave(&priv->reg_lock, flags);
|
||||||
|
if (!iwl_grab_nic_access(priv))
|
||||||
|
iwl_release_nic_access(priv);
|
||||||
|
spin_unlock_irqrestore(&priv->reg_lock, flags);
|
||||||
|
|
||||||
|
/* Reschedule the ct_kill timer to occur in
|
||||||
|
* CT_KILL_EXIT_DURATION seconds to ensure we get a
|
||||||
|
* thermal update */
|
||||||
|
IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
|
||||||
|
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
|
||||||
|
jiffies + CT_KILL_EXIT_DURATION * HZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
||||||
|
bool stop)
|
||||||
|
{
|
||||||
|
if (stop) {
|
||||||
|
IWL_DEBUG_POWER(priv, "Stop all queues\n");
|
||||||
|
if (priv->mac80211_registered)
|
||||||
|
ieee80211_stop_queues(priv->hw);
|
||||||
|
IWL_DEBUG_POWER(priv,
|
||||||
|
"Schedule 5 seconds CT_KILL Timer\n");
|
||||||
|
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
|
||||||
|
jiffies + CT_KILL_EXIT_DURATION * HZ);
|
||||||
|
} else {
|
||||||
|
IWL_DEBUG_POWER(priv, "Wake all queues\n");
|
||||||
|
if (priv->mac80211_registered)
|
||||||
|
ieee80211_wake_queues(priv->hw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iwl_tt_ready_for_ct_kill(unsigned long data)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* temperature timer expired, ready to go into CT_KILL state */
|
||||||
|
if (tt->state != IWL_TI_CT_KILL) {
|
||||||
|
IWL_DEBUG_POWER(priv, "entering CT_KILL state when "
|
||||||
|
"temperature timer expired\n");
|
||||||
|
tt->state = IWL_TI_CT_KILL;
|
||||||
|
set_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
iwl_perform_ct_kill_task(priv, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
|
||||||
|
/* make request to retrieve statistics information */
|
||||||
|
iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
|
/* Reschedule the ct_kill wait timer */
|
||||||
|
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
|
||||||
|
jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
|
||||||
|
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
|
||||||
|
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Legacy thermal throttling
|
||||||
|
* 1) Avoid NIC destruction due to high temperatures
|
||||||
|
* Chip will identify dangerously high temperatures that can
|
||||||
|
* harm the device and will power down
|
||||||
|
* 2) Avoid the NIC power down due to high temperature
|
||||||
|
* Throttle early enough to lower the power consumption before
|
||||||
|
* drastic steps are needed
|
||||||
|
*/
|
||||||
|
static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
enum iwl_tt_state old_state;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
|
if ((tt->tt_previous_temp) &&
|
||||||
|
(temp > tt->tt_previous_temp) &&
|
||||||
|
((temp - tt->tt_previous_temp) >
|
||||||
|
IWL_TT_INCREASE_MARGIN)) {
|
||||||
|
IWL_DEBUG_POWER(priv,
|
||||||
|
"Temperature increase %d degree Celsius\n",
|
||||||
|
(temp - tt->tt_previous_temp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
old_state = tt->state;
|
||||||
|
/* in Celsius */
|
||||||
|
if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
|
||||||
|
tt->state = IWL_TI_CT_KILL;
|
||||||
|
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
|
||||||
|
tt->state = IWL_TI_2;
|
||||||
|
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
|
||||||
|
tt->state = IWL_TI_1;
|
||||||
|
else
|
||||||
|
tt->state = IWL_TI_0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
|
tt->tt_previous_temp = temp;
|
||||||
|
#endif
|
||||||
|
/* stop ct_kill_waiting_tm timer */
|
||||||
|
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
||||||
|
if (tt->state != old_state) {
|
||||||
|
switch (tt->state) {
|
||||||
|
case IWL_TI_0:
|
||||||
|
/*
|
||||||
|
* When the system is ready to go back to IWL_TI_0
|
||||||
|
* we only have to call iwl_power_update_mode() to
|
||||||
|
* do so.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case IWL_TI_1:
|
||||||
|
tt->tt_power_mode = IWL_POWER_INDEX_3;
|
||||||
|
break;
|
||||||
|
case IWL_TI_2:
|
||||||
|
tt->tt_power_mode = IWL_POWER_INDEX_4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
if (old_state == IWL_TI_CT_KILL)
|
||||||
|
clear_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
if (tt->state != IWL_TI_CT_KILL &&
|
||||||
|
iwl_power_update_mode(priv, true)) {
|
||||||
|
/* TT state not updated
|
||||||
|
* try again during next temperature read
|
||||||
|
*/
|
||||||
|
if (old_state == IWL_TI_CT_KILL)
|
||||||
|
set_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
tt->state = old_state;
|
||||||
|
IWL_ERR(priv, "Cannot update power mode, "
|
||||||
|
"TT state not updated\n");
|
||||||
|
} else {
|
||||||
|
if (tt->state == IWL_TI_CT_KILL) {
|
||||||
|
if (force) {
|
||||||
|
set_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
iwl_perform_ct_kill_task(priv, true);
|
||||||
|
} else {
|
||||||
|
iwl_prepare_ct_kill_task(priv);
|
||||||
|
tt->state = old_state;
|
||||||
|
}
|
||||||
|
} else if (old_state == IWL_TI_CT_KILL &&
|
||||||
|
tt->state != IWL_TI_CT_KILL)
|
||||||
|
iwl_perform_ct_kill_task(priv, false);
|
||||||
|
IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
|
||||||
|
tt->state);
|
||||||
|
IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
|
||||||
|
tt->tt_power_mode);
|
||||||
|
}
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advance thermal throttling
|
||||||
|
* 1) Avoid NIC destruction due to high temperatures
|
||||||
|
* Chip will identify dangerously high temperatures that can
|
||||||
|
* harm the device and will power down
|
||||||
|
* 2) Avoid the NIC power down due to high temperature
|
||||||
|
* Throttle early enough to lower the power consumption before
|
||||||
|
* drastic steps are needed
|
||||||
|
* Actions include relaxing the power down sleep thresholds and
|
||||||
|
* decreasing the number of TX streams
|
||||||
|
* 3) Avoid throughput performance impact as much as possible
|
||||||
|
*
|
||||||
|
*=============================================================================
|
||||||
|
* Condition Nxt State Condition Nxt State Condition Nxt State
|
||||||
|
*-----------------------------------------------------------------------------
|
||||||
|
* IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
|
||||||
|
* IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
|
||||||
|
* IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
|
||||||
|
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
|
||||||
|
*=============================================================================
|
||||||
|
*/
|
||||||
|
static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
int i;
|
||||||
|
bool changed = false;
|
||||||
|
enum iwl_tt_state old_state;
|
||||||
|
struct iwl_tt_trans *transaction;
|
||||||
|
|
||||||
|
old_state = tt->state;
|
||||||
|
for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
|
||||||
|
/* based on the current TT state,
|
||||||
|
* find the curresponding transaction table
|
||||||
|
* each table has (IWL_TI_STATE_MAX - 1) entries
|
||||||
|
* tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
|
||||||
|
* will advance to the correct table.
|
||||||
|
* then based on the current temperature
|
||||||
|
* find the next state need to transaction to
|
||||||
|
* go through all the possible (IWL_TI_STATE_MAX - 1) entries
|
||||||
|
* in the current table to see if transaction is needed
|
||||||
|
*/
|
||||||
|
transaction = tt->transaction +
|
||||||
|
((old_state * (IWL_TI_STATE_MAX - 1)) + i);
|
||||||
|
if (temp >= transaction->tt_low &&
|
||||||
|
temp <= transaction->tt_high) {
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
|
if ((tt->tt_previous_temp) &&
|
||||||
|
(temp > tt->tt_previous_temp) &&
|
||||||
|
((temp - tt->tt_previous_temp) >
|
||||||
|
IWL_TT_INCREASE_MARGIN)) {
|
||||||
|
IWL_DEBUG_POWER(priv,
|
||||||
|
"Temperature increase %d "
|
||||||
|
"degree Celsius\n",
|
||||||
|
(temp - tt->tt_previous_temp));
|
||||||
|
}
|
||||||
|
tt->tt_previous_temp = temp;
|
||||||
|
#endif
|
||||||
|
if (old_state !=
|
||||||
|
transaction->next_state) {
|
||||||
|
changed = true;
|
||||||
|
tt->state =
|
||||||
|
transaction->next_state;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* stop ct_kill_waiting_tm timer */
|
||||||
|
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
||||||
|
if (changed) {
|
||||||
|
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
|
||||||
|
|
||||||
|
if (tt->state >= IWL_TI_1) {
|
||||||
|
/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
|
||||||
|
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
||||||
|
if (!iwl_ht_enabled(priv))
|
||||||
|
/* disable HT */
|
||||||
|
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
||||||
|
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
||||||
|
RXON_FLG_HT40_PROT_MSK |
|
||||||
|
RXON_FLG_HT_PROT_MSK);
|
||||||
|
else {
|
||||||
|
/* check HT capability and set
|
||||||
|
* according to the system HT capability
|
||||||
|
* in case get disabled before */
|
||||||
|
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* restore system power setting -- it will be
|
||||||
|
* recalculated automatically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* check HT capability and set
|
||||||
|
* according to the system HT capability
|
||||||
|
* in case get disabled before */
|
||||||
|
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
||||||
|
}
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
if (old_state == IWL_TI_CT_KILL)
|
||||||
|
clear_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
if (tt->state != IWL_TI_CT_KILL &&
|
||||||
|
iwl_power_update_mode(priv, true)) {
|
||||||
|
/* TT state not updated
|
||||||
|
* try again during next temperature read
|
||||||
|
*/
|
||||||
|
IWL_ERR(priv, "Cannot update power mode, "
|
||||||
|
"TT state not updated\n");
|
||||||
|
if (old_state == IWL_TI_CT_KILL)
|
||||||
|
set_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
tt->state = old_state;
|
||||||
|
} else {
|
||||||
|
IWL_DEBUG_POWER(priv,
|
||||||
|
"Thermal Throttling to new state: %u\n",
|
||||||
|
tt->state);
|
||||||
|
if (old_state != IWL_TI_CT_KILL &&
|
||||||
|
tt->state == IWL_TI_CT_KILL) {
|
||||||
|
if (force) {
|
||||||
|
IWL_DEBUG_POWER(priv,
|
||||||
|
"Enter IWL_TI_CT_KILL\n");
|
||||||
|
set_bit(STATUS_CT_KILL, &priv->status);
|
||||||
|
iwl_perform_ct_kill_task(priv, true);
|
||||||
|
} else {
|
||||||
|
iwl_prepare_ct_kill_task(priv);
|
||||||
|
tt->state = old_state;
|
||||||
|
}
|
||||||
|
} else if (old_state == IWL_TI_CT_KILL &&
|
||||||
|
tt->state != IWL_TI_CT_KILL) {
|
||||||
|
IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
|
||||||
|
iwl_perform_ct_kill_task(priv, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card State Notification indicated reach critical temperature
|
||||||
|
* if PSP not enable, no Thermal Throttling function will be performed
|
||||||
|
* just set the GP1 bit to acknowledge the event
|
||||||
|
* otherwise, go into IWL_TI_CT_KILL state
|
||||||
|
* since Card State Notification will not provide any temperature reading
|
||||||
|
* for Legacy mode
|
||||||
|
* so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
|
||||||
|
* for advance mode
|
||||||
|
* pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
|
||||||
|
*/
|
||||||
|
static void iwl_bg_ct_enter(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!iwl_is_ready(priv))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tt->state != IWL_TI_CT_KILL) {
|
||||||
|
IWL_ERR(priv, "Device reached critical temperature "
|
||||||
|
"- ucode going to sleep!\n");
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
iwl_legacy_tt_handler(priv,
|
||||||
|
IWL_MINIMAL_POWER_THRESHOLD,
|
||||||
|
true);
|
||||||
|
else
|
||||||
|
iwl_advance_tt_handler(priv,
|
||||||
|
CT_KILL_THRESHOLD + 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card State Notification indicated out of critical temperature
|
||||||
|
* since Card State Notification will not provide any temperature reading
|
||||||
|
* so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
|
||||||
|
* to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
|
||||||
|
*/
|
||||||
|
static void iwl_bg_ct_exit(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!iwl_is_ready(priv))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* stop ct_kill_exit_tm timer */
|
||||||
|
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||||
|
|
||||||
|
if (tt->state == IWL_TI_CT_KILL) {
|
||||||
|
IWL_ERR(priv,
|
||||||
|
"Device temperature below critical"
|
||||||
|
"- ucode awake!\n");
|
||||||
|
/*
|
||||||
|
* exit from CT_KILL state
|
||||||
|
* reset the current temperature reading
|
||||||
|
*/
|
||||||
|
priv->temperature = 0;
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
iwl_legacy_tt_handler(priv,
|
||||||
|
IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
|
||||||
|
true);
|
||||||
|
else
|
||||||
|
iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
|
||||||
|
queue_work(priv->workqueue, &priv->ct_enter);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
|
||||||
|
|
||||||
|
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
|
||||||
|
queue_work(priv->workqueue, &priv->ct_exit);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
|
||||||
|
|
||||||
|
static void iwl_bg_tt_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
|
||||||
|
s32 temp = priv->temperature; /* degrees CELSIUS except specified */
|
||||||
|
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (priv->cfg->temperature_kelvin)
|
||||||
|
temp = KELVIN_TO_CELSIUS(priv->temperature);
|
||||||
|
|
||||||
|
if (!priv->thermal_throttle.advanced_tt)
|
||||||
|
iwl_legacy_tt_handler(priv, temp, false);
|
||||||
|
else
|
||||||
|
iwl_advance_tt_handler(priv, temp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iwl_tt_handler(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
|
||||||
|
queue_work(priv->workqueue, &priv->tt_work);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_tt_handler);
|
||||||
|
|
||||||
|
/* Thermal throttling initialization
|
||||||
|
* For advance thermal throttling:
|
||||||
|
* Initialize Thermal Index and temperature threshold table
|
||||||
|
* Initialize thermal throttling restriction table
|
||||||
|
*/
|
||||||
|
void iwl_tt_initialize(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
|
||||||
|
struct iwl_tt_trans *transaction;
|
||||||
|
|
||||||
|
IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
|
||||||
|
|
||||||
|
memset(tt, 0, sizeof(struct iwl_tt_mgmt));
|
||||||
|
|
||||||
|
tt->state = IWL_TI_0;
|
||||||
|
init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||||
|
priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
|
||||||
|
priv->thermal_throttle.ct_kill_exit_tm.function =
|
||||||
|
iwl_tt_check_exit_ct_kill;
|
||||||
|
init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
|
||||||
|
priv->thermal_throttle.ct_kill_waiting_tm.data =
|
||||||
|
(unsigned long)priv;
|
||||||
|
priv->thermal_throttle.ct_kill_waiting_tm.function =
|
||||||
|
iwl_tt_ready_for_ct_kill;
|
||||||
|
/* setup deferred ct kill work */
|
||||||
|
INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
|
||||||
|
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
|
||||||
|
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
|
||||||
|
|
||||||
|
if (priv->cfg->adv_thermal_throttle) {
|
||||||
|
IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
|
||||||
|
tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
|
||||||
|
IWL_TI_STATE_MAX, GFP_KERNEL);
|
||||||
|
tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
|
||||||
|
IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!tt->restriction || !tt->transaction) {
|
||||||
|
IWL_ERR(priv, "Fallback to Legacy Throttling\n");
|
||||||
|
priv->thermal_throttle.advanced_tt = false;
|
||||||
|
kfree(tt->restriction);
|
||||||
|
tt->restriction = NULL;
|
||||||
|
kfree(tt->transaction);
|
||||||
|
tt->transaction = NULL;
|
||||||
|
} else {
|
||||||
|
transaction = tt->transaction +
|
||||||
|
(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
|
||||||
|
memcpy(transaction, &tt_range_0[0], size);
|
||||||
|
transaction = tt->transaction +
|
||||||
|
(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
|
||||||
|
memcpy(transaction, &tt_range_1[0], size);
|
||||||
|
transaction = tt->transaction +
|
||||||
|
(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
|
||||||
|
memcpy(transaction, &tt_range_2[0], size);
|
||||||
|
transaction = tt->transaction +
|
||||||
|
(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
|
||||||
|
memcpy(transaction, &tt_range_3[0], size);
|
||||||
|
size = sizeof(struct iwl_tt_restriction) *
|
||||||
|
IWL_TI_STATE_MAX;
|
||||||
|
memcpy(tt->restriction,
|
||||||
|
&restriction_range[0], size);
|
||||||
|
priv->thermal_throttle.advanced_tt = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
|
||||||
|
priv->thermal_throttle.advanced_tt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_tt_initialize);
|
||||||
|
|
||||||
|
/* cleanup thermal throttling management related memory and timer */
|
||||||
|
void iwl_tt_exit(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
||||||
|
|
||||||
|
/* stop ct_kill_exit_tm timer if activated */
|
||||||
|
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
||||||
|
/* stop ct_kill_waiting_tm timer if activated */
|
||||||
|
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
||||||
|
cancel_work_sync(&priv->tt_work);
|
||||||
|
cancel_work_sync(&priv->ct_enter);
|
||||||
|
cancel_work_sync(&priv->ct_exit);
|
||||||
|
|
||||||
|
if (priv->thermal_throttle.advanced_tt) {
|
||||||
|
/* free advance thermal throttling memory */
|
||||||
|
kfree(tt->restriction);
|
||||||
|
tt->restriction = NULL;
|
||||||
|
kfree(tt->transaction);
|
||||||
|
tt->transaction = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_tt_exit);
|
129
drivers/net/wireless/iwlwifi/iwl-agn-tt.h
Normal file
129
drivers/net/wireless/iwlwifi/iwl-agn-tt.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Portions of this file are derived from the ipw3945 project, as well
|
||||||
|
* as portions of the ieee80211 subsystem header files.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||||
|
*
|
||||||
|
* The full GNU General Public License is included in this distribution in the
|
||||||
|
* file called LICENSE.
|
||||||
|
*
|
||||||
|
* Contact Information:
|
||||||
|
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||||
|
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||||
|
*****************************************************************************/
|
||||||
|
#ifndef __iwl_tt_setting_h__
|
||||||
|
#define __iwl_tt_setting_h__
|
||||||
|
|
||||||
|
#include "iwl-commands.h"
|
||||||
|
|
||||||
|
#define IWL_ABSOLUTE_ZERO 0
|
||||||
|
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
|
||||||
|
#define IWL_TT_INCREASE_MARGIN 5
|
||||||
|
#define IWL_TT_CT_KILL_MARGIN 3
|
||||||
|
|
||||||
|
enum iwl_antenna_ok {
|
||||||
|
IWL_ANT_OK_NONE,
|
||||||
|
IWL_ANT_OK_SINGLE,
|
||||||
|
IWL_ANT_OK_MULTI,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Thermal Throttling State Machine states */
|
||||||
|
enum iwl_tt_state {
|
||||||
|
IWL_TI_0, /* normal temperature, system power state */
|
||||||
|
IWL_TI_1, /* high temperature detect, low power state */
|
||||||
|
IWL_TI_2, /* higher temperature detected, lower power state */
|
||||||
|
IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
|
||||||
|
IWL_TI_STATE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_tt_restriction - Thermal Throttling restriction table
|
||||||
|
* @tx_stream: number of tx stream allowed
|
||||||
|
* @is_ht: ht enable/disable
|
||||||
|
* @rx_stream: number of rx stream allowed
|
||||||
|
*
|
||||||
|
* This table is used by advance thermal throttling management
|
||||||
|
* based on the current thermal throttling state, and determines
|
||||||
|
* the number of tx/rx streams and the status of HT operation.
|
||||||
|
*/
|
||||||
|
struct iwl_tt_restriction {
|
||||||
|
enum iwl_antenna_ok tx_stream;
|
||||||
|
enum iwl_antenna_ok rx_stream;
|
||||||
|
bool is_ht;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_tt_trans - Thermal Throttling transaction table
|
||||||
|
* @next_state: next thermal throttling mode
|
||||||
|
* @tt_low: low temperature threshold to change state
|
||||||
|
* @tt_high: high temperature threshold to change state
|
||||||
|
*
|
||||||
|
* This is used by the advanced thermal throttling algorithm
|
||||||
|
* to determine the next thermal state to go based on the
|
||||||
|
* current temperature.
|
||||||
|
*/
|
||||||
|
struct iwl_tt_trans {
|
||||||
|
enum iwl_tt_state next_state;
|
||||||
|
u32 tt_low;
|
||||||
|
u32 tt_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_tt_mgnt - Thermal Throttling Management structure
|
||||||
|
* @advanced_tt: advanced thermal throttle required
|
||||||
|
* @state: current Thermal Throttling state
|
||||||
|
* @tt_power_mode: Thermal Throttling power mode index
|
||||||
|
* being used to set power level when
|
||||||
|
* when thermal throttling state != IWL_TI_0
|
||||||
|
* the tt_power_mode should set to different
|
||||||
|
* power mode based on the current tt state
|
||||||
|
* @tt_previous_temperature: last measured temperature
|
||||||
|
* @iwl_tt_restriction: ptr to restriction tbl, used by advance
|
||||||
|
* thermal throttling to determine how many tx/rx streams
|
||||||
|
* should be used in tt state; and can HT be enabled or not
|
||||||
|
* @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
|
||||||
|
* state transaction
|
||||||
|
* @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
|
||||||
|
* @ct_kill_exit_tm: timer to exit thermal kill
|
||||||
|
*/
|
||||||
|
struct iwl_tt_mgmt {
|
||||||
|
enum iwl_tt_state state;
|
||||||
|
bool advanced_tt;
|
||||||
|
u8 tt_power_mode;
|
||||||
|
bool ct_kill_toggle;
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
|
s32 tt_previous_temp;
|
||||||
|
#endif
|
||||||
|
struct iwl_tt_restriction *restriction;
|
||||||
|
struct iwl_tt_trans *transaction;
|
||||||
|
struct timer_list ct_kill_exit_tm;
|
||||||
|
struct timer_list ct_kill_waiting_tm;
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
|
||||||
|
bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
|
||||||
|
bool iwl_ht_enabled(struct iwl_priv *priv);
|
||||||
|
bool iwl_check_for_ct_kill(struct iwl_priv *priv);
|
||||||
|
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
|
||||||
|
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
|
||||||
|
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
|
||||||
|
void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
|
||||||
|
void iwl_tt_handler(struct iwl_priv *priv);
|
||||||
|
void iwl_tt_initialize(struct iwl_priv *priv);
|
||||||
|
void iwl_tt_exit(struct iwl_priv *priv);
|
||||||
|
|
||||||
|
#endif /* __iwl_tt_setting_h__ */
|
|
@ -470,8 +470,8 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
|
||||||
{
|
{
|
||||||
struct ieee80211_key_conf *keyconf = info->control.hw_key;
|
struct ieee80211_key_conf *keyconf = info->control.hw_key;
|
||||||
|
|
||||||
switch (keyconf->alg) {
|
switch (keyconf->cipher) {
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
|
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
|
||||||
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
|
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
|
||||||
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
if (info->flags & IEEE80211_TX_CTL_AMPDU)
|
||||||
|
@ -479,20 +479,20 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
|
||||||
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
|
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
|
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
|
||||||
ieee80211_get_tkip_key(keyconf, skb_frag,
|
ieee80211_get_tkip_key(keyconf, skb_frag,
|
||||||
IEEE80211_TKIP_P2_KEY, tx_cmd->key);
|
IEEE80211_TKIP_P2_KEY, tx_cmd->key);
|
||||||
IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
|
IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
|
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
|
||||||
|
/* fall through */
|
||||||
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
|
tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
|
||||||
(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
|
(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
|
||||||
|
|
||||||
if (keyconf->keylen == WEP_KEY_LEN_128)
|
|
||||||
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
|
|
||||||
|
|
||||||
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
|
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
|
||||||
|
|
||||||
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
|
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
|
||||||
|
@ -500,7 +500,7 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
|
IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci-aspm.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
@ -763,10 +764,10 @@ static void iwl_bg_ucode_trace(unsigned long data)
|
||||||
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
|
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
|
||||||
struct iwl_rx_mem_buffer *rxb)
|
struct iwl_rx_mem_buffer *rxb)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||||
struct iwl4965_beacon_notif *beacon =
|
struct iwl4965_beacon_notif *beacon =
|
||||||
(struct iwl4965_beacon_notif *)pkt->u.raw;
|
(struct iwl4965_beacon_notif *)pkt->u.raw;
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
|
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
|
||||||
|
|
||||||
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
|
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
|
||||||
|
@ -778,6 +779,8 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
|
||||||
le32_to_cpu(beacon->low_tsf), rate);
|
le32_to_cpu(beacon->low_tsf), rate);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
|
||||||
|
|
||||||
if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
|
if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
|
||||||
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
|
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
|
||||||
queue_work(priv->workqueue, &priv->beacon_update);
|
queue_work(priv->workqueue, &priv->beacon_update);
|
||||||
|
@ -1656,24 +1659,37 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
|
||||||
static int iwl_mac_setup_register(struct iwl_priv *priv,
|
static int iwl_mac_setup_register(struct iwl_priv *priv,
|
||||||
struct iwlagn_ucode_capabilities *capa);
|
struct iwlagn_ucode_capabilities *capa);
|
||||||
|
|
||||||
|
#define UCODE_EXPERIMENTAL_INDEX 100
|
||||||
|
#define UCODE_EXPERIMENTAL_TAG "exp"
|
||||||
|
|
||||||
static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
|
static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
|
||||||
{
|
{
|
||||||
const char *name_pre = priv->cfg->fw_name_pre;
|
const char *name_pre = priv->cfg->fw_name_pre;
|
||||||
|
char tag[8];
|
||||||
|
|
||||||
if (first)
|
if (first) {
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||||
|
priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
|
||||||
|
strcpy(tag, UCODE_EXPERIMENTAL_TAG);
|
||||||
|
} else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
|
||||||
|
#endif
|
||||||
priv->fw_index = priv->cfg->ucode_api_max;
|
priv->fw_index = priv->cfg->ucode_api_max;
|
||||||
else
|
sprintf(tag, "%d", priv->fw_index);
|
||||||
|
} else {
|
||||||
priv->fw_index--;
|
priv->fw_index--;
|
||||||
|
sprintf(tag, "%d", priv->fw_index);
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->fw_index < priv->cfg->ucode_api_min) {
|
if (priv->fw_index < priv->cfg->ucode_api_min) {
|
||||||
IWL_ERR(priv, "no suitable firmware found!\n");
|
IWL_ERR(priv, "no suitable firmware found!\n");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(priv->firmware_name, "%s%d%s",
|
sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
|
||||||
name_pre, priv->fw_index, ".ucode");
|
|
||||||
|
|
||||||
IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n",
|
IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
|
||||||
|
(priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
||||||
|
? "EXPERIMENTAL " : "",
|
||||||
priv->firmware_name);
|
priv->firmware_name);
|
||||||
|
|
||||||
return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
|
return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
|
||||||
|
@ -1968,8 +1984,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
||||||
memset(&pieces, 0, sizeof(pieces));
|
memset(&pieces, 0, sizeof(pieces));
|
||||||
|
|
||||||
if (!ucode_raw) {
|
if (!ucode_raw) {
|
||||||
IWL_ERR(priv, "request for firmware file '%s' failed.\n",
|
if (priv->fw_index <= priv->cfg->ucode_api_max)
|
||||||
priv->firmware_name);
|
IWL_ERR(priv,
|
||||||
|
"request for firmware file '%s' failed.\n",
|
||||||
|
priv->firmware_name);
|
||||||
goto try_again;
|
goto try_again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2016,7 +2034,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
||||||
api_max, api_ver);
|
api_max, api_ver);
|
||||||
|
|
||||||
if (build)
|
if (build)
|
||||||
sprintf(buildstr, " build %u", build);
|
sprintf(buildstr, " build %u%s", build,
|
||||||
|
(priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
|
||||||
|
? " (EXP)" : "");
|
||||||
else
|
else
|
||||||
buildstr[0] = '\0';
|
buildstr[0] = '\0';
|
||||||
|
|
||||||
|
@ -2589,6 +2609,52 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
struct iwl_ct_kill_config cmd;
|
||||||
|
struct iwl_ct_kill_throttling_config adv_cmd;
|
||||||
|
unsigned long flags;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
||||||
|
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
priv->thermal_throttle.ct_kill_toggle = false;
|
||||||
|
|
||||||
|
if (priv->cfg->support_ct_kill_exit) {
|
||||||
|
adv_cmd.critical_temperature_enter =
|
||||||
|
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
||||||
|
adv_cmd.critical_temperature_exit =
|
||||||
|
cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
|
||||||
|
|
||||||
|
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
||||||
|
sizeof(adv_cmd), &adv_cmd);
|
||||||
|
if (ret)
|
||||||
|
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
||||||
|
else
|
||||||
|
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||||
|
"succeeded, "
|
||||||
|
"critical temperature enter is %d,"
|
||||||
|
"exit is %d\n",
|
||||||
|
priv->hw_params.ct_kill_threshold,
|
||||||
|
priv->hw_params.ct_kill_exit_threshold);
|
||||||
|
} else {
|
||||||
|
cmd.critical_temperature_R =
|
||||||
|
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
||||||
|
|
||||||
|
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
||||||
|
sizeof(cmd), &cmd);
|
||||||
|
if (ret)
|
||||||
|
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
||||||
|
else
|
||||||
|
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
||||||
|
"succeeded, "
|
||||||
|
"critical temperature is %d\n",
|
||||||
|
priv->hw_params.ct_kill_threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_alive_start - called after REPLY_ALIVE notification received
|
* iwl_alive_start - called after REPLY_ALIVE notification received
|
||||||
* from protocol/runtime uCode (initialization uCode's
|
* from protocol/runtime uCode (initialization uCode's
|
||||||
|
@ -3060,9 +3126,7 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
|
||||||
iwl_setup_rxon_timing(priv, vif);
|
ret = iwl_send_rxon_timing(priv, vif);
|
||||||
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
|
|
||||||
sizeof(priv->rxon_timing), &priv->rxon_timing);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||||
"Attempting to continue.\n");
|
"Attempting to continue.\n");
|
||||||
|
@ -3298,9 +3362,7 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
|
||||||
/* RXON Timing */
|
/* RXON Timing */
|
||||||
iwl_setup_rxon_timing(priv, vif);
|
ret = iwl_send_rxon_timing(priv, vif);
|
||||||
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
|
|
||||||
sizeof(priv->rxon_timing), &priv->rxon_timing);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||||
"Attempting to continue.\n");
|
"Attempting to continue.\n");
|
||||||
|
@ -3386,7 +3448,9 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
* in 1X mode.
|
* in 1X mode.
|
||||||
* In legacy wep mode, we use another host command to the uCode.
|
* In legacy wep mode, we use another host command to the uCode.
|
||||||
*/
|
*/
|
||||||
if (key->alg == ALG_WEP && !sta && vif->type != NL80211_IFTYPE_AP) {
|
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||||
|
key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
|
||||||
|
!sta) {
|
||||||
if (cmd == SET_KEY)
|
if (cmd == SET_KEY)
|
||||||
is_default_wep_key = !priv->key_mapping_key;
|
is_default_wep_key = !priv->key_mapping_key;
|
||||||
else
|
else
|
||||||
|
@ -3581,6 +3645,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
|
||||||
struct iwl_priv *priv = hw->priv;
|
struct iwl_priv *priv = hw->priv;
|
||||||
const struct iwl_channel_info *ch_info;
|
const struct iwl_channel_info *ch_info;
|
||||||
struct ieee80211_conf *conf = &hw->conf;
|
struct ieee80211_conf *conf = &hw->conf;
|
||||||
|
struct ieee80211_channel *channel = ch_switch->channel;
|
||||||
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
||||||
u16 ch;
|
u16 ch;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
|
@ -3604,11 +3669,10 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
if (priv->cfg->ops->lib->set_channel_switch) {
|
if (priv->cfg->ops->lib->set_channel_switch) {
|
||||||
|
|
||||||
ch = ieee80211_frequency_to_channel(
|
ch = channel->hw_value;
|
||||||
ch_switch->channel->center_freq);
|
|
||||||
if (le16_to_cpu(priv->active_rxon.channel) != ch) {
|
if (le16_to_cpu(priv->active_rxon.channel) != ch) {
|
||||||
ch_info = iwl_get_channel_info(priv,
|
ch_info = iwl_get_channel_info(priv,
|
||||||
conf->channel->band,
|
channel->band,
|
||||||
ch);
|
ch);
|
||||||
if (!is_channel_valid(ch_info)) {
|
if (!is_channel_valid(ch_info)) {
|
||||||
IWL_DEBUG_MAC80211(priv, "invalid channel\n");
|
IWL_DEBUG_MAC80211(priv, "invalid channel\n");
|
||||||
|
@ -3637,15 +3701,12 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
|
||||||
} else
|
} else
|
||||||
ht_conf->is_40mhz = false;
|
ht_conf->is_40mhz = false;
|
||||||
|
|
||||||
/* if we are switching from ht to 2.4 clear flags
|
if (le16_to_cpu(priv->staging_rxon.channel) != ch)
|
||||||
* from any ht related info since 2.4 does not
|
|
||||||
* support ht */
|
|
||||||
if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
|
|
||||||
priv->staging_rxon.flags = 0;
|
priv->staging_rxon.flags = 0;
|
||||||
|
|
||||||
iwl_set_rxon_channel(priv, conf->channel);
|
iwl_set_rxon_channel(priv, channel);
|
||||||
iwl_set_rxon_ht(priv, ht_conf);
|
iwl_set_rxon_ht(priv, ht_conf);
|
||||||
iwl_set_flags_for_band(priv, conf->channel->band,
|
iwl_set_flags_for_band(priv, channel->band,
|
||||||
priv->vif);
|
priv->vif);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
|
@ -3923,8 +3984,35 @@ static struct ieee80211_ops iwl_hw_ops = {
|
||||||
.sta_remove = iwl_mac_sta_remove,
|
.sta_remove = iwl_mac_sta_remove,
|
||||||
.channel_switch = iwl_mac_channel_switch,
|
.channel_switch = iwl_mac_channel_switch,
|
||||||
.flush = iwl_mac_flush,
|
.flush = iwl_mac_flush,
|
||||||
|
.tx_last_beacon = iwl_mac_tx_last_beacon,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void iwl_hw_detect(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
|
||||||
|
priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
|
||||||
|
pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
|
||||||
|
IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iwl_set_hw_params(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
|
||||||
|
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
|
||||||
|
if (priv->cfg->mod_params->amsdu_size_8K)
|
||||||
|
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
|
||||||
|
else
|
||||||
|
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
|
||||||
|
|
||||||
|
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
|
||||||
|
|
||||||
|
if (priv->cfg->mod_params->disable_11n)
|
||||||
|
priv->cfg->sku &= ~IWL_SKU_N;
|
||||||
|
|
||||||
|
/* Device-specific setup */
|
||||||
|
return priv->cfg->ops->lib->set_hw_params(priv);
|
||||||
|
}
|
||||||
|
|
||||||
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -3968,6 +4056,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
/**************************
|
/**************************
|
||||||
* 2. Initializing PCI bus
|
* 2. Initializing PCI bus
|
||||||
**************************/
|
**************************/
|
||||||
|
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
|
||||||
|
PCIE_LINK_STATE_CLKPM);
|
||||||
|
|
||||||
if (pci_enable_device(pdev)) {
|
if (pci_enable_device(pdev)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto out_ieee80211_free_hw;
|
goto out_ieee80211_free_hw;
|
||||||
|
|
|
@ -1367,21 +1367,24 @@ struct iwl4965_rx_non_cfg_phy {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|
||||||
#define IWL50_RX_RES_PHY_CNT 8
|
#define IWLAGN_RX_RES_PHY_CNT 8
|
||||||
#define IWL50_RX_RES_AGC_IDX 1
|
#define IWLAGN_RX_RES_AGC_IDX 1
|
||||||
#define IWL50_RX_RES_RSSI_AB_IDX 2
|
#define IWLAGN_RX_RES_RSSI_AB_IDX 2
|
||||||
#define IWL50_RX_RES_RSSI_C_IDX 3
|
#define IWLAGN_RX_RES_RSSI_C_IDX 3
|
||||||
#define IWL50_OFDM_AGC_MSK 0xfe00
|
#define IWLAGN_OFDM_AGC_MSK 0xfe00
|
||||||
#define IWL50_OFDM_AGC_BIT_POS 9
|
#define IWLAGN_OFDM_AGC_BIT_POS 9
|
||||||
#define IWL50_OFDM_RSSI_A_MSK 0x00ff
|
#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
|
||||||
#define IWL50_OFDM_RSSI_A_BIT_POS 0
|
#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
|
||||||
#define IWL50_OFDM_RSSI_B_MSK 0xff0000
|
#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
|
||||||
#define IWL50_OFDM_RSSI_B_BIT_POS 16
|
#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
|
||||||
#define IWL50_OFDM_RSSI_C_MSK 0x00ff
|
#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
|
||||||
#define IWL50_OFDM_RSSI_C_BIT_POS 0
|
#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
|
||||||
|
#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
|
||||||
|
#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
|
||||||
|
#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
|
||||||
|
|
||||||
struct iwl5000_non_cfg_phy {
|
struct iwlagn_non_cfg_phy {
|
||||||
__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */
|
__le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT]; /* up to 8 phy entries */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1401,7 +1404,7 @@ struct iwl_rx_phy_res {
|
||||||
u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
|
u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
|
||||||
__le32 rate_n_flags; /* RATE_MCS_* */
|
__le32 rate_n_flags; /* RATE_MCS_* */
|
||||||
__le16 byte_count; /* frame's byte-count */
|
__le16 byte_count; /* frame's byte-count */
|
||||||
__le16 reserved3;
|
__le16 frame_time; /* frame's time on the air */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct iwl_rx_mpdu_res_start {
|
struct iwl_rx_mpdu_res_start {
|
||||||
|
@ -2092,8 +2095,8 @@ struct iwl_link_qual_general_params {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
|
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
|
||||||
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535)
|
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
|
||||||
#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0)
|
#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
|
||||||
|
|
||||||
#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
|
#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
|
||||||
#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
|
#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
|
||||||
|
@ -2110,8 +2113,10 @@ struct iwl_link_qual_general_params {
|
||||||
*/
|
*/
|
||||||
struct iwl_link_qual_agg_params {
|
struct iwl_link_qual_agg_params {
|
||||||
|
|
||||||
/* Maximum number of uSec in aggregation.
|
/*
|
||||||
* Driver should set this to 4000 (4 milliseconds). */
|
*Maximum number of uSec in aggregation.
|
||||||
|
* default set to 4000 (4 milliseconds) if not configured in .cfg
|
||||||
|
*/
|
||||||
__le16 agg_time_limit;
|
__le16 agg_time_limit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2919,6 +2924,11 @@ struct iwl_scancomplete_notification {
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
enum iwl_ibss_manager {
|
||||||
|
IWL_NOT_IBSS_MANAGER = 0,
|
||||||
|
IWL_IBSS_MANAGER = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BEACON_NOTIFICATION = 0x90 (notification only, not a command)
|
* BEACON_NOTIFICATION = 0x90 (notification only, not a command)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -183,14 +183,6 @@ out:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_alloc_all);
|
EXPORT_SYMBOL(iwl_alloc_all);
|
||||||
|
|
||||||
void iwl_hw_detect(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
|
|
||||||
priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
|
|
||||||
pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_hw_detect);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* QoS support
|
* QoS support
|
||||||
*/
|
*/
|
||||||
|
@ -247,7 +239,11 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
|
||||||
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
||||||
|
|
||||||
ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
|
ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
|
||||||
|
if (priv->cfg->ampdu_factor)
|
||||||
|
ht_info->ampdu_factor = priv->cfg->ampdu_factor;
|
||||||
ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
|
ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
|
||||||
|
if (priv->cfg->ampdu_density)
|
||||||
|
ht_info->ampdu_density = priv->cfg->ampdu_density;
|
||||||
|
|
||||||
ht_info->mcs.rx_mask[0] = 0xFF;
|
ht_info->mcs.rx_mask[0] = 0xFF;
|
||||||
if (rx_chains_num >= 2)
|
if (rx_chains_num >= 2)
|
||||||
|
@ -499,17 +495,19 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
|
||||||
return new_val;
|
return new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
int iwl_send_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
u64 tsf;
|
u64 tsf;
|
||||||
s32 interval_tm, rem;
|
s32 interval_tm, rem;
|
||||||
unsigned long flags;
|
|
||||||
struct ieee80211_conf *conf = NULL;
|
struct ieee80211_conf *conf = NULL;
|
||||||
u16 beacon_int;
|
u16 beacon_int;
|
||||||
|
|
||||||
conf = ieee80211_get_hw_conf(priv->hw);
|
conf = ieee80211_get_hw_conf(priv->hw);
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
lockdep_assert_held(&priv->mutex);
|
||||||
|
|
||||||
|
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
|
||||||
|
|
||||||
priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
|
priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
|
||||||
priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
|
priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
|
||||||
|
|
||||||
|
@ -532,14 +530,16 @@ void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
rem = do_div(tsf, interval_tm);
|
rem = do_div(tsf, interval_tm);
|
||||||
priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
|
priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
IWL_DEBUG_ASSOC(priv,
|
IWL_DEBUG_ASSOC(priv,
|
||||||
"beacon interval %d beacon timer %d beacon tim %d\n",
|
"beacon interval %d beacon timer %d beacon tim %d\n",
|
||||||
le16_to_cpu(priv->rxon_timing.beacon_interval),
|
le16_to_cpu(priv->rxon_timing.beacon_interval),
|
||||||
le32_to_cpu(priv->rxon_timing.beacon_init_val),
|
le32_to_cpu(priv->rxon_timing.beacon_init_val),
|
||||||
le16_to_cpu(priv->rxon_timing.atim_window));
|
le16_to_cpu(priv->rxon_timing.atim_window));
|
||||||
|
|
||||||
|
return iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
|
||||||
|
sizeof(priv->rxon_timing), &priv->rxon_timing);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_setup_rxon_timing);
|
EXPORT_SYMBOL(iwl_send_rxon_timing);
|
||||||
|
|
||||||
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
|
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
|
||||||
{
|
{
|
||||||
|
@ -912,25 +912,18 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv,
|
||||||
EXPORT_SYMBOL(iwl_get_single_channel_number);
|
EXPORT_SYMBOL(iwl_get_single_channel_number);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
|
* iwl_set_rxon_channel - Set the band and channel values in staging RXON
|
||||||
* @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
|
* @ch: requested channel as a pointer to struct ieee80211_channel
|
||||||
* @channel: Any channel valid for the requested phymode
|
|
||||||
|
|
||||||
* In addition to setting the staging RXON, priv->phymode is also set.
|
* In addition to setting the staging RXON, priv->band is also set.
|
||||||
*
|
*
|
||||||
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
|
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
|
||||||
* in the staging RXON flag structure based on the phymode
|
* in the staging RXON flag structure based on the ch->band
|
||||||
*/
|
*/
|
||||||
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
|
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
|
||||||
{
|
{
|
||||||
enum ieee80211_band band = ch->band;
|
enum ieee80211_band band = ch->band;
|
||||||
u16 channel = ieee80211_frequency_to_channel(ch->center_freq);
|
u16 channel = ch->hw_value;
|
||||||
|
|
||||||
if (!iwl_get_channel_info(priv, band, channel)) {
|
|
||||||
IWL_DEBUG_INFO(priv, "Could not set channel to %d [%d]\n",
|
|
||||||
channel, band);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
|
if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
|
||||||
(priv->band == band))
|
(priv->band == band))
|
||||||
|
@ -1328,25 +1321,6 @@ out:
|
||||||
EXPORT_SYMBOL(iwl_apm_init);
|
EXPORT_SYMBOL(iwl_apm_init);
|
||||||
|
|
||||||
|
|
||||||
int iwl_set_hw_params(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
|
|
||||||
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
|
|
||||||
if (priv->cfg->mod_params->amsdu_size_8K)
|
|
||||||
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
|
|
||||||
else
|
|
||||||
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
|
|
||||||
|
|
||||||
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
|
|
||||||
|
|
||||||
if (priv->cfg->mod_params->disable_11n)
|
|
||||||
priv->cfg->sku &= ~IWL_SKU_N;
|
|
||||||
|
|
||||||
/* Device-specific setup */
|
|
||||||
return priv->cfg->ops->lib->set_hw_params(priv);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_set_hw_params);
|
|
||||||
|
|
||||||
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1496,76 +1470,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_send_statistics_request);
|
EXPORT_SYMBOL(iwl_send_statistics_request);
|
||||||
|
|
||||||
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_ct_kill_config cmd;
|
|
||||||
struct iwl_ct_kill_throttling_config adv_cmd;
|
|
||||||
unsigned long flags;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
|
||||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
priv->thermal_throttle.ct_kill_toggle = false;
|
|
||||||
|
|
||||||
if (priv->cfg->support_ct_kill_exit) {
|
|
||||||
adv_cmd.critical_temperature_enter =
|
|
||||||
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
|
||||||
adv_cmd.critical_temperature_exit =
|
|
||||||
cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
|
|
||||||
|
|
||||||
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
|
||||||
sizeof(adv_cmd), &adv_cmd);
|
|
||||||
if (ret)
|
|
||||||
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
|
||||||
else
|
|
||||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
|
||||||
"succeeded, "
|
|
||||||
"critical temperature enter is %d,"
|
|
||||||
"exit is %d\n",
|
|
||||||
priv->hw_params.ct_kill_threshold,
|
|
||||||
priv->hw_params.ct_kill_exit_threshold);
|
|
||||||
} else {
|
|
||||||
cmd.critical_temperature_R =
|
|
||||||
cpu_to_le32(priv->hw_params.ct_kill_threshold);
|
|
||||||
|
|
||||||
ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
|
|
||||||
sizeof(cmd), &cmd);
|
|
||||||
if (ret)
|
|
||||||
IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
|
|
||||||
else
|
|
||||||
IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
|
|
||||||
"succeeded, "
|
|
||||||
"critical temperature is %d\n",
|
|
||||||
priv->hw_params.ct_kill_threshold);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CARD_STATE_CMD
|
|
||||||
*
|
|
||||||
* Use: Sets the device's internal card state to enable, disable, or halt
|
|
||||||
*
|
|
||||||
* When in the 'enable' state the card operates as normal.
|
|
||||||
* When in the 'disable' state, the card enters into a low power mode.
|
|
||||||
* When in the 'halt' state, the card is shut down and must be fully
|
|
||||||
* restarted to come back on.
|
|
||||||
*/
|
|
||||||
int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
|
|
||||||
{
|
|
||||||
struct iwl_host_cmd cmd = {
|
|
||||||
.id = REPLY_CARD_STATE_CMD,
|
|
||||||
.len = sizeof(u32),
|
|
||||||
.data = &flags,
|
|
||||||
.flags = meta_flag,
|
|
||||||
};
|
|
||||||
|
|
||||||
return iwl_send_cmd(priv, &cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
|
void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
|
||||||
struct iwl_rx_mem_buffer *rxb)
|
struct iwl_rx_mem_buffer *rxb)
|
||||||
{
|
{
|
||||||
|
@ -1648,6 +1552,14 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_mac_conf_tx);
|
EXPORT_SYMBOL(iwl_mac_conf_tx);
|
||||||
|
|
||||||
|
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
|
||||||
|
{
|
||||||
|
struct iwl_priv *priv = hw->priv;
|
||||||
|
|
||||||
|
return priv->ibss_manager == IWL_IBSS_MANAGER;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon);
|
||||||
|
|
||||||
static void iwl_ht_conf(struct iwl_priv *priv,
|
static void iwl_ht_conf(struct iwl_priv *priv,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
|
@ -2014,6 +1926,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
struct iwl_priv *priv = hw->priv;
|
struct iwl_priv *priv = hw->priv;
|
||||||
const struct iwl_channel_info *ch_info;
|
const struct iwl_channel_info *ch_info;
|
||||||
struct ieee80211_conf *conf = &hw->conf;
|
struct ieee80211_conf *conf = &hw->conf;
|
||||||
|
struct ieee80211_channel *channel = conf->channel;
|
||||||
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -2023,7 +1936,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
|
IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
|
||||||
conf->channel->hw_value, changed);
|
channel->hw_value, changed);
|
||||||
|
|
||||||
if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
|
if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
|
||||||
test_bit(STATUS_SCANNING, &priv->status))) {
|
test_bit(STATUS_SCANNING, &priv->status))) {
|
||||||
|
@ -2054,8 +1967,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
if (scan_active)
|
if (scan_active)
|
||||||
goto set_ch_out;
|
goto set_ch_out;
|
||||||
|
|
||||||
ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
|
ch = channel->hw_value;
|
||||||
ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
|
ch_info = iwl_get_channel_info(priv, channel->band, ch);
|
||||||
if (!is_channel_valid(ch_info)) {
|
if (!is_channel_valid(ch_info)) {
|
||||||
IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
|
IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -2086,16 +1999,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
|
||||||
* from BSS config in iwl_ht_conf */
|
* from BSS config in iwl_ht_conf */
|
||||||
ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
|
ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
|
||||||
|
|
||||||
/* if we are switching from ht to 2.4 clear flags
|
|
||||||
* from any ht related info since 2.4 does not
|
|
||||||
* support ht */
|
|
||||||
if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
|
if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
|
||||||
priv->staging_rxon.flags = 0;
|
priv->staging_rxon.flags = 0;
|
||||||
|
|
||||||
iwl_set_rxon_channel(priv, conf->channel);
|
iwl_set_rxon_channel(priv, channel);
|
||||||
iwl_set_rxon_ht(priv, ht_conf);
|
iwl_set_rxon_ht(priv, ht_conf);
|
||||||
|
|
||||||
iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
|
iwl_set_flags_for_band(priv, channel->band, priv->vif);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
if (priv->cfg->ops->lib->update_bcast_station)
|
if (priv->cfg->ops->lib->update_bcast_station)
|
||||||
|
|
|
@ -136,6 +136,12 @@ struct iwl_temp_ops {
|
||||||
void (*set_calib_version)(struct iwl_priv *priv);
|
void (*set_calib_version)(struct iwl_priv *priv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct iwl_tt_ops {
|
||||||
|
bool (*lower_power_detection)(struct iwl_priv *priv);
|
||||||
|
u8 (*tt_power_mode)(struct iwl_priv *priv);
|
||||||
|
bool (*ct_kill_check)(struct iwl_priv *priv);
|
||||||
|
};
|
||||||
|
|
||||||
struct iwl_lib_ops {
|
struct iwl_lib_ops {
|
||||||
/* set hw dependent parameters */
|
/* set hw dependent parameters */
|
||||||
int (*set_hw_params)(struct iwl_priv *priv);
|
int (*set_hw_params)(struct iwl_priv *priv);
|
||||||
|
@ -212,6 +218,9 @@ struct iwl_lib_ops {
|
||||||
void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
|
void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
|
||||||
|
|
||||||
struct iwl_debugfs_ops debugfs_ops;
|
struct iwl_debugfs_ops debugfs_ops;
|
||||||
|
|
||||||
|
/* thermal throttling */
|
||||||
|
struct iwl_tt_ops tt_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_led_ops {
|
struct iwl_led_ops {
|
||||||
|
@ -269,6 +278,11 @@ struct iwl_mod_params {
|
||||||
* @chain_noise_calib_by_driver: driver has the capability to perform
|
* @chain_noise_calib_by_driver: driver has the capability to perform
|
||||||
* chain noise calibration operation
|
* chain noise calibration operation
|
||||||
* @scan_antennas: available antenna for scan operation
|
* @scan_antennas: available antenna for scan operation
|
||||||
|
* @need_dc_calib: need to perform init dc calibration
|
||||||
|
* @bt_statistics: use BT version of statistics notification
|
||||||
|
* @agg_time_limit: maximum number of uSec in aggregation
|
||||||
|
* @ampdu_factor: Maximum A-MPDU length factor
|
||||||
|
* @ampdu_density: Minimum A-MPDU spacing
|
||||||
*
|
*
|
||||||
* We enable the driver to be backward compatible wrt API version. The
|
* We enable the driver to be backward compatible wrt API version. The
|
||||||
* driver specifies which APIs it supports (with @ucode_api_max being the
|
* driver specifies which APIs it supports (with @ucode_api_max being the
|
||||||
|
@ -339,6 +353,9 @@ struct iwl_cfg {
|
||||||
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
|
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
|
||||||
const bool need_dc_calib;
|
const bool need_dc_calib;
|
||||||
const bool bt_statistics;
|
const bool bt_statistics;
|
||||||
|
u16 agg_time_limit;
|
||||||
|
u8 ampdu_factor;
|
||||||
|
u8 ampdu_density;
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
|
@ -347,10 +364,10 @@ struct iwl_cfg {
|
||||||
|
|
||||||
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
|
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
|
||||||
struct ieee80211_ops *hw_ops);
|
struct ieee80211_ops *hw_ops);
|
||||||
void iwl_hw_detect(struct iwl_priv *priv);
|
|
||||||
void iwl_activate_qos(struct iwl_priv *priv);
|
void iwl_activate_qos(struct iwl_priv *priv);
|
||||||
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||||
const struct ieee80211_tx_queue_params *params);
|
const struct ieee80211_tx_queue_params *params);
|
||||||
|
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
|
||||||
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
|
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
|
||||||
int iwl_check_rxon_cmd(struct iwl_priv *priv);
|
int iwl_check_rxon_cmd(struct iwl_priv *priv);
|
||||||
int iwl_full_rxon_required(struct iwl_priv *priv);
|
int iwl_full_rxon_required(struct iwl_priv *priv);
|
||||||
|
@ -372,7 +389,6 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
|
||||||
u32 decrypt_res,
|
u32 decrypt_res,
|
||||||
struct ieee80211_rx_status *stats);
|
struct ieee80211_rx_status *stats);
|
||||||
void iwl_irq_handle_error(struct iwl_priv *priv);
|
void iwl_irq_handle_error(struct iwl_priv *priv);
|
||||||
int iwl_set_hw_params(struct iwl_priv *priv);
|
|
||||||
void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||||
void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
|
@ -527,7 +543,6 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
|
||||||
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
struct cfg80211_scan_request *req);
|
struct cfg80211_scan_request *req);
|
||||||
void iwl_bg_start_internal_scan(struct work_struct *work);
|
|
||||||
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
|
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
|
||||||
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
|
int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
|
||||||
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
|
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
|
||||||
|
@ -539,9 +554,6 @@ u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
|
||||||
u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
|
||||||
enum ieee80211_band band,
|
enum ieee80211_band band,
|
||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
void iwl_bg_scan_check(struct work_struct *data);
|
|
||||||
void iwl_bg_abort_scan(struct work_struct *work);
|
|
||||||
void iwl_bg_scan_completed(struct work_struct *work);
|
|
||||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||||
|
|
||||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||||
|
@ -580,8 +592,6 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
|
||||||
|
|
||||||
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
||||||
|
|
||||||
int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
|
|
||||||
u8 meta_flag);
|
|
||||||
|
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
* PCI *
|
* PCI *
|
||||||
|
@ -695,7 +705,6 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
|
||||||
return iwl_is_ready(priv);
|
return iwl_is_ready(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
|
||||||
extern void iwl_send_bt_config(struct iwl_priv *priv);
|
extern void iwl_send_bt_config(struct iwl_priv *priv);
|
||||||
extern int iwl_send_statistics_request(struct iwl_priv *priv,
|
extern int iwl_send_statistics_request(struct iwl_priv *priv,
|
||||||
u8 flags, bool clear);
|
u8 flags, bool clear);
|
||||||
|
@ -704,7 +713,7 @@ extern int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||||
void iwl_apm_stop(struct iwl_priv *priv);
|
void iwl_apm_stop(struct iwl_priv *priv);
|
||||||
int iwl_apm_init(struct iwl_priv *priv);
|
int iwl_apm_init(struct iwl_priv *priv);
|
||||||
|
|
||||||
void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
int iwl_send_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||||
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
|
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
return priv->cfg->ops->hcmd->rxon_assoc(priv);
|
return priv->cfg->ops->hcmd->rxon_assoc(priv);
|
||||||
|
|
|
@ -467,8 +467,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
|
||||||
for (i = 0; i < supp_band->n_channels; i++)
|
for (i = 0; i < supp_band->n_channels; i++)
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"%d: %ddBm: BSS%s%s, %s.\n",
|
"%d: %ddBm: BSS%s%s, %s.\n",
|
||||||
ieee80211_frequency_to_channel(
|
channels[i].hw_value,
|
||||||
channels[i].center_freq),
|
|
||||||
channels[i].max_power,
|
channels[i].max_power,
|
||||||
channels[i].flags & IEEE80211_CHAN_RADAR ?
|
channels[i].flags & IEEE80211_CHAN_RADAR ?
|
||||||
" (IEEE 802.11h required)" : "",
|
" (IEEE 802.11h required)" : "",
|
||||||
|
@ -491,8 +490,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
|
||||||
for (i = 0; i < supp_band->n_channels; i++)
|
for (i = 0; i < supp_band->n_channels; i++)
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"%d: %ddBm: BSS%s%s, %s.\n",
|
"%d: %ddBm: BSS%s%s, %s.\n",
|
||||||
ieee80211_frequency_to_channel(
|
channels[i].hw_value,
|
||||||
channels[i].center_freq),
|
|
||||||
channels[i].max_power,
|
channels[i].max_power,
|
||||||
channels[i].flags & IEEE80211_CHAN_RADAR ?
|
channels[i].flags & IEEE80211_CHAN_RADAR ?
|
||||||
" (IEEE 802.11h required)" : "",
|
" (IEEE 802.11h required)" : "",
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "iwl-led.h"
|
#include "iwl-led.h"
|
||||||
#include "iwl-power.h"
|
#include "iwl-power.h"
|
||||||
#include "iwl-agn-rs.h"
|
#include "iwl-agn-rs.h"
|
||||||
|
#include "iwl-agn-tt.h"
|
||||||
|
|
||||||
struct iwl_tx_queue;
|
struct iwl_tx_queue;
|
||||||
|
|
||||||
|
@ -420,7 +421,7 @@ struct iwl_tid_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_hw_key {
|
struct iwl_hw_key {
|
||||||
enum ieee80211_key_alg alg;
|
u32 cipher;
|
||||||
int keylen;
|
int keylen;
|
||||||
u8 keyidx;
|
u8 keyidx;
|
||||||
u8 key[32];
|
u8 key[32];
|
||||||
|
@ -434,7 +435,13 @@ union iwl_ht_rate_supp {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
|
#define CFG_HT_RX_AMPDU_FACTOR_8K (0x0)
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_16K (0x1)
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_32K (0x2)
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_64K (0x3)
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_DEF CFG_HT_RX_AMPDU_FACTOR_64K
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_MAX CFG_HT_RX_AMPDU_FACTOR_64K
|
||||||
|
#define CFG_HT_RX_AMPDU_FACTOR_MIN CFG_HT_RX_AMPDU_FACTOR_8K
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximal MPDU density for TX aggregation
|
* Maximal MPDU density for TX aggregation
|
||||||
|
@ -443,8 +450,13 @@ union iwl_ht_rate_supp {
|
||||||
* 6 - 8us density
|
* 6 - 8us density
|
||||||
* 7 - 16us density
|
* 7 - 16us density
|
||||||
*/
|
*/
|
||||||
|
#define CFG_HT_MPDU_DENSITY_2USEC (0x4)
|
||||||
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
|
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
|
||||||
|
#define CFG_HT_MPDU_DENSITY_8USEC (0x6)
|
||||||
|
#define CFG_HT_MPDU_DENSITY_16USEC (0x7)
|
||||||
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
|
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
|
||||||
|
#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
|
||||||
|
#define CFG_HT_MPDU_DENSITY_MIN (0x1)
|
||||||
|
|
||||||
struct iwl_ht_config {
|
struct iwl_ht_config {
|
||||||
/* self configuration data */
|
/* self configuration data */
|
||||||
|
@ -1052,7 +1064,6 @@ struct iwl_event_log {
|
||||||
#define IWL_DEF_MONITORING_PERIOD (1000)
|
#define IWL_DEF_MONITORING_PERIOD (1000)
|
||||||
#define IWL_LONG_MONITORING_PERIOD (5000)
|
#define IWL_LONG_MONITORING_PERIOD (5000)
|
||||||
#define IWL_ONE_HUNDRED_MSECS (100)
|
#define IWL_ONE_HUNDRED_MSECS (100)
|
||||||
#define IWL_SIXTY_SECS (60000)
|
|
||||||
|
|
||||||
enum iwl_reset {
|
enum iwl_reset {
|
||||||
IWL_RF_RESET = 0,
|
IWL_RF_RESET = 0,
|
||||||
|
@ -1110,6 +1121,9 @@ struct iwl_priv {
|
||||||
u32 ucode_beacon_time;
|
u32 ucode_beacon_time;
|
||||||
int missed_beacon_threshold;
|
int missed_beacon_threshold;
|
||||||
|
|
||||||
|
/* track IBSS manager (last beacon) status */
|
||||||
|
u32 ibss_manager;
|
||||||
|
|
||||||
/* storing the jiffies when the plcp error rate is received */
|
/* storing the jiffies when the plcp error rate is received */
|
||||||
unsigned long plcp_jiffies;
|
unsigned long plcp_jiffies;
|
||||||
|
|
||||||
|
|
|
@ -192,47 +192,6 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
|
||||||
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
|
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default Thermal Throttling transaction table
|
|
||||||
* Current state | Throttling Down | Throttling Up
|
|
||||||
*=============================================================================
|
|
||||||
* Condition Nxt State Condition Nxt State Condition Nxt State
|
|
||||||
*-----------------------------------------------------------------------------
|
|
||||||
* IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
|
|
||||||
* IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
|
|
||||||
* IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
|
|
||||||
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
|
|
||||||
*=============================================================================
|
|
||||||
*/
|
|
||||||
static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
|
|
||||||
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
|
|
||||||
{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
|
||||||
};
|
|
||||||
static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
|
|
||||||
{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
|
|
||||||
{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
|
||||||
};
|
|
||||||
static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
|
|
||||||
{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
|
|
||||||
};
|
|
||||||
static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
|
|
||||||
{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
|
|
||||||
{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Advance Thermal Throttling default restriction table */
|
|
||||||
static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
|
|
||||||
{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
|
|
||||||
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
|
|
||||||
{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
|
|
||||||
{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
|
static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
|
||||||
struct iwl_powertable_cmd *cmd)
|
struct iwl_powertable_cmd *cmd)
|
||||||
{
|
{
|
||||||
|
@ -308,7 +267,6 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
|
||||||
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
|
bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
|
||||||
bool update_chains;
|
bool update_chains;
|
||||||
struct iwl_powertable_cmd cmd;
|
struct iwl_powertable_cmd cmd;
|
||||||
|
@ -325,9 +283,13 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
||||||
else if (priv->cfg->supports_idle &&
|
else if (priv->cfg->supports_idle &&
|
||||||
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
|
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
|
||||||
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
|
iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
|
||||||
else if (tt->state >= IWL_TI_1)
|
else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
|
||||||
iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
|
priv->cfg->ops->lib->tt_ops.tt_power_mode &&
|
||||||
else if (!enabled)
|
priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
|
||||||
|
/* in thermal throttling low power state */
|
||||||
|
iwl_static_sleep_cmd(priv, &cmd,
|
||||||
|
priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
|
||||||
|
} else if (!enabled)
|
||||||
iwl_power_sleep_cam_cmd(priv, &cmd);
|
iwl_power_sleep_cam_cmd(priv, &cmd);
|
||||||
else if (priv->power_data.debug_sleep_level_override >= 0)
|
else if (priv->power_data.debug_sleep_level_override >= 0)
|
||||||
iwl_static_sleep_cmd(priv, &cmd,
|
iwl_static_sleep_cmd(priv, &cmd,
|
||||||
|
@ -367,592 +329,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_power_update_mode);
|
EXPORT_SYMBOL(iwl_power_update_mode);
|
||||||
|
|
||||||
bool iwl_ht_enabled(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
struct iwl_tt_restriction *restriction;
|
|
||||||
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
return true;
|
|
||||||
restriction = tt->restriction + tt->state;
|
|
||||||
return restriction->is_ht;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_ht_enabled);
|
|
||||||
|
|
||||||
bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
s32 temp = priv->temperature; /* degrees CELSIUS except specified */
|
|
||||||
bool within_margin = false;
|
|
||||||
|
|
||||||
if (priv->cfg->temperature_kelvin)
|
|
||||||
temp = KELVIN_TO_CELSIUS(priv->temperature);
|
|
||||||
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
|
|
||||||
CT_KILL_THRESHOLD_LEGACY) ? true : false;
|
|
||||||
else
|
|
||||||
within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
|
|
||||||
CT_KILL_THRESHOLD) ? true : false;
|
|
||||||
return within_margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
struct iwl_tt_restriction *restriction;
|
|
||||||
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
return IWL_ANT_OK_MULTI;
|
|
||||||
restriction = tt->restriction + tt->state;
|
|
||||||
return restriction->tx_stream;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tx_ant_restriction);
|
|
||||||
|
|
||||||
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
struct iwl_tt_restriction *restriction;
|
|
||||||
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
return IWL_ANT_OK_MULTI;
|
|
||||||
restriction = tt->restriction + tt->state;
|
|
||||||
return restriction->rx_stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */
|
|
||||||
#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* toggle the bit to wake up uCode and check the temperature
|
|
||||||
* if the temperature is below CT, uCode will stay awake and send card
|
|
||||||
* state notification with CT_KILL bit clear to inform Thermal Throttling
|
|
||||||
* Management to change state. Otherwise, uCode will go back to sleep
|
|
||||||
* without doing anything, driver should continue the 5 seconds timer
|
|
||||||
* to wake up uCode for temperature check until temperature drop below CT
|
|
||||||
*/
|
|
||||||
static void iwl_tt_check_exit_ct_kill(unsigned long data)
|
|
||||||
{
|
|
||||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tt->state == IWL_TI_CT_KILL) {
|
|
||||||
if (priv->thermal_throttle.ct_kill_toggle) {
|
|
||||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
|
|
||||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
|
||||||
priv->thermal_throttle.ct_kill_toggle = false;
|
|
||||||
} else {
|
|
||||||
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
|
|
||||||
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
|
|
||||||
priv->thermal_throttle.ct_kill_toggle = true;
|
|
||||||
}
|
|
||||||
iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
|
||||||
spin_lock_irqsave(&priv->reg_lock, flags);
|
|
||||||
if (!iwl_grab_nic_access(priv))
|
|
||||||
iwl_release_nic_access(priv);
|
|
||||||
spin_unlock_irqrestore(&priv->reg_lock, flags);
|
|
||||||
|
|
||||||
/* Reschedule the ct_kill timer to occur in
|
|
||||||
* CT_KILL_EXIT_DURATION seconds to ensure we get a
|
|
||||||
* thermal update */
|
|
||||||
IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
|
|
||||||
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
|
|
||||||
CT_KILL_EXIT_DURATION * HZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
|
|
||||||
bool stop)
|
|
||||||
{
|
|
||||||
if (stop) {
|
|
||||||
IWL_DEBUG_POWER(priv, "Stop all queues\n");
|
|
||||||
if (priv->mac80211_registered)
|
|
||||||
ieee80211_stop_queues(priv->hw);
|
|
||||||
IWL_DEBUG_POWER(priv,
|
|
||||||
"Schedule 5 seconds CT_KILL Timer\n");
|
|
||||||
mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
|
|
||||||
CT_KILL_EXIT_DURATION * HZ);
|
|
||||||
} else {
|
|
||||||
IWL_DEBUG_POWER(priv, "Wake all queues\n");
|
|
||||||
if (priv->mac80211_registered)
|
|
||||||
ieee80211_wake_queues(priv->hw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iwl_tt_ready_for_ct_kill(unsigned long data)
|
|
||||||
{
|
|
||||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* temperature timer expired, ready to go into CT_KILL state */
|
|
||||||
if (tt->state != IWL_TI_CT_KILL) {
|
|
||||||
IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
|
|
||||||
tt->state = IWL_TI_CT_KILL;
|
|
||||||
set_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
iwl_perform_ct_kill_task(priv, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
|
|
||||||
/* make request to retrieve statistics information */
|
|
||||||
iwl_send_statistics_request(priv, CMD_SYNC, false);
|
|
||||||
/* Reschedule the ct_kill wait timer */
|
|
||||||
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
|
|
||||||
jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY)
|
|
||||||
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100)
|
|
||||||
#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Legacy thermal throttling
|
|
||||||
* 1) Avoid NIC destruction due to high temperatures
|
|
||||||
* Chip will identify dangerously high temperatures that can
|
|
||||||
* harm the device and will power down
|
|
||||||
* 2) Avoid the NIC power down due to high temperature
|
|
||||||
* Throttle early enough to lower the power consumption before
|
|
||||||
* drastic steps are needed
|
|
||||||
*/
|
|
||||||
static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
enum iwl_tt_state old_state;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
if ((tt->tt_previous_temp) &&
|
|
||||||
(temp > tt->tt_previous_temp) &&
|
|
||||||
((temp - tt->tt_previous_temp) >
|
|
||||||
IWL_TT_INCREASE_MARGIN)) {
|
|
||||||
IWL_DEBUG_POWER(priv,
|
|
||||||
"Temperature increase %d degree Celsius\n",
|
|
||||||
(temp - tt->tt_previous_temp));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
old_state = tt->state;
|
|
||||||
/* in Celsius */
|
|
||||||
if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
|
|
||||||
tt->state = IWL_TI_CT_KILL;
|
|
||||||
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
|
|
||||||
tt->state = IWL_TI_2;
|
|
||||||
else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
|
|
||||||
tt->state = IWL_TI_1;
|
|
||||||
else
|
|
||||||
tt->state = IWL_TI_0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
tt->tt_previous_temp = temp;
|
|
||||||
#endif
|
|
||||||
/* stop ct_kill_waiting_tm timer */
|
|
||||||
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
|
||||||
if (tt->state != old_state) {
|
|
||||||
switch (tt->state) {
|
|
||||||
case IWL_TI_0:
|
|
||||||
/*
|
|
||||||
* When the system is ready to go back to IWL_TI_0
|
|
||||||
* we only have to call iwl_power_update_mode() to
|
|
||||||
* do so.
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
case IWL_TI_1:
|
|
||||||
tt->tt_power_mode = IWL_POWER_INDEX_3;
|
|
||||||
break;
|
|
||||||
case IWL_TI_2:
|
|
||||||
tt->tt_power_mode = IWL_POWER_INDEX_4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mutex_lock(&priv->mutex);
|
|
||||||
if (old_state == IWL_TI_CT_KILL)
|
|
||||||
clear_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
if (tt->state != IWL_TI_CT_KILL &&
|
|
||||||
iwl_power_update_mode(priv, true)) {
|
|
||||||
/* TT state not updated
|
|
||||||
* try again during next temperature read
|
|
||||||
*/
|
|
||||||
if (old_state == IWL_TI_CT_KILL)
|
|
||||||
set_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
tt->state = old_state;
|
|
||||||
IWL_ERR(priv, "Cannot update power mode, "
|
|
||||||
"TT state not updated\n");
|
|
||||||
} else {
|
|
||||||
if (tt->state == IWL_TI_CT_KILL) {
|
|
||||||
if (force) {
|
|
||||||
set_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
iwl_perform_ct_kill_task(priv, true);
|
|
||||||
} else {
|
|
||||||
iwl_prepare_ct_kill_task(priv);
|
|
||||||
tt->state = old_state;
|
|
||||||
}
|
|
||||||
} else if (old_state == IWL_TI_CT_KILL &&
|
|
||||||
tt->state != IWL_TI_CT_KILL)
|
|
||||||
iwl_perform_ct_kill_task(priv, false);
|
|
||||||
IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
|
|
||||||
tt->state);
|
|
||||||
IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
|
|
||||||
tt->tt_power_mode);
|
|
||||||
}
|
|
||||||
mutex_unlock(&priv->mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance thermal throttling
|
|
||||||
* 1) Avoid NIC destruction due to high temperatures
|
|
||||||
* Chip will identify dangerously high temperatures that can
|
|
||||||
* harm the device and will power down
|
|
||||||
* 2) Avoid the NIC power down due to high temperature
|
|
||||||
* Throttle early enough to lower the power consumption before
|
|
||||||
* drastic steps are needed
|
|
||||||
* Actions include relaxing the power down sleep thresholds and
|
|
||||||
* decreasing the number of TX streams
|
|
||||||
* 3) Avoid throughput performance impact as much as possible
|
|
||||||
*
|
|
||||||
*=============================================================================
|
|
||||||
* Condition Nxt State Condition Nxt State Condition Nxt State
|
|
||||||
*-----------------------------------------------------------------------------
|
|
||||||
* IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A
|
|
||||||
* IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0
|
|
||||||
* IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1
|
|
||||||
* IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0
|
|
||||||
*=============================================================================
|
|
||||||
*/
|
|
||||||
static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
int i;
|
|
||||||
bool changed = false;
|
|
||||||
enum iwl_tt_state old_state;
|
|
||||||
struct iwl_tt_trans *transaction;
|
|
||||||
|
|
||||||
old_state = tt->state;
|
|
||||||
for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
|
|
||||||
/* based on the current TT state,
|
|
||||||
* find the curresponding transaction table
|
|
||||||
* each table has (IWL_TI_STATE_MAX - 1) entries
|
|
||||||
* tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
|
|
||||||
* will advance to the correct table.
|
|
||||||
* then based on the current temperature
|
|
||||||
* find the next state need to transaction to
|
|
||||||
* go through all the possible (IWL_TI_STATE_MAX - 1) entries
|
|
||||||
* in the current table to see if transaction is needed
|
|
||||||
*/
|
|
||||||
transaction = tt->transaction +
|
|
||||||
((old_state * (IWL_TI_STATE_MAX - 1)) + i);
|
|
||||||
if (temp >= transaction->tt_low &&
|
|
||||||
temp <= transaction->tt_high) {
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
if ((tt->tt_previous_temp) &&
|
|
||||||
(temp > tt->tt_previous_temp) &&
|
|
||||||
((temp - tt->tt_previous_temp) >
|
|
||||||
IWL_TT_INCREASE_MARGIN)) {
|
|
||||||
IWL_DEBUG_POWER(priv,
|
|
||||||
"Temperature increase %d "
|
|
||||||
"degree Celsius\n",
|
|
||||||
(temp - tt->tt_previous_temp));
|
|
||||||
}
|
|
||||||
tt->tt_previous_temp = temp;
|
|
||||||
#endif
|
|
||||||
if (old_state !=
|
|
||||||
transaction->next_state) {
|
|
||||||
changed = true;
|
|
||||||
tt->state =
|
|
||||||
transaction->next_state;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* stop ct_kill_waiting_tm timer */
|
|
||||||
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
|
||||||
if (changed) {
|
|
||||||
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
|
|
||||||
|
|
||||||
if (tt->state >= IWL_TI_1) {
|
|
||||||
/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
|
|
||||||
tt->tt_power_mode = IWL_POWER_INDEX_5;
|
|
||||||
if (!iwl_ht_enabled(priv))
|
|
||||||
/* disable HT */
|
|
||||||
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
|
|
||||||
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
|
|
||||||
RXON_FLG_HT40_PROT_MSK |
|
|
||||||
RXON_FLG_HT_PROT_MSK);
|
|
||||||
else {
|
|
||||||
/* check HT capability and set
|
|
||||||
* according to the system HT capability
|
|
||||||
* in case get disabled before */
|
|
||||||
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* restore system power setting -- it will be
|
|
||||||
* recalculated automatically.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* check HT capability and set
|
|
||||||
* according to the system HT capability
|
|
||||||
* in case get disabled before */
|
|
||||||
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
|
||||||
}
|
|
||||||
mutex_lock(&priv->mutex);
|
|
||||||
if (old_state == IWL_TI_CT_KILL)
|
|
||||||
clear_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
if (tt->state != IWL_TI_CT_KILL &&
|
|
||||||
iwl_power_update_mode(priv, true)) {
|
|
||||||
/* TT state not updated
|
|
||||||
* try again during next temperature read
|
|
||||||
*/
|
|
||||||
IWL_ERR(priv, "Cannot update power mode, "
|
|
||||||
"TT state not updated\n");
|
|
||||||
if (old_state == IWL_TI_CT_KILL)
|
|
||||||
set_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
tt->state = old_state;
|
|
||||||
} else {
|
|
||||||
IWL_DEBUG_POWER(priv,
|
|
||||||
"Thermal Throttling to new state: %u\n",
|
|
||||||
tt->state);
|
|
||||||
if (old_state != IWL_TI_CT_KILL &&
|
|
||||||
tt->state == IWL_TI_CT_KILL) {
|
|
||||||
if (force) {
|
|
||||||
IWL_DEBUG_POWER(priv,
|
|
||||||
"Enter IWL_TI_CT_KILL\n");
|
|
||||||
set_bit(STATUS_CT_KILL, &priv->status);
|
|
||||||
iwl_perform_ct_kill_task(priv, true);
|
|
||||||
} else {
|
|
||||||
iwl_prepare_ct_kill_task(priv);
|
|
||||||
tt->state = old_state;
|
|
||||||
}
|
|
||||||
} else if (old_state == IWL_TI_CT_KILL &&
|
|
||||||
tt->state != IWL_TI_CT_KILL) {
|
|
||||||
IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
|
|
||||||
iwl_perform_ct_kill_task(priv, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&priv->mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Card State Notification indicated reach critical temperature
|
|
||||||
* if PSP not enable, no Thermal Throttling function will be performed
|
|
||||||
* just set the GP1 bit to acknowledge the event
|
|
||||||
* otherwise, go into IWL_TI_CT_KILL state
|
|
||||||
* since Card State Notification will not provide any temperature reading
|
|
||||||
* for Legacy mode
|
|
||||||
* so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
|
|
||||||
* for advance mode
|
|
||||||
* pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
|
|
||||||
*/
|
|
||||||
static void iwl_bg_ct_enter(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!iwl_is_ready(priv))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tt->state != IWL_TI_CT_KILL) {
|
|
||||||
IWL_ERR(priv, "Device reached critical temperature "
|
|
||||||
"- ucode going to sleep!\n");
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
iwl_legacy_tt_handler(priv,
|
|
||||||
IWL_MINIMAL_POWER_THRESHOLD,
|
|
||||||
true);
|
|
||||||
else
|
|
||||||
iwl_advance_tt_handler(priv,
|
|
||||||
CT_KILL_THRESHOLD + 1, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Card State Notification indicated out of critical temperature
|
|
||||||
* since Card State Notification will not provide any temperature reading
|
|
||||||
* so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
|
|
||||||
* to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
|
|
||||||
*/
|
|
||||||
static void iwl_bg_ct_exit(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!iwl_is_ready(priv))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* stop ct_kill_exit_tm timer */
|
|
||||||
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
|
||||||
|
|
||||||
if (tt->state == IWL_TI_CT_KILL) {
|
|
||||||
IWL_ERR(priv,
|
|
||||||
"Device temperature below critical"
|
|
||||||
"- ucode awake!\n");
|
|
||||||
/*
|
|
||||||
* exit from CT_KILL state
|
|
||||||
* reset the current temperature reading
|
|
||||||
*/
|
|
||||||
priv->temperature = 0;
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
iwl_legacy_tt_handler(priv,
|
|
||||||
IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
|
|
||||||
true);
|
|
||||||
else
|
|
||||||
iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
|
|
||||||
queue_work(priv->workqueue, &priv->ct_enter);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
|
|
||||||
|
|
||||||
void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
|
|
||||||
queue_work(priv->workqueue, &priv->ct_exit);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
|
|
||||||
|
|
||||||
static void iwl_bg_tt_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
|
|
||||||
s32 temp = priv->temperature; /* degrees CELSIUS except specified */
|
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (priv->cfg->temperature_kelvin)
|
|
||||||
temp = KELVIN_TO_CELSIUS(priv->temperature);
|
|
||||||
|
|
||||||
if (!priv->thermal_throttle.advanced_tt)
|
|
||||||
iwl_legacy_tt_handler(priv, temp, false);
|
|
||||||
else
|
|
||||||
iwl_advance_tt_handler(priv, temp, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void iwl_tt_handler(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
|
|
||||||
queue_work(priv->workqueue, &priv->tt_work);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tt_handler);
|
|
||||||
|
|
||||||
/* Thermal throttling initialization
|
|
||||||
* For advance thermal throttling:
|
|
||||||
* Initialize Thermal Index and temperature threshold table
|
|
||||||
* Initialize thermal throttling restriction table
|
|
||||||
*/
|
|
||||||
void iwl_tt_initialize(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
|
|
||||||
struct iwl_tt_trans *transaction;
|
|
||||||
|
|
||||||
IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
|
|
||||||
|
|
||||||
memset(tt, 0, sizeof(struct iwl_tt_mgmt));
|
|
||||||
|
|
||||||
tt->state = IWL_TI_0;
|
|
||||||
init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
|
|
||||||
priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
|
|
||||||
priv->thermal_throttle.ct_kill_exit_tm.function =
|
|
||||||
iwl_tt_check_exit_ct_kill;
|
|
||||||
init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
|
|
||||||
priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
|
|
||||||
priv->thermal_throttle.ct_kill_waiting_tm.function =
|
|
||||||
iwl_tt_ready_for_ct_kill;
|
|
||||||
/* setup deferred ct kill work */
|
|
||||||
INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
|
|
||||||
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
|
|
||||||
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
|
|
||||||
|
|
||||||
if (priv->cfg->adv_thermal_throttle) {
|
|
||||||
IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
|
|
||||||
tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
|
|
||||||
IWL_TI_STATE_MAX, GFP_KERNEL);
|
|
||||||
tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
|
|
||||||
IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!tt->restriction || !tt->transaction) {
|
|
||||||
IWL_ERR(priv, "Fallback to Legacy Throttling\n");
|
|
||||||
priv->thermal_throttle.advanced_tt = false;
|
|
||||||
kfree(tt->restriction);
|
|
||||||
tt->restriction = NULL;
|
|
||||||
kfree(tt->transaction);
|
|
||||||
tt->transaction = NULL;
|
|
||||||
} else {
|
|
||||||
transaction = tt->transaction +
|
|
||||||
(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
|
|
||||||
memcpy(transaction, &tt_range_0[0], size);
|
|
||||||
transaction = tt->transaction +
|
|
||||||
(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
|
|
||||||
memcpy(transaction, &tt_range_1[0], size);
|
|
||||||
transaction = tt->transaction +
|
|
||||||
(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
|
|
||||||
memcpy(transaction, &tt_range_2[0], size);
|
|
||||||
transaction = tt->transaction +
|
|
||||||
(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
|
|
||||||
memcpy(transaction, &tt_range_3[0], size);
|
|
||||||
size = sizeof(struct iwl_tt_restriction) *
|
|
||||||
IWL_TI_STATE_MAX;
|
|
||||||
memcpy(tt->restriction,
|
|
||||||
&restriction_range[0], size);
|
|
||||||
priv->thermal_throttle.advanced_tt = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
|
|
||||||
priv->thermal_throttle.advanced_tt = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tt_initialize);
|
|
||||||
|
|
||||||
/* cleanup thermal throttling management related memory and timer */
|
|
||||||
void iwl_tt_exit(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
|
|
||||||
|
|
||||||
/* stop ct_kill_exit_tm timer if activated */
|
|
||||||
del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
|
|
||||||
/* stop ct_kill_waiting_tm timer if activated */
|
|
||||||
del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
|
|
||||||
cancel_work_sync(&priv->tt_work);
|
|
||||||
cancel_work_sync(&priv->ct_enter);
|
|
||||||
cancel_work_sync(&priv->ct_exit);
|
|
||||||
|
|
||||||
if (priv->thermal_throttle.advanced_tt) {
|
|
||||||
/* free advance thermal throttling memory */
|
|
||||||
kfree(tt->restriction);
|
|
||||||
tt->restriction = NULL;
|
|
||||||
kfree(tt->transaction);
|
|
||||||
tt->transaction = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(iwl_tt_exit);
|
|
||||||
|
|
||||||
/* initialize to default */
|
/* initialize to default */
|
||||||
void iwl_power_initialize(struct iwl_priv *priv)
|
void iwl_power_initialize(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,90 +30,6 @@
|
||||||
|
|
||||||
#include "iwl-commands.h"
|
#include "iwl-commands.h"
|
||||||
|
|
||||||
#define IWL_ABSOLUTE_ZERO 0
|
|
||||||
#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
|
|
||||||
#define IWL_TT_INCREASE_MARGIN 5
|
|
||||||
#define IWL_TT_CT_KILL_MARGIN 3
|
|
||||||
|
|
||||||
enum iwl_antenna_ok {
|
|
||||||
IWL_ANT_OK_NONE,
|
|
||||||
IWL_ANT_OK_SINGLE,
|
|
||||||
IWL_ANT_OK_MULTI,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Thermal Throttling State Machine states */
|
|
||||||
enum iwl_tt_state {
|
|
||||||
IWL_TI_0, /* normal temperature, system power state */
|
|
||||||
IWL_TI_1, /* high temperature detect, low power state */
|
|
||||||
IWL_TI_2, /* higher temperature detected, lower power state */
|
|
||||||
IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
|
|
||||||
IWL_TI_STATE_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct iwl_tt_restriction - Thermal Throttling restriction table
|
|
||||||
* @tx_stream: number of tx stream allowed
|
|
||||||
* @is_ht: ht enable/disable
|
|
||||||
* @rx_stream: number of rx stream allowed
|
|
||||||
*
|
|
||||||
* This table is used by advance thermal throttling management
|
|
||||||
* based on the current thermal throttling state, and determines
|
|
||||||
* the number of tx/rx streams and the status of HT operation.
|
|
||||||
*/
|
|
||||||
struct iwl_tt_restriction {
|
|
||||||
enum iwl_antenna_ok tx_stream;
|
|
||||||
enum iwl_antenna_ok rx_stream;
|
|
||||||
bool is_ht;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct iwl_tt_trans - Thermal Throttling transaction table
|
|
||||||
* @next_state: next thermal throttling mode
|
|
||||||
* @tt_low: low temperature threshold to change state
|
|
||||||
* @tt_high: high temperature threshold to change state
|
|
||||||
*
|
|
||||||
* This is used by the advanced thermal throttling algorithm
|
|
||||||
* to determine the next thermal state to go based on the
|
|
||||||
* current temperature.
|
|
||||||
*/
|
|
||||||
struct iwl_tt_trans {
|
|
||||||
enum iwl_tt_state next_state;
|
|
||||||
u32 tt_low;
|
|
||||||
u32 tt_high;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct iwl_tt_mgnt - Thermal Throttling Management structure
|
|
||||||
* @advanced_tt: advanced thermal throttle required
|
|
||||||
* @state: current Thermal Throttling state
|
|
||||||
* @tt_power_mode: Thermal Throttling power mode index
|
|
||||||
* being used to set power level when
|
|
||||||
* when thermal throttling state != IWL_TI_0
|
|
||||||
* the tt_power_mode should set to different
|
|
||||||
* power mode based on the current tt state
|
|
||||||
* @tt_previous_temperature: last measured temperature
|
|
||||||
* @iwl_tt_restriction: ptr to restriction tbl, used by advance
|
|
||||||
* thermal throttling to determine how many tx/rx streams
|
|
||||||
* should be used in tt state; and can HT be enabled or not
|
|
||||||
* @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
|
|
||||||
* state transaction
|
|
||||||
* @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
|
|
||||||
* @ct_kill_exit_tm: timer to exit thermal kill
|
|
||||||
*/
|
|
||||||
struct iwl_tt_mgmt {
|
|
||||||
enum iwl_tt_state state;
|
|
||||||
bool advanced_tt;
|
|
||||||
u8 tt_power_mode;
|
|
||||||
bool ct_kill_toggle;
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
s32 tt_previous_temp;
|
|
||||||
#endif
|
|
||||||
struct iwl_tt_restriction *restriction;
|
|
||||||
struct iwl_tt_trans *transaction;
|
|
||||||
struct timer_list ct_kill_exit_tm;
|
|
||||||
struct timer_list ct_kill_waiting_tm;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum iwl_power_level {
|
enum iwl_power_level {
|
||||||
IWL_POWER_INDEX_1,
|
IWL_POWER_INDEX_1,
|
||||||
IWL_POWER_INDEX_2,
|
IWL_POWER_INDEX_2,
|
||||||
|
@ -130,15 +46,6 @@ struct iwl_power_mgr {
|
||||||
};
|
};
|
||||||
|
|
||||||
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
|
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
|
||||||
bool iwl_ht_enabled(struct iwl_priv *priv);
|
|
||||||
bool iwl_within_ct_kill_margin(struct iwl_priv *priv);
|
|
||||||
enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
|
|
||||||
enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
|
|
||||||
void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
|
|
||||||
void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
|
|
||||||
void iwl_tt_handler(struct iwl_priv *priv);
|
|
||||||
void iwl_tt_initialize(struct iwl_priv *priv);
|
|
||||||
void iwl_tt_exit(struct iwl_priv *priv);
|
|
||||||
void iwl_power_initialize(struct iwl_priv *priv);
|
void iwl_power_initialize(struct iwl_priv *priv);
|
||||||
|
|
||||||
extern bool no_sleep_autoadjust;
|
extern bool no_sleep_autoadjust;
|
||||||
|
|
|
@ -378,7 +378,7 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
|
||||||
queue_work(priv->workqueue, &priv->start_internal_scan);
|
queue_work(priv->workqueue, &priv->start_internal_scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void iwl_bg_start_internal_scan(struct work_struct *work)
|
static void iwl_bg_start_internal_scan(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv =
|
struct iwl_priv *priv =
|
||||||
container_of(work, struct iwl_priv, start_internal_scan);
|
container_of(work, struct iwl_priv, start_internal_scan);
|
||||||
|
@ -418,9 +418,8 @@ void iwl_bg_start_internal_scan(struct work_struct *work)
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_bg_start_internal_scan);
|
|
||||||
|
|
||||||
void iwl_bg_scan_check(struct work_struct *data)
|
static void iwl_bg_scan_check(struct work_struct *data)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv =
|
struct iwl_priv *priv =
|
||||||
container_of(data, struct iwl_priv, scan_check.work);
|
container_of(data, struct iwl_priv, scan_check.work);
|
||||||
|
@ -439,7 +438,6 @@ void iwl_bg_scan_check(struct work_struct *data)
|
||||||
}
|
}
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_bg_scan_check);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_fill_probe_req - fill in all required fields and IE for probe request
|
* iwl_fill_probe_req - fill in all required fields and IE for probe request
|
||||||
|
@ -489,7 +487,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_fill_probe_req);
|
EXPORT_SYMBOL(iwl_fill_probe_req);
|
||||||
|
|
||||||
void iwl_bg_abort_scan(struct work_struct *work)
|
static void iwl_bg_abort_scan(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
|
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
|
||||||
|
|
||||||
|
@ -504,13 +502,13 @@ void iwl_bg_abort_scan(struct work_struct *work)
|
||||||
iwl_send_scan_abort(priv);
|
iwl_send_scan_abort(priv);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_bg_abort_scan);
|
|
||||||
|
|
||||||
void iwl_bg_scan_completed(struct work_struct *work)
|
static void iwl_bg_scan_completed(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv =
|
struct iwl_priv *priv =
|
||||||
container_of(work, struct iwl_priv, scan_completed);
|
container_of(work, struct iwl_priv, scan_completed);
|
||||||
bool internal = false;
|
bool internal = false;
|
||||||
|
bool scan_completed = false;
|
||||||
|
|
||||||
IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
|
IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
|
||||||
|
|
||||||
|
@ -521,7 +519,8 @@ void iwl_bg_scan_completed(struct work_struct *work)
|
||||||
priv->is_internal_short_scan = false;
|
priv->is_internal_short_scan = false;
|
||||||
IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
|
IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
|
||||||
internal = true;
|
internal = true;
|
||||||
} else {
|
} else if (priv->scan_request) {
|
||||||
|
scan_completed = true;
|
||||||
priv->scan_request = NULL;
|
priv->scan_request = NULL;
|
||||||
priv->scan_vif = NULL;
|
priv->scan_vif = NULL;
|
||||||
}
|
}
|
||||||
|
@ -552,10 +551,9 @@ void iwl_bg_scan_completed(struct work_struct *work)
|
||||||
* into driver again into functions that will attempt to take
|
* into driver again into functions that will attempt to take
|
||||||
* mutex.
|
* mutex.
|
||||||
*/
|
*/
|
||||||
if (!internal)
|
if (scan_completed)
|
||||||
ieee80211_scan_completed(priv->hw, false);
|
ieee80211_scan_completed(priv->hw, false);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_bg_scan_completed);
|
|
||||||
|
|
||||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
|
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -818,7 +818,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
|
||||||
|
|
||||||
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
keyconf->hw_key_idx = HW_KEY_DEFAULT;
|
keyconf->hw_key_idx = HW_KEY_DEFAULT;
|
||||||
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
|
priv->stations[IWL_AP_ID].keyinfo.cipher = keyconf->cipher;
|
||||||
|
|
||||||
priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
|
priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
|
||||||
memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
|
memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
|
||||||
|
@ -856,7 +856,7 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
|
|
||||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||||
priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
|
priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
|
||||||
|
|
||||||
|
@ -906,7 +906,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
||||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||||
|
|
||||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||||
|
@ -955,7 +955,7 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
|
|
||||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||||
priv->stations[sta_id].keyinfo.keylen = 16;
|
priv->stations[sta_id].keyinfo.keylen = 16;
|
||||||
|
|
||||||
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
||||||
|
@ -1090,24 +1090,26 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
|
||||||
priv->key_mapping_key++;
|
priv->key_mapping_key++;
|
||||||
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
|
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
|
||||||
|
|
||||||
switch (keyconf->alg) {
|
switch (keyconf->cipher) {
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv,
|
IWL_ERR(priv,
|
||||||
"Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
|
"Unknown alg: %s cipher = %x\n", __func__,
|
||||||
|
keyconf->cipher);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
|
IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n",
|
||||||
keyconf->alg, keyconf->keylen, keyconf->keyidx,
|
keyconf->cipher, keyconf->keylen, keyconf->keyidx,
|
||||||
sta_id, ret);
|
sta_id, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -422,6 +422,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||||
int len;
|
int len;
|
||||||
u32 idx;
|
u32 idx;
|
||||||
u16 fix_size;
|
u16 fix_size;
|
||||||
|
bool is_ct_kill = false;
|
||||||
|
|
||||||
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
|
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
|
||||||
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
|
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
|
||||||
|
@ -443,9 +444,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||||
|
|
||||||
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
|
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
|
||||||
IWL_ERR(priv, "No space in command queue\n");
|
IWL_ERR(priv, "No space in command queue\n");
|
||||||
if (iwl_within_ct_kill_margin(priv))
|
if (priv->cfg->ops->lib->tt_ops.ct_kill_check) {
|
||||||
iwl_tt_enter_ct_kill(priv);
|
is_ct_kill =
|
||||||
else {
|
priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
|
||||||
|
}
|
||||||
|
if (!is_ct_kill) {
|
||||||
IWL_ERR(priv, "Restarting adapter due to queue full\n");
|
IWL_ERR(priv, "Restarting adapter due to queue full\n");
|
||||||
queue_work(priv->workqueue, &priv->restart);
|
queue_work(priv->workqueue, &priv->restart);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci-aspm.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
@ -151,7 +152,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
||||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||||
keyconf->keylen);
|
keyconf->keylen);
|
||||||
|
@ -222,23 +223,25 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
|
||||||
|
|
||||||
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
|
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
|
||||||
|
|
||||||
switch (keyconf->alg) {
|
switch (keyconf->cipher) {
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
|
ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
|
IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__,
|
||||||
|
keyconf->cipher);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
|
IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n",
|
||||||
keyconf->alg, keyconf->keylen, keyconf->keyidx,
|
keyconf->cipher, keyconf->keylen, keyconf->keyidx,
|
||||||
sta_id, ret);
|
sta_id, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -254,10 +257,11 @@ static int iwl3945_remove_static_key(struct iwl_priv *priv)
|
||||||
static int iwl3945_set_static_key(struct iwl_priv *priv,
|
static int iwl3945_set_static_key(struct iwl_priv *priv,
|
||||||
struct ieee80211_key_conf *key)
|
struct ieee80211_key_conf *key)
|
||||||
{
|
{
|
||||||
if (key->alg == ALG_WEP)
|
if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||||
|
key->cipher == WLAN_CIPHER_SUITE_WEP104)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
|
IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,23 +373,25 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
||||||
struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
|
struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
|
||||||
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
|
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
|
||||||
|
|
||||||
switch (keyinfo->alg) {
|
tx_cmd->sec_ctl = 0;
|
||||||
case ALG_CCMP:
|
|
||||||
|
switch (keyinfo->cipher) {
|
||||||
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
|
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
|
||||||
memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
|
memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
|
||||||
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
|
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
|
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
|
||||||
|
/* fall through */
|
||||||
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
|
||||||
(info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
|
(info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
|
||||||
|
|
||||||
if (keyinfo->keylen == 13)
|
|
||||||
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
|
|
||||||
|
|
||||||
memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
|
memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
|
||||||
|
|
||||||
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
|
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
|
||||||
|
@ -393,7 +399,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg);
|
IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,9 +819,9 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
|
||||||
static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
|
static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
|
||||||
struct iwl_rx_mem_buffer *rxb)
|
struct iwl_rx_mem_buffer *rxb)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||||
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
|
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
u8 rate = beacon->beacon_notify_hdr.rate;
|
u8 rate = beacon->beacon_notify_hdr.rate;
|
||||||
|
|
||||||
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
|
IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
|
||||||
|
@ -827,6 +833,8 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
|
||||||
le32_to_cpu(beacon->low_tsf), rate);
|
le32_to_cpu(beacon->low_tsf), rate);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
|
||||||
|
|
||||||
if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
|
if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
|
||||||
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
|
(!test_bit(STATUS_EXIT_PENDING, &priv->status)))
|
||||||
queue_work(priv->workqueue, &priv->beacon_update);
|
queue_work(priv->workqueue, &priv->beacon_update);
|
||||||
|
@ -3086,10 +3094,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
|
||||||
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
|
rc = iwl_send_rxon_timing(priv, vif);
|
||||||
iwl_setup_rxon_timing(priv, vif);
|
|
||||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
|
|
||||||
sizeof(priv->rxon_timing), &priv->rxon_timing);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||||
"Attempting to continue.\n");
|
"Attempting to continue.\n");
|
||||||
|
@ -3263,11 +3268,7 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
|
||||||
/* RXON Timing */
|
/* RXON Timing */
|
||||||
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
|
rc = iwl_send_rxon_timing(priv, vif);
|
||||||
iwl_setup_rxon_timing(priv, vif);
|
|
||||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
|
|
||||||
sizeof(priv->rxon_timing),
|
|
||||||
&priv->rxon_timing);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||||
"Attempting to continue.\n");
|
"Attempting to continue.\n");
|
||||||
|
@ -3785,10 +3786,8 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
|
||||||
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
|
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
|
||||||
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
|
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
|
||||||
INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
|
INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
|
||||||
INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
|
|
||||||
INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
|
iwl_setup_scan_deferred_work(priv);
|
||||||
INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
|
|
||||||
INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
|
|
||||||
|
|
||||||
iwl3945_hw_setup_deferred_work(priv);
|
iwl3945_hw_setup_deferred_work(priv);
|
||||||
|
|
||||||
|
@ -3853,6 +3852,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
|
||||||
.hw_scan = iwl_mac_hw_scan,
|
.hw_scan = iwl_mac_hw_scan,
|
||||||
.sta_add = iwl3945_mac_sta_add,
|
.sta_add = iwl3945_mac_sta_add,
|
||||||
.sta_remove = iwl_mac_sta_remove,
|
.sta_remove = iwl_mac_sta_remove,
|
||||||
|
.tx_last_beacon = iwl_mac_tx_last_beacon,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int iwl3945_init_drv(struct iwl_priv *priv)
|
static int iwl3945_init_drv(struct iwl_priv *priv)
|
||||||
|
@ -4009,6 +4009,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||||
/***************************
|
/***************************
|
||||||
* 2. Initializing PCI bus
|
* 2. Initializing PCI bus
|
||||||
* *************************/
|
* *************************/
|
||||||
|
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
|
||||||
|
PCIE_LINK_STATE_CLKPM);
|
||||||
|
|
||||||
if (pci_enable_device(pdev)) {
|
if (pci_enable_device(pdev)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto out_ieee80211_free_hw;
|
goto out_ieee80211_free_hw;
|
||||||
|
|
|
@ -1195,11 +1195,8 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
|
||||||
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
|
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
|
||||||
"oid is 0x%x\n", hdr->oid);
|
"oid is 0x%x\n", hdr->oid);
|
||||||
|
|
||||||
if (hdr->oid <= WIFI_IF_NTFY_MAX) {
|
set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
|
||||||
set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
|
wake_up_interruptible(&iwm->wifi_ntfy_queue);
|
||||||
wake_up_interruptible(&iwm->wifi_ntfy_queue);
|
|
||||||
} else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
switch (hdr->oid) {
|
switch (hdr->oid) {
|
||||||
case UMAC_WIFI_IF_CMD_SET_PROFILE:
|
case UMAC_WIFI_IF_CMD_SET_PROFILE:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include <linux/ieee80211.h>
|
#include <linux/ieee80211.h>
|
||||||
#include <net/cfg80211.h>
|
#include <net/cfg80211.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
@ -526,20 +527,31 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||||
|
|
||||||
pos = scanresp->bssdesc_and_tlvbuffer;
|
pos = scanresp->bssdesc_and_tlvbuffer;
|
||||||
|
|
||||||
|
lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RSP", scanresp->bssdesc_and_tlvbuffer,
|
||||||
|
scanresp->bssdescriptsize);
|
||||||
|
|
||||||
tsfdesc = pos + bsssize;
|
tsfdesc = pos + bsssize;
|
||||||
tsfsize = 4 + 8 * scanresp->nr_sets;
|
tsfsize = 4 + 8 * scanresp->nr_sets;
|
||||||
|
lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TSF", (u8 *) tsfdesc, tsfsize);
|
||||||
|
|
||||||
/* Validity check: we expect a Marvell-Local TLV */
|
/* Validity check: we expect a Marvell-Local TLV */
|
||||||
i = get_unaligned_le16(tsfdesc);
|
i = get_unaligned_le16(tsfdesc);
|
||||||
tsfdesc += 2;
|
tsfdesc += 2;
|
||||||
if (i != TLV_TYPE_TSFTIMESTAMP)
|
if (i != TLV_TYPE_TSFTIMESTAMP) {
|
||||||
|
lbs_deb_scan("scan response: invalid TSF Timestamp %d\n", i);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Validity check: the TLV holds TSF values with 8 bytes each, so
|
/* Validity check: the TLV holds TSF values with 8 bytes each, so
|
||||||
* the size in the TLV must match the nr_sets value */
|
* the size in the TLV must match the nr_sets value */
|
||||||
i = get_unaligned_le16(tsfdesc);
|
i = get_unaligned_le16(tsfdesc);
|
||||||
tsfdesc += 2;
|
tsfdesc += 2;
|
||||||
if (i / 8 != scanresp->nr_sets)
|
if (i / 8 != scanresp->nr_sets) {
|
||||||
|
lbs_deb_scan("scan response: invalid number of TSF timestamp "
|
||||||
|
"sets (expected %d got %d)\n", scanresp->nr_sets,
|
||||||
|
i / 8);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < scanresp->nr_sets; i++) {
|
for (i = 0; i < scanresp->nr_sets; i++) {
|
||||||
const u8 *bssid;
|
const u8 *bssid;
|
||||||
|
@ -581,8 +593,11 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||||
id = *pos++;
|
id = *pos++;
|
||||||
elen = *pos++;
|
elen = *pos++;
|
||||||
left -= 2;
|
left -= 2;
|
||||||
if (elen > left || elen == 0)
|
if (elen > left || elen == 0) {
|
||||||
|
lbs_deb_scan("scan response: invalid IE fmt\n");
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (id == WLAN_EID_DS_PARAMS)
|
if (id == WLAN_EID_DS_PARAMS)
|
||||||
chan_no = *pos;
|
chan_no = *pos;
|
||||||
if (id == WLAN_EID_SSID) {
|
if (id == WLAN_EID_SSID) {
|
||||||
|
@ -613,7 +628,9 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||||
capa, intvl, ie, ielen,
|
capa, intvl, ie, ielen,
|
||||||
LBS_SCAN_RSSI_TO_MBM(rssi),
|
LBS_SCAN_RSSI_TO_MBM(rssi),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
}
|
} else
|
||||||
|
lbs_deb_scan("scan response: missing BSS channel IE\n");
|
||||||
|
|
||||||
tsfdesc += 8;
|
tsfdesc += 8;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1103,7 +1120,7 @@ static int lbs_associate(struct lbs_private *priv,
|
||||||
lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
|
lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
|
||||||
|
|
||||||
/* add auth type TLV */
|
/* add auth type TLV */
|
||||||
if (priv->fwrelease >= 0x09000000)
|
if (MRVL_FW_MAJOR_REV(priv->fwrelease) >= 9)
|
||||||
pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
|
pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
|
||||||
|
|
||||||
/* add WPA/WPA2 TLV */
|
/* add WPA/WPA2 TLV */
|
||||||
|
@ -1114,6 +1131,9 @@ static int lbs_associate(struct lbs_private *priv,
|
||||||
(u16)(pos - (u8 *) &cmd->iebuf);
|
(u16)(pos - (u8 *) &cmd->iebuf);
|
||||||
cmd->hdr.size = cpu_to_le16(len);
|
cmd->hdr.size = cpu_to_le16(len);
|
||||||
|
|
||||||
|
lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_CMD", (u8 *) cmd,
|
||||||
|
le16_to_cpu(cmd->hdr.size));
|
||||||
|
|
||||||
/* store for later use */
|
/* store for later use */
|
||||||
memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
|
memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
|
||||||
|
|
||||||
|
@ -1121,14 +1141,28 @@ static int lbs_associate(struct lbs_private *priv,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
||||||
/* generate connect message to cfg80211 */
|
/* generate connect message to cfg80211 */
|
||||||
|
|
||||||
resp = (void *) cmd; /* recast for easier field access */
|
resp = (void *) cmd; /* recast for easier field access */
|
||||||
status = le16_to_cpu(resp->statuscode);
|
status = le16_to_cpu(resp->statuscode);
|
||||||
|
|
||||||
/* Convert statis code of old firmware */
|
/* Older FW versions map the IEEE 802.11 Status Code in the association
|
||||||
if (priv->fwrelease < 0x09000000)
|
* response to the following values returned in resp->statuscode:
|
||||||
|
*
|
||||||
|
* IEEE Status Code Marvell Status Code
|
||||||
|
* 0 -> 0x0000 ASSOC_RESULT_SUCCESS
|
||||||
|
* 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* others -> 0x0003 ASSOC_RESULT_REFUSED
|
||||||
|
*
|
||||||
|
* Other response codes:
|
||||||
|
* 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
|
||||||
|
* 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
|
||||||
|
* association response from the AP)
|
||||||
|
*/
|
||||||
|
if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
@ -1150,11 +1184,16 @@ static int lbs_associate(struct lbs_private *priv,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lbs_deb_assoc("association failure %d\n", status);
|
lbs_deb_assoc("association failure %d\n", status);
|
||||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
/* v5 OLPC firmware does return the AP status code if
|
||||||
|
* it's not one of the values above. Let that through.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lbs_deb_assoc("status %d, capability 0x%04x\n", status,
|
lbs_deb_assoc("status %d, statuscode 0x%04x, capability 0x%04x, "
|
||||||
le16_to_cpu(resp->capability));
|
"aid 0x%04x\n", status, le16_to_cpu(resp->statuscode),
|
||||||
|
le16_to_cpu(resp->capability), le16_to_cpu(resp->aid));
|
||||||
|
|
||||||
resp_ie_len = le16_to_cpu(resp->hdr.size)
|
resp_ie_len = le16_to_cpu(resp->hdr.size)
|
||||||
- sizeof(resp->hdr)
|
- sizeof(resp->hdr)
|
||||||
|
@ -1174,7 +1213,6 @@ static int lbs_associate(struct lbs_private *priv,
|
||||||
netif_tx_wake_all_queues(priv->dev);
|
netif_tx_wake_all_queues(priv->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -8,7 +8,14 @@
|
||||||
#define _LBS_DECL_H_
|
#define _LBS_DECL_H_
|
||||||
|
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
|
||||||
|
/* Should be terminated by a NULL entry */
|
||||||
|
struct lbs_fw_table {
|
||||||
|
int model;
|
||||||
|
const char *helper;
|
||||||
|
const char *fwname;
|
||||||
|
};
|
||||||
|
|
||||||
struct lbs_private;
|
struct lbs_private;
|
||||||
struct sk_buff;
|
struct sk_buff;
|
||||||
|
@ -53,4 +60,10 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
|
||||||
u32 lbs_fw_index_to_data_rate(u8 index);
|
u32 lbs_fw_index_to_data_rate(u8 index);
|
||||||
u8 lbs_data_rate_to_fw_index(u32 rate);
|
u8 lbs_data_rate_to_fw_index(u32 rate);
|
||||||
|
|
||||||
|
int lbs_get_firmware(struct device *dev, const char *user_helper,
|
||||||
|
const char *user_mainfw, u32 card_model,
|
||||||
|
const struct lbs_fw_table *fw_table,
|
||||||
|
const struct firmware **helper,
|
||||||
|
const struct firmware **mainfw);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
|
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
|
||||||
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
|
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_FIRMWARE("libertas_cs_helper.fw");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,9 +60,34 @@ struct if_cs_card {
|
||||||
struct lbs_private *priv;
|
struct lbs_private *priv;
|
||||||
void __iomem *iobase;
|
void __iomem *iobase;
|
||||||
bool align_regs;
|
bool align_regs;
|
||||||
|
u32 model;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MODEL_UNKNOWN = 0x00,
|
||||||
|
MODEL_8305 = 0x01,
|
||||||
|
MODEL_8381 = 0x02,
|
||||||
|
MODEL_8385 = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct lbs_fw_table fw_table[] = {
|
||||||
|
{ MODEL_8305, "libertas/cf8305.bin", NULL },
|
||||||
|
{ MODEL_8305, "libertas_cs_helper.fw", NULL },
|
||||||
|
{ MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
|
||||||
|
{ MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
|
||||||
|
{ MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
|
||||||
|
{ MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
|
||||||
|
{ 0, NULL, NULL }
|
||||||
|
};
|
||||||
|
MODULE_FIRMWARE("libertas/cf8305.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/cf8381_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/cf8381.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/cf8385_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/cf8385.bin");
|
||||||
|
MODULE_FIRMWARE("libertas_cs_helper.fw");
|
||||||
|
MODULE_FIRMWARE("libertas_cs.fw");
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
/* Hardware access */
|
/* Hardware access */
|
||||||
|
@ -289,22 +313,19 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
|
||||||
#define CF8385_MANFID 0x02df
|
#define CF8385_MANFID 0x02df
|
||||||
#define CF8385_CARDID 0x8103
|
#define CF8385_CARDID 0x8103
|
||||||
|
|
||||||
static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
|
/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
|
||||||
|
* that gets fixed. Currently there's no way to access it from the probe hook.
|
||||||
|
*/
|
||||||
|
static inline u32 get_model(u16 manf_id, u16 card_id)
|
||||||
{
|
{
|
||||||
return (p_dev->manf_id == CF8305_MANFID &&
|
/* NOTE: keep in sync with if_cs_ids */
|
||||||
p_dev->card_id == CF8305_CARDID);
|
if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
|
||||||
}
|
return MODEL_8305;
|
||||||
|
else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
|
||||||
static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
|
return MODEL_8381;
|
||||||
{
|
else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
|
||||||
return (p_dev->manf_id == CF8381_MANFID &&
|
return MODEL_8385;
|
||||||
p_dev->card_id == CF8381_CARDID);
|
return MODEL_UNKNOWN;
|
||||||
}
|
|
||||||
|
|
||||||
static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev)
|
|
||||||
{
|
|
||||||
return (p_dev->manf_id == CF8385_MANFID &&
|
|
||||||
p_dev->card_id == CF8385_CARDID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
|
@ -558,12 +579,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||||
*
|
*
|
||||||
* Return 0 on success
|
* Return 0 on success
|
||||||
*/
|
*/
|
||||||
static int if_cs_prog_helper(struct if_cs_card *card)
|
static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
u8 scratch;
|
u8 scratch;
|
||||||
const struct firmware *fw;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_CS);
|
lbs_deb_enter(LBS_DEB_CS);
|
||||||
|
|
||||||
|
@ -589,14 +609,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: make firmware file configurable */
|
|
||||||
ret = request_firmware(&fw, "libertas_cs_helper.fw",
|
|
||||||
&card->p_dev->dev);
|
|
||||||
if (ret) {
|
|
||||||
lbs_pr_err("can't load helper firmware\n");
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
lbs_deb_cs("helper size %td\n", fw->size);
|
lbs_deb_cs("helper size %td\n", fw->size);
|
||||||
|
|
||||||
/* "Set the 5 bytes of the helper image to 0" */
|
/* "Set the 5 bytes of the helper image to 0" */
|
||||||
|
@ -635,7 +647,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
|
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
|
||||||
sent, ret);
|
sent, ret);
|
||||||
goto err_release;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
|
@ -644,17 +656,14 @@ static int if_cs_prog_helper(struct if_cs_card *card)
|
||||||
sent += count;
|
sent += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_release:
|
|
||||||
release_firmware(fw);
|
|
||||||
done:
|
done:
|
||||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int if_cs_prog_real(struct if_cs_card *card)
|
static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
|
||||||
{
|
{
|
||||||
const struct firmware *fw;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int retry = 0;
|
int retry = 0;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -662,21 +671,13 @@ static int if_cs_prog_real(struct if_cs_card *card)
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_CS);
|
lbs_deb_enter(LBS_DEB_CS);
|
||||||
|
|
||||||
/* TODO: make firmware file configurable */
|
|
||||||
ret = request_firmware(&fw, "libertas_cs.fw",
|
|
||||||
&card->p_dev->dev);
|
|
||||||
if (ret) {
|
|
||||||
lbs_pr_err("can't load firmware\n");
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
lbs_deb_cs("fw size %td\n", fw->size);
|
lbs_deb_cs("fw size %td\n", fw->size);
|
||||||
|
|
||||||
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
|
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
|
||||||
IF_CS_SQ_HELPER_OK);
|
IF_CS_SQ_HELPER_OK);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lbs_pr_err("helper firmware doesn't answer\n");
|
lbs_pr_err("helper firmware doesn't answer\n");
|
||||||
goto err_release;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (sent = 0; sent < fw->size; sent += len) {
|
for (sent = 0; sent < fw->size; sent += len) {
|
||||||
|
@ -691,7 +692,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
|
||||||
if (retry > 20) {
|
if (retry > 20) {
|
||||||
lbs_pr_err("could not download firmware\n");
|
lbs_pr_err("could not download firmware\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err_release;
|
goto done;
|
||||||
}
|
}
|
||||||
if (retry) {
|
if (retry) {
|
||||||
sent -= len;
|
sent -= len;
|
||||||
|
@ -710,7 +711,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
|
||||||
IF_CS_BIT_COMMAND);
|
IF_CS_BIT_COMMAND);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lbs_pr_err("can't download firmware at 0x%x\n", sent);
|
lbs_pr_err("can't download firmware at 0x%x\n", sent);
|
||||||
goto err_release;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,9 +719,6 @@ static int if_cs_prog_real(struct if_cs_card *card)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
lbs_pr_err("firmware download failed\n");
|
lbs_pr_err("firmware download failed\n");
|
||||||
|
|
||||||
err_release:
|
|
||||||
release_firmware(fw);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -824,6 +822,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||||
unsigned int prod_id;
|
unsigned int prod_id;
|
||||||
struct lbs_private *priv;
|
struct lbs_private *priv;
|
||||||
struct if_cs_card *card;
|
struct if_cs_card *card;
|
||||||
|
const struct firmware *helper = NULL;
|
||||||
|
const struct firmware *mainfw = NULL;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_CS);
|
lbs_deb_enter(LBS_DEB_CS);
|
||||||
|
|
||||||
|
@ -843,7 +843,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||||
goto out1;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an interrupt line. Note that this does not assign
|
* Allocate an interrupt line. Note that this does not assign
|
||||||
* a handler to the interrupt, unless the 'Handler' member of
|
* a handler to the interrupt, unless the 'Handler' member of
|
||||||
|
@ -881,34 +880,47 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||||
*/
|
*/
|
||||||
card->align_regs = 0;
|
card->align_regs = 0;
|
||||||
|
|
||||||
|
card->model = get_model(p_dev->manf_id, p_dev->card_id);
|
||||||
|
if (card->model == MODEL_UNKNOWN) {
|
||||||
|
lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
|
||||||
|
p_dev->manf_id, p_dev->card_id);
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we have a current silicon */
|
/* Check if we have a current silicon */
|
||||||
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
|
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
|
||||||
if (if_cs_hw_is_cf8305(p_dev)) {
|
if (card->model == MODEL_8305) {
|
||||||
card->align_regs = 1;
|
card->align_regs = 1;
|
||||||
if (prod_id < IF_CS_CF8305_B1_REV) {
|
if (prod_id < IF_CS_CF8305_B1_REV) {
|
||||||
lbs_pr_err("old chips like 8305 rev B3 "
|
lbs_pr_err("8305 rev B0 and older are not supported\n");
|
||||||
"aren't supported\n");
|
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
|
if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
|
||||||
lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
|
lbs_pr_err("8381 rev B2 and older are not supported\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) {
|
if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
|
||||||
lbs_pr_err("old chips like 8385 rev B1 aren't supported\n");
|
lbs_pr_err("8385 rev B0 and older are not supported\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
|
||||||
|
&fw_table[0], &helper, &mainfw);
|
||||||
|
if (ret) {
|
||||||
|
lbs_pr_err("failed to find firmware (%d)\n", ret);
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Load the firmware early, before calling into libertas.ko */
|
/* Load the firmware early, before calling into libertas.ko */
|
||||||
ret = if_cs_prog_helper(card);
|
ret = if_cs_prog_helper(card, helper);
|
||||||
if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
|
if (ret == 0 && (card->model != MODEL_8305))
|
||||||
ret = if_cs_prog_real(card);
|
ret = if_cs_prog_real(card, mainfw);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out2;
|
goto out2;
|
||||||
|
|
||||||
|
@ -957,6 +969,11 @@ out2:
|
||||||
out1:
|
out1:
|
||||||
pcmcia_disable_device(p_dev);
|
pcmcia_disable_device(p_dev);
|
||||||
out:
|
out:
|
||||||
|
if (helper)
|
||||||
|
release_firmware(helper);
|
||||||
|
if (mainfw)
|
||||||
|
release_firmware(mainfw);
|
||||||
|
|
||||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -993,6 +1010,7 @@ static struct pcmcia_device_id if_cs_ids[] = {
|
||||||
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
|
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
|
||||||
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
|
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
|
||||||
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
|
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
|
||||||
|
/* NOTE: keep in sync with get_model() */
|
||||||
PCMCIA_DEVICE_NULL,
|
PCMCIA_DEVICE_NULL,
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
|
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
|
||||||
|
|
|
@ -76,36 +76,32 @@ static const struct sdio_device_id if_sdio_ids[] = {
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
|
MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
|
||||||
|
|
||||||
struct if_sdio_model {
|
#define MODEL_8385 0x04
|
||||||
int model;
|
#define MODEL_8686 0x0b
|
||||||
const char *helper;
|
#define MODEL_8688 0x10
|
||||||
const char *firmware;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct if_sdio_model if_sdio_models[] = {
|
static const struct lbs_fw_table fw_table[] = {
|
||||||
{
|
{ MODEL_8385, "libertas/sd8385_helper.bin", "libertas/sd8385.bin" },
|
||||||
/* 8385 */
|
{ MODEL_8385, "sd8385_helper.bin", "sd8385.bin" },
|
||||||
.model = IF_SDIO_MODEL_8385,
|
{ MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
|
||||||
.helper = "sd8385_helper.bin",
|
{ MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
|
||||||
.firmware = "sd8385.bin",
|
{ MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
|
||||||
},
|
{ MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
|
||||||
{
|
{ MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
|
||||||
/* 8686 */
|
{ 0, NULL, NULL }
|
||||||
.model = IF_SDIO_MODEL_8686,
|
|
||||||
.helper = "sd8686_helper.bin",
|
|
||||||
.firmware = "sd8686.bin",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* 8688 */
|
|
||||||
.model = IF_SDIO_MODEL_8688,
|
|
||||||
.helper = "sd8688_helper.bin",
|
|
||||||
.firmware = "sd8688.bin",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
MODULE_FIRMWARE("libertas/sd8385_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8385.bin");
|
||||||
MODULE_FIRMWARE("sd8385_helper.bin");
|
MODULE_FIRMWARE("sd8385_helper.bin");
|
||||||
MODULE_FIRMWARE("sd8385.bin");
|
MODULE_FIRMWARE("sd8385.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8686_v9_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8686_v9.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8686_v8.bin");
|
||||||
MODULE_FIRMWARE("sd8686_helper.bin");
|
MODULE_FIRMWARE("sd8686_helper.bin");
|
||||||
MODULE_FIRMWARE("sd8686.bin");
|
MODULE_FIRMWARE("sd8686.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8688_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/sd8688.bin");
|
||||||
MODULE_FIRMWARE("sd8688_helper.bin");
|
MODULE_FIRMWARE("sd8688_helper.bin");
|
||||||
MODULE_FIRMWARE("sd8688.bin");
|
MODULE_FIRMWARE("sd8688.bin");
|
||||||
|
|
||||||
|
@ -187,11 +183,11 @@ static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
|
||||||
u16 rx_len;
|
u16 rx_len;
|
||||||
|
|
||||||
switch (card->model) {
|
switch (card->model) {
|
||||||
case IF_SDIO_MODEL_8385:
|
case MODEL_8385:
|
||||||
case IF_SDIO_MODEL_8686:
|
case MODEL_8686:
|
||||||
rx_len = if_sdio_read_scratch(card, &ret);
|
rx_len = if_sdio_read_scratch(card, &ret);
|
||||||
break;
|
break;
|
||||||
case IF_SDIO_MODEL_8688:
|
case MODEL_8688:
|
||||||
default: /* for newer chipsets */
|
default: /* for newer chipsets */
|
||||||
rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
|
rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -288,7 +284,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
if (card->model == IF_SDIO_MODEL_8385) {
|
if (card->model == MODEL_8385) {
|
||||||
event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
|
event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -466,10 +462,10 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
|
||||||
|
|
||||||
#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
|
#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
|
||||||
|
|
||||||
static int if_sdio_prog_helper(struct if_sdio_card *card)
|
static int if_sdio_prog_helper(struct if_sdio_card *card,
|
||||||
|
const struct firmware *fw)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
const struct firmware *fw;
|
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
u8 *chunk_buffer;
|
u8 *chunk_buffer;
|
||||||
u32 chunk_size;
|
u32 chunk_size;
|
||||||
|
@ -478,16 +474,10 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
ret = request_firmware(&fw, card->helper, &card->func->dev);
|
|
||||||
if (ret) {
|
|
||||||
lbs_pr_err("can't load helper firmware\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_buffer = kzalloc(64, GFP_KERNEL);
|
chunk_buffer = kzalloc(64, GFP_KERNEL);
|
||||||
if (!chunk_buffer) {
|
if (!chunk_buffer) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto release_fw;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdio_claim_host(card->func);
|
sdio_claim_host(card->func);
|
||||||
|
@ -562,22 +552,19 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
|
||||||
release:
|
release:
|
||||||
sdio_release_host(card->func);
|
sdio_release_host(card->func);
|
||||||
kfree(chunk_buffer);
|
kfree(chunk_buffer);
|
||||||
release_fw:
|
|
||||||
release_firmware(fw);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret)
|
if (ret)
|
||||||
lbs_pr_err("failed to load helper firmware\n");
|
lbs_pr_err("failed to load helper firmware\n");
|
||||||
|
|
||||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int if_sdio_prog_real(struct if_sdio_card *card)
|
static int if_sdio_prog_real(struct if_sdio_card *card,
|
||||||
|
const struct firmware *fw)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
const struct firmware *fw;
|
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
u8 *chunk_buffer;
|
u8 *chunk_buffer;
|
||||||
u32 chunk_size;
|
u32 chunk_size;
|
||||||
|
@ -586,16 +573,10 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
ret = request_firmware(&fw, card->firmware, &card->func->dev);
|
|
||||||
if (ret) {
|
|
||||||
lbs_pr_err("can't load firmware\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk_buffer = kzalloc(512, GFP_KERNEL);
|
chunk_buffer = kzalloc(512, GFP_KERNEL);
|
||||||
if (!chunk_buffer) {
|
if (!chunk_buffer) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto release_fw;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdio_claim_host(card->func);
|
sdio_claim_host(card->func);
|
||||||
|
@ -685,15 +666,12 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
|
||||||
release:
|
release:
|
||||||
sdio_release_host(card->func);
|
sdio_release_host(card->func);
|
||||||
kfree(chunk_buffer);
|
kfree(chunk_buffer);
|
||||||
release_fw:
|
|
||||||
release_firmware(fw);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret)
|
if (ret)
|
||||||
lbs_pr_err("failed to load firmware\n");
|
lbs_pr_err("failed to load firmware\n");
|
||||||
|
|
||||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,6 +679,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u16 scratch;
|
u16 scratch;
|
||||||
|
const struct firmware *helper = NULL;
|
||||||
|
const struct firmware *mainfw = NULL;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
|
@ -718,11 +698,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = if_sdio_prog_helper(card);
|
ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
|
||||||
|
card->model, &fw_table[0], &helper, &mainfw);
|
||||||
|
if (ret) {
|
||||||
|
lbs_pr_err("failed to find firmware (%d)\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = if_sdio_prog_helper(card, helper);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = if_sdio_prog_real(card);
|
ret = if_sdio_prog_real(card, mainfw);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -733,8 +720,12 @@ success:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
if (helper)
|
||||||
|
release_firmware(helper);
|
||||||
|
if (mainfw)
|
||||||
|
release_firmware(mainfw);
|
||||||
|
|
||||||
|
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +929,7 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
"ID: %x", &model) == 1)
|
"ID: %x", &model) == 1)
|
||||||
break;
|
break;
|
||||||
if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
|
if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
|
||||||
model = IF_SDIO_MODEL_8385;
|
model = MODEL_8385;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -956,13 +947,13 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
card->model = model;
|
card->model = model;
|
||||||
|
|
||||||
switch (card->model) {
|
switch (card->model) {
|
||||||
case IF_SDIO_MODEL_8385:
|
case MODEL_8385:
|
||||||
card->scratch_reg = IF_SDIO_SCRATCH_OLD;
|
card->scratch_reg = IF_SDIO_SCRATCH_OLD;
|
||||||
break;
|
break;
|
||||||
case IF_SDIO_MODEL_8686:
|
case MODEL_8686:
|
||||||
card->scratch_reg = IF_SDIO_SCRATCH;
|
card->scratch_reg = IF_SDIO_SCRATCH;
|
||||||
break;
|
break;
|
||||||
case IF_SDIO_MODEL_8688:
|
case MODEL_8688:
|
||||||
default: /* for newer chipsets */
|
default: /* for newer chipsets */
|
||||||
card->scratch_reg = IF_SDIO_FW_STATUS;
|
card->scratch_reg = IF_SDIO_FW_STATUS;
|
||||||
break;
|
break;
|
||||||
|
@ -972,49 +963,17 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
card->workqueue = create_workqueue("libertas_sdio");
|
card->workqueue = create_workqueue("libertas_sdio");
|
||||||
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
|
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
|
||||||
|
|
||||||
for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
|
/* Check if we support this card */
|
||||||
if (card->model == if_sdio_models[i].model)
|
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
|
||||||
|
if (card->model == fw_table[i].model)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (i == ARRAY_SIZE(fw_table)) {
|
||||||
if (i == ARRAY_SIZE(if_sdio_models)) {
|
|
||||||
lbs_pr_err("unknown card model 0x%x\n", card->model);
|
lbs_pr_err("unknown card model 0x%x\n", card->model);
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
card->helper = if_sdio_models[i].helper;
|
|
||||||
card->firmware = if_sdio_models[i].firmware;
|
|
||||||
|
|
||||||
kparam_block_sysfs_write(helper_name);
|
|
||||||
if (lbs_helper_name) {
|
|
||||||
char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
|
|
||||||
if (!helper) {
|
|
||||||
kparam_unblock_sysfs_write(helper_name);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free;
|
|
||||||
}
|
|
||||||
lbs_deb_sdio("overriding helper firmware: %s\n",
|
|
||||||
lbs_helper_name);
|
|
||||||
card->helper = helper;
|
|
||||||
card->helper_allocated = true;
|
|
||||||
}
|
|
||||||
kparam_unblock_sysfs_write(helper_name);
|
|
||||||
|
|
||||||
kparam_block_sysfs_write(fw_name);
|
|
||||||
if (lbs_fw_name) {
|
|
||||||
char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
|
|
||||||
if (!fw_name) {
|
|
||||||
kparam_unblock_sysfs_write(fw_name);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free;
|
|
||||||
}
|
|
||||||
lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
|
|
||||||
card->firmware = fw_name;
|
|
||||||
card->firmware_allocated = true;
|
|
||||||
}
|
|
||||||
kparam_unblock_sysfs_write(fw_name);
|
|
||||||
|
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
ret = sdio_enable_func(func);
|
ret = sdio_enable_func(func);
|
||||||
|
@ -1028,7 +987,7 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
/* For 1-bit transfers to the 8686 model, we need to enable the
|
/* For 1-bit transfers to the 8686 model, we need to enable the
|
||||||
* interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
|
* interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
|
||||||
* bit to allow access to non-vendor registers. */
|
* bit to allow access to non-vendor registers. */
|
||||||
if ((card->model == IF_SDIO_MODEL_8686) &&
|
if ((card->model == MODEL_8686) &&
|
||||||
(host->caps & MMC_CAP_SDIO_IRQ) &&
|
(host->caps & MMC_CAP_SDIO_IRQ) &&
|
||||||
(host->ios.bus_width == MMC_BUS_WIDTH_1)) {
|
(host->ios.bus_width == MMC_BUS_WIDTH_1)) {
|
||||||
u8 reg;
|
u8 reg;
|
||||||
|
@ -1091,8 +1050,8 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
* Get rx_unit if the chip is SD8688 or newer.
|
* Get rx_unit if the chip is SD8688 or newer.
|
||||||
* SD8385 & SD8686 do not have rx_unit.
|
* SD8385 & SD8686 do not have rx_unit.
|
||||||
*/
|
*/
|
||||||
if ((card->model != IF_SDIO_MODEL_8385)
|
if ((card->model != MODEL_8385)
|
||||||
&& (card->model != IF_SDIO_MODEL_8686))
|
&& (card->model != MODEL_8686))
|
||||||
card->rx_unit = if_sdio_read_rx_unit(card);
|
card->rx_unit = if_sdio_read_rx_unit(card);
|
||||||
else
|
else
|
||||||
card->rx_unit = 0;
|
card->rx_unit = 0;
|
||||||
|
@ -1108,7 +1067,7 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
/*
|
/*
|
||||||
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
|
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
|
||||||
*/
|
*/
|
||||||
if (card->model == IF_SDIO_MODEL_8688) {
|
if (card->model == MODEL_8688) {
|
||||||
struct cmd_header cmd;
|
struct cmd_header cmd;
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
@ -1165,7 +1124,7 @@ static void if_sdio_remove(struct sdio_func *func)
|
||||||
|
|
||||||
card = sdio_get_drvdata(func);
|
card = sdio_get_drvdata(func);
|
||||||
|
|
||||||
if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
|
if (user_rmmod && (card->model == MODEL_8688)) {
|
||||||
/*
|
/*
|
||||||
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
|
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
|
||||||
* multiple functions
|
* multiple functions
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
#ifndef _LBS_IF_SDIO_H
|
#ifndef _LBS_IF_SDIO_H
|
||||||
#define _LBS_IF_SDIO_H
|
#define _LBS_IF_SDIO_H
|
||||||
|
|
||||||
#define IF_SDIO_MODEL_8385 0x04
|
|
||||||
#define IF_SDIO_MODEL_8686 0x0b
|
|
||||||
#define IF_SDIO_MODEL_8688 0x10
|
|
||||||
|
|
||||||
#define IF_SDIO_IOPORT 0x00
|
#define IF_SDIO_IOPORT 0x00
|
||||||
|
|
||||||
#define IF_SDIO_H_INT_MASK 0x04
|
#define IF_SDIO_H_INT_MASK 0x04
|
||||||
|
|
|
@ -39,9 +39,6 @@ struct if_spi_card {
|
||||||
struct lbs_private *priv;
|
struct lbs_private *priv;
|
||||||
struct libertas_spi_platform_data *pdata;
|
struct libertas_spi_platform_data *pdata;
|
||||||
|
|
||||||
char helper_fw_name[IF_SPI_FW_NAME_MAX];
|
|
||||||
char main_fw_name[IF_SPI_FW_NAME_MAX];
|
|
||||||
|
|
||||||
/* The card ID and card revision, as reported by the hardware. */
|
/* The card ID and card revision, as reported by the hardware. */
|
||||||
u16 card_id;
|
u16 card_id;
|
||||||
u8 card_rev;
|
u8 card_rev;
|
||||||
|
@ -70,10 +67,28 @@ static void free_if_spi_card(struct if_spi_card *card)
|
||||||
kfree(card);
|
kfree(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct chip_ident chip_id_to_device_name[] = {
|
#define MODEL_8385 0x04
|
||||||
{ .chip_id = 0x04, .name = 8385 },
|
#define MODEL_8686 0x0b
|
||||||
{ .chip_id = 0x0b, .name = 8686 },
|
#define MODEL_8688 0x10
|
||||||
|
|
||||||
|
static const struct lbs_fw_table fw_table[] = {
|
||||||
|
{ MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
|
||||||
|
{ MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
|
||||||
|
{ MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
|
||||||
|
{ MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
|
||||||
|
{ MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
|
||||||
|
{ 0, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8385.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8686.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/gspi8688.bin");
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPI Interface Unit Routines
|
* SPI Interface Unit Routines
|
||||||
|
@ -399,26 +414,20 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
|
||||||
* Firmware Loading
|
* Firmware Loading
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int if_spi_prog_helper_firmware(struct if_spi_card *card)
|
static int if_spi_prog_helper_firmware(struct if_spi_card *card,
|
||||||
|
const struct firmware *firmware)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
const struct firmware *firmware = NULL;
|
|
||||||
int bytes_remaining;
|
int bytes_remaining;
|
||||||
const u8 *fw;
|
const u8 *fw;
|
||||||
u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
|
u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
|
||||||
struct spi_device *spi = card->spi;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SPI);
|
lbs_deb_enter(LBS_DEB_SPI);
|
||||||
|
|
||||||
err = spu_set_interrupt_mode(card, 1, 0);
|
err = spu_set_interrupt_mode(card, 1, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
/* Get helper firmware image */
|
|
||||||
err = request_firmware(&firmware, card->helper_fw_name, &spi->dev);
|
|
||||||
if (err) {
|
|
||||||
lbs_pr_err("request_firmware failed with err = %d\n", err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
bytes_remaining = firmware->size;
|
bytes_remaining = firmware->size;
|
||||||
fw = firmware->data;
|
fw = firmware->data;
|
||||||
|
|
||||||
|
@ -429,13 +438,13 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
|
||||||
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
|
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
|
||||||
HELPER_FW_LOAD_CHUNK_SZ);
|
HELPER_FW_LOAD_CHUNK_SZ);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
|
|
||||||
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
|
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
|
||||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
|
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
|
||||||
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
|
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
|
|
||||||
/* Feed the data into the command read/write port reg
|
/* Feed the data into the command read/write port reg
|
||||||
* in chunks of 64 bytes */
|
* in chunks of 64 bytes */
|
||||||
|
@ -446,16 +455,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
|
||||||
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
|
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
|
||||||
temp, HELPER_FW_LOAD_CHUNK_SZ);
|
temp, HELPER_FW_LOAD_CHUNK_SZ);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
|
|
||||||
/* Interrupt the boot code */
|
/* Interrupt the boot code */
|
||||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
||||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
|
bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
|
||||||
fw += HELPER_FW_LOAD_CHUNK_SZ;
|
fw += HELPER_FW_LOAD_CHUNK_SZ;
|
||||||
}
|
}
|
||||||
|
@ -465,18 +474,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
|
||||||
* bootloader. This completes the helper download. */
|
* bootloader. This completes the helper download. */
|
||||||
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
|
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
|
||||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||||
goto release_firmware;
|
goto out;
|
||||||
|
|
||||||
lbs_deb_spi("waiting for helper to boot...\n");
|
lbs_deb_spi("waiting for helper to boot...\n");
|
||||||
|
|
||||||
release_firmware:
|
|
||||||
release_firmware(firmware);
|
|
||||||
out:
|
out:
|
||||||
if (err)
|
if (err)
|
||||||
lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
|
lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
|
||||||
|
@ -523,13 +530,12 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
static int if_spi_prog_main_firmware(struct if_spi_card *card,
|
||||||
|
const struct firmware *firmware)
|
||||||
{
|
{
|
||||||
int len, prev_len;
|
int len, prev_len;
|
||||||
int bytes, crc_err = 0, err = 0;
|
int bytes, crc_err = 0, err = 0;
|
||||||
const struct firmware *firmware = NULL;
|
|
||||||
const u8 *fw;
|
const u8 *fw;
|
||||||
struct spi_device *spi = card->spi;
|
|
||||||
u16 num_crc_errs;
|
u16 num_crc_errs;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SPI);
|
lbs_deb_enter(LBS_DEB_SPI);
|
||||||
|
@ -538,19 +544,11 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Get firmware image */
|
|
||||||
err = request_firmware(&firmware, card->main_fw_name, &spi->dev);
|
|
||||||
if (err) {
|
|
||||||
lbs_pr_err("%s: can't get firmware '%s' from kernel. "
|
|
||||||
"err = %d\n", __func__, card->main_fw_name, err);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
|
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
lbs_pr_err("%s: timed out waiting for initial "
|
lbs_pr_err("%s: timed out waiting for initial "
|
||||||
"scratch reg = 0\n", __func__);
|
"scratch reg = 0\n", __func__);
|
||||||
goto release_firmware;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_crc_errs = 0;
|
num_crc_errs = 0;
|
||||||
|
@ -560,7 +558,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
||||||
while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
|
while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
err = len;
|
err = len;
|
||||||
goto release_firmware;
|
goto out;
|
||||||
}
|
}
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
/* If there are no more bytes left, we would normally
|
/* If there are no more bytes left, we would normally
|
||||||
|
@ -575,7 +573,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
||||||
lbs_pr_err("Too many CRC errors encountered "
|
lbs_pr_err("Too many CRC errors encountered "
|
||||||
"in firmware load.\n");
|
"in firmware load.\n");
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto release_firmware;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Previous transfer succeeded. Advance counters. */
|
/* Previous transfer succeeded. Advance counters. */
|
||||||
|
@ -590,15 +588,15 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
||||||
|
|
||||||
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
|
err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
|
||||||
card->cmd_buffer, len);
|
card->cmd_buffer, len);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
|
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
|
||||||
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
|
||||||
if (err)
|
if (err)
|
||||||
goto release_firmware;
|
goto out;
|
||||||
prev_len = len;
|
prev_len = len;
|
||||||
}
|
}
|
||||||
if (bytes > prev_len) {
|
if (bytes > prev_len) {
|
||||||
|
@ -611,12 +609,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
|
||||||
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
|
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
|
||||||
if (err) {
|
if (err) {
|
||||||
lbs_pr_err("failed to confirm the firmware download\n");
|
lbs_pr_err("failed to confirm the firmware download\n");
|
||||||
goto release_firmware;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
release_firmware:
|
|
||||||
release_firmware(firmware);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (err)
|
if (err)
|
||||||
lbs_pr_err("failed to load firmware (err=%d)\n", err);
|
lbs_pr_err("failed to load firmware (err=%d)\n", err);
|
||||||
|
@ -800,14 +795,16 @@ static int lbs_spi_thread(void *data)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY)
|
if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
|
||||||
err = if_spi_c2h_cmd(card);
|
err = if_spi_c2h_cmd(card);
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err;
|
||||||
if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY)
|
}
|
||||||
|
if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
|
||||||
err = if_spi_c2h_data(card);
|
err = if_spi_c2h_data(card);
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* workaround: in PS mode, the card does not set the Command
|
/* workaround: in PS mode, the card does not set the Command
|
||||||
* Download Ready bit, but it sets TX Download Ready. */
|
* Download Ready bit, but it sets TX Download Ready. */
|
||||||
|
@ -886,37 +883,16 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
|
||||||
* SPI callbacks
|
* SPI callbacks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int if_spi_calculate_fw_names(u16 card_id,
|
|
||||||
char *helper_fw, char *main_fw)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ARRAY_SIZE(chip_id_to_device_name); ++i) {
|
|
||||||
if (card_id == chip_id_to_device_name[i].chip_id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == ARRAY_SIZE(chip_id_to_device_name)) {
|
|
||||||
lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id);
|
|
||||||
return -EAFNOSUPPORT;
|
|
||||||
}
|
|
||||||
snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin",
|
|
||||||
chip_id_to_device_name[i].name);
|
|
||||||
snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin",
|
|
||||||
chip_id_to_device_name[i].name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
|
|
||||||
MODULE_FIRMWARE("libertas/gspi8385.bin");
|
|
||||||
MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
|
|
||||||
MODULE_FIRMWARE("libertas/gspi8686.bin");
|
|
||||||
|
|
||||||
static int __devinit if_spi_probe(struct spi_device *spi)
|
static int __devinit if_spi_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct if_spi_card *card;
|
struct if_spi_card *card;
|
||||||
struct lbs_private *priv = NULL;
|
struct lbs_private *priv = NULL;
|
||||||
struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
|
struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
|
||||||
int err = 0;
|
int err = 0, i;
|
||||||
u32 scratch;
|
u32 scratch;
|
||||||
struct sched_param param = { .sched_priority = 1 };
|
struct sched_param param = { .sched_priority = 1 };
|
||||||
|
const struct firmware *helper = NULL;
|
||||||
|
const struct firmware *mainfw = NULL;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SPI);
|
lbs_deb_enter(LBS_DEB_SPI);
|
||||||
|
|
||||||
|
@ -961,10 +937,25 @@ static int __devinit if_spi_probe(struct spi_device *spi)
|
||||||
lbs_deb_spi("Firmware is already loaded for "
|
lbs_deb_spi("Firmware is already loaded for "
|
||||||
"Marvell WLAN 802.11 adapter\n");
|
"Marvell WLAN 802.11 adapter\n");
|
||||||
else {
|
else {
|
||||||
err = if_spi_calculate_fw_names(card->card_id,
|
/* Check if we support this card */
|
||||||
card->helper_fw_name, card->main_fw_name);
|
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
|
||||||
if (err)
|
if (card->card_id == fw_table[i].model)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == ARRAY_SIZE(fw_table)) {
|
||||||
|
lbs_pr_err("Unsupported chip_id: 0x%02x\n",
|
||||||
|
card->card_id);
|
||||||
|
err = -ENODEV;
|
||||||
goto free_card;
|
goto free_card;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lbs_get_firmware(&card->spi->dev, NULL, NULL,
|
||||||
|
card->card_id, &fw_table[0], &helper,
|
||||||
|
&mainfw);
|
||||||
|
if (err) {
|
||||||
|
lbs_pr_err("failed to find firmware (%d)\n", err);
|
||||||
|
goto free_card;
|
||||||
|
}
|
||||||
|
|
||||||
lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
|
lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
|
||||||
"(chip_id = 0x%04x, chip_rev = 0x%02x) "
|
"(chip_id = 0x%04x, chip_rev = 0x%02x) "
|
||||||
|
@ -973,10 +964,10 @@ static int __devinit if_spi_probe(struct spi_device *spi)
|
||||||
card->card_id, card->card_rev,
|
card->card_id, card->card_rev,
|
||||||
spi->master->bus_num, spi->chip_select,
|
spi->master->bus_num, spi->chip_select,
|
||||||
spi->max_speed_hz);
|
spi->max_speed_hz);
|
||||||
err = if_spi_prog_helper_firmware(card);
|
err = if_spi_prog_helper_firmware(card, helper);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_card;
|
goto free_card;
|
||||||
err = if_spi_prog_main_firmware(card);
|
err = if_spi_prog_main_firmware(card, mainfw);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_card;
|
goto free_card;
|
||||||
lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
|
lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
|
||||||
|
@ -1044,6 +1035,11 @@ remove_card:
|
||||||
free_card:
|
free_card:
|
||||||
free_if_spi_card(card);
|
free_if_spi_card(card);
|
||||||
out:
|
out:
|
||||||
|
if (helper)
|
||||||
|
release_firmware(helper);
|
||||||
|
if (mainfw)
|
||||||
|
release_firmware(mainfw);
|
||||||
|
|
||||||
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
|
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,6 @@
|
||||||
|
|
||||||
#define IF_SPI_FW_NAME_MAX 30
|
#define IF_SPI_FW_NAME_MAX 30
|
||||||
|
|
||||||
struct chip_ident {
|
|
||||||
u16 chip_id;
|
|
||||||
u16 name;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_MAIN_FW_LOAD_CRC_ERR 10
|
#define MAX_MAIN_FW_LOAD_CRC_ERR 10
|
||||||
|
|
||||||
/* Chunk size when loading the helper firmware */
|
/* Chunk size when loading the helper firmware */
|
||||||
|
|
|
@ -26,15 +26,25 @@
|
||||||
|
|
||||||
#define MESSAGE_HEADER_LEN 4
|
#define MESSAGE_HEADER_LEN 4
|
||||||
|
|
||||||
static char *lbs_fw_name = "usb8388.bin";
|
static char *lbs_fw_name = NULL;
|
||||||
module_param_named(fw_name, lbs_fw_name, charp, 0644);
|
module_param_named(fw_name, lbs_fw_name, charp, 0644);
|
||||||
|
|
||||||
|
MODULE_FIRMWARE("libertas/usb8388_v9.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/usb8388_v5.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/usb8388.bin");
|
||||||
|
MODULE_FIRMWARE("libertas/usb8682.bin");
|
||||||
MODULE_FIRMWARE("usb8388.bin");
|
MODULE_FIRMWARE("usb8388.bin");
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MODEL_UNKNOWN = 0x0,
|
||||||
|
MODEL_8388 = 0x1,
|
||||||
|
MODEL_8682 = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
static struct usb_device_id if_usb_table[] = {
|
static struct usb_device_id if_usb_table[] = {
|
||||||
/* Enter the device signature inside */
|
/* Enter the device signature inside */
|
||||||
{ USB_DEVICE(0x1286, 0x2001) },
|
{ USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
|
||||||
{ USB_DEVICE(0x05a3, 0x8388) },
|
{ USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
|
||||||
{} /* Terminating entry */
|
{} /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +76,8 @@ static ssize_t if_usb_firmware_set(struct device *dev,
|
||||||
struct if_usb_card *cardp = priv->card;
|
struct if_usb_card *cardp = priv->card;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
BUG_ON(buf == NULL);
|
||||||
|
|
||||||
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
|
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return count;
|
return count;
|
||||||
|
@ -91,6 +103,8 @@ static ssize_t if_usb_boot2_set(struct device *dev,
|
||||||
struct if_usb_card *cardp = priv->card;
|
struct if_usb_card *cardp = priv->card;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
BUG_ON(buf == NULL);
|
||||||
|
|
||||||
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
|
ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return count;
|
return count;
|
||||||
|
@ -244,6 +258,7 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||||
init_waitqueue_head(&cardp->fw_wq);
|
init_waitqueue_head(&cardp->fw_wq);
|
||||||
|
|
||||||
cardp->udev = udev;
|
cardp->udev = udev;
|
||||||
|
cardp->model = (uint32_t) id->driver_info;
|
||||||
iface_desc = intf->cur_altsetting;
|
iface_desc = intf->cur_altsetting;
|
||||||
|
|
||||||
lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
|
lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
|
||||||
|
@ -924,6 +939,38 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* table of firmware file names */
|
||||||
|
static const struct {
|
||||||
|
u32 model;
|
||||||
|
const char *fwname;
|
||||||
|
} fw_table[] = {
|
||||||
|
{ MODEL_8388, "libertas/usb8388_v9.bin" },
|
||||||
|
{ MODEL_8388, "libertas/usb8388_v5.bin" },
|
||||||
|
{ MODEL_8388, "libertas/usb8388.bin" },
|
||||||
|
{ MODEL_8388, "usb8388.bin" },
|
||||||
|
{ MODEL_8682, "libertas/usb8682.bin" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_fw(struct if_usb_card *cardp, const char *fwname)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Try user-specified firmware first */
|
||||||
|
if (fwname)
|
||||||
|
return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
|
||||||
|
|
||||||
|
/* Otherwise search for firmware to use */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
|
||||||
|
if (fw_table[i].model != cardp->model)
|
||||||
|
continue;
|
||||||
|
if (request_firmware(&cardp->fw, fw_table[i].fwname,
|
||||||
|
&cardp->udev->dev) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
static int __if_usb_prog_firmware(struct if_usb_card *cardp,
|
static int __if_usb_prog_firmware(struct if_usb_card *cardp,
|
||||||
const char *fwname, int cmd)
|
const char *fwname, int cmd)
|
||||||
{
|
{
|
||||||
|
@ -933,10 +980,9 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_USB);
|
lbs_deb_enter(LBS_DEB_USB);
|
||||||
|
|
||||||
ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
|
ret = get_fw(cardp, fwname);
|
||||||
if (ret < 0) {
|
if (ret) {
|
||||||
lbs_pr_err("request_firmware() failed with %#x\n", ret);
|
lbs_pr_err("failed to find firmware (%d)\n", ret);
|
||||||
lbs_pr_err("firmware %s not found\n", fwname);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct bootcmdresp
|
||||||
/** USB card description structure*/
|
/** USB card description structure*/
|
||||||
struct if_usb_card {
|
struct if_usb_card {
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
|
uint32_t model; /* MODEL_* */
|
||||||
struct urb *rx_urb, *tx_urb;
|
struct urb *rx_urb, *tx_urb;
|
||||||
struct lbs_private *priv;
|
struct lbs_private *priv;
|
||||||
|
|
||||||
|
|
|
@ -1047,6 +1047,111 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
|
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves two-stage firmware
|
||||||
|
*
|
||||||
|
* @param dev A pointer to device structure
|
||||||
|
* @param user_helper User-defined helper firmware file
|
||||||
|
* @param user_mainfw User-defined main firmware file
|
||||||
|
* @param card_model Bus-specific card model ID used to filter firmware table
|
||||||
|
* elements
|
||||||
|
* @param fw_table Table of firmware file names and device model numbers
|
||||||
|
* terminated by an entry with a NULL helper name
|
||||||
|
* @param helper On success, the helper firmware; caller must free
|
||||||
|
* @param mainfw On success, the main firmware; caller must free
|
||||||
|
*
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int lbs_get_firmware(struct device *dev, const char *user_helper,
|
||||||
|
const char *user_mainfw, u32 card_model,
|
||||||
|
const struct lbs_fw_table *fw_table,
|
||||||
|
const struct firmware **helper,
|
||||||
|
const struct firmware **mainfw)
|
||||||
|
{
|
||||||
|
const struct lbs_fw_table *iter;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
BUG_ON(helper == NULL);
|
||||||
|
BUG_ON(mainfw == NULL);
|
||||||
|
|
||||||
|
/* Try user-specified firmware first */
|
||||||
|
if (user_helper) {
|
||||||
|
ret = request_firmware(helper, user_helper, dev);
|
||||||
|
if (ret) {
|
||||||
|
lbs_pr_err("couldn't find helper firmware %s",
|
||||||
|
user_helper);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user_mainfw) {
|
||||||
|
ret = request_firmware(mainfw, user_mainfw, dev);
|
||||||
|
if (ret) {
|
||||||
|
lbs_pr_err("couldn't find main firmware %s",
|
||||||
|
user_mainfw);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*helper && *mainfw)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Otherwise search for firmware to use. If neither the helper or
|
||||||
|
* the main firmware were specified by the user, then we need to
|
||||||
|
* make sure that found helper & main are from the same entry in
|
||||||
|
* fw_table.
|
||||||
|
*/
|
||||||
|
iter = fw_table;
|
||||||
|
while (iter && iter->helper) {
|
||||||
|
if (iter->model != card_model)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
if (*helper == NULL) {
|
||||||
|
ret = request_firmware(helper, iter->helper, dev);
|
||||||
|
if (ret)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
/* If the device has one-stage firmware (ie cf8305) and
|
||||||
|
* we've got it then we don't need to bother with the
|
||||||
|
* main firmware.
|
||||||
|
*/
|
||||||
|
if (iter->fwname == NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*mainfw == NULL) {
|
||||||
|
ret = request_firmware(mainfw, iter->fwname, dev);
|
||||||
|
if (ret && !user_helper) {
|
||||||
|
/* Clear the helper if it wasn't user-specified
|
||||||
|
* and the main firmware load failed, to ensure
|
||||||
|
* we don't have mismatched firmware pairs.
|
||||||
|
*/
|
||||||
|
release_firmware(*helper);
|
||||||
|
*helper = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*helper && *mainfw)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
next:
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* Failed */
|
||||||
|
if (*helper) {
|
||||||
|
release_firmware(*helper);
|
||||||
|
*helper = NULL;
|
||||||
|
}
|
||||||
|
if (*mainfw) {
|
||||||
|
release_firmware(*mainfw);
|
||||||
|
*mainfw = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(lbs_get_firmware);
|
||||||
|
|
||||||
static int __init lbs_init_module(void)
|
static int __init lbs_init_module(void)
|
||||||
{
|
{
|
||||||
lbs_deb_enter(LBS_DEB_MAIN);
|
lbs_deb_enter(LBS_DEB_MAIN);
|
||||||
|
|
|
@ -54,7 +54,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
|
||||||
/**
|
/**
|
||||||
* if_usb_wrike_bulk_callback - call back to handle URB status
|
* if_usb_wrike_bulk_callback - call back to handle URB status
|
||||||
*
|
*
|
||||||
* @param urb pointer to urb structure
|
* @param urb pointer to urb structure
|
||||||
*/
|
*/
|
||||||
static void if_usb_write_bulk_callback(struct urb *urb)
|
static void if_usb_write_bulk_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
|
@ -178,16 +178,19 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||||
le16_to_cpu(endpoint->wMaxPacketSize);
|
le16_to_cpu(endpoint->wMaxPacketSize);
|
||||||
cardp->ep_in = usb_endpoint_num(endpoint);
|
cardp->ep_in = usb_endpoint_num(endpoint);
|
||||||
|
|
||||||
lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
|
lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n",
|
||||||
lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
|
cardp->ep_in);
|
||||||
|
lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n",
|
||||||
|
cardp->ep_in_size);
|
||||||
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||||
cardp->ep_out_size =
|
cardp->ep_out_size =
|
||||||
le16_to_cpu(endpoint->wMaxPacketSize);
|
le16_to_cpu(endpoint->wMaxPacketSize);
|
||||||
cardp->ep_out = usb_endpoint_num(endpoint);
|
cardp->ep_out = usb_endpoint_num(endpoint);
|
||||||
|
|
||||||
lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
|
lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n",
|
||||||
|
cardp->ep_out);
|
||||||
lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
|
lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
|
||||||
cardp->ep_out_size);
|
cardp->ep_out_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cardp->ep_out_size || !cardp->ep_in_size) {
|
if (!cardp->ep_out_size || !cardp->ep_in_size) {
|
||||||
|
@ -318,10 +321,12 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
|
||||||
|
|
||||||
if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
|
if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
|
lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
|
lbtf_deb_usb2(&cardp->udev->dev,
|
||||||
cardp->fwseqnum, cardp->totalbytes);
|
"seqnum = %d totalbytes = %d\n",
|
||||||
|
cardp->fwseqnum, cardp->totalbytes);
|
||||||
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
|
} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
|
lbtf_deb_usb2(&cardp->udev->dev,
|
||||||
|
"Host has finished FW downloading\n");
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
|
lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
|
||||||
|
|
||||||
/* Host has finished FW downloading
|
/* Host has finished FW downloading
|
||||||
|
@ -367,7 +372,7 @@ EXPORT_SYMBOL_GPL(if_usb_reset_device);
|
||||||
/**
|
/**
|
||||||
* usb_tx_block - transfer data to the device
|
* usb_tx_block - transfer data to the device
|
||||||
*
|
*
|
||||||
* @priv pointer to struct lbtf_private
|
* @priv pointer to struct lbtf_private
|
||||||
* @payload pointer to payload data
|
* @payload pointer to payload data
|
||||||
* @nb data length
|
* @nb data length
|
||||||
* @data non-zero for data, zero for commands
|
* @data non-zero for data, zero for commands
|
||||||
|
@ -400,7 +405,8 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
|
||||||
urb->transfer_flags |= URB_ZERO_PACKET;
|
urb->transfer_flags |= URB_ZERO_PACKET;
|
||||||
|
|
||||||
if (usb_submit_urb(urb, GFP_ATOMIC)) {
|
if (usb_submit_urb(urb, GFP_ATOMIC)) {
|
||||||
lbtf_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
|
"usb_submit_urb failed: %d\n", ret);
|
||||||
goto tx_ret;
|
goto tx_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,10 +444,12 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
|
||||||
|
|
||||||
cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
|
cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
|
||||||
|
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
|
lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n",
|
||||||
|
cardp->rx_urb);
|
||||||
ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
|
ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
lbtf_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
|
"Submit Rx URB failed: %d\n", ret);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
cardp->rx_skb = NULL;
|
cardp->rx_skb = NULL;
|
||||||
lbtf_deb_leave(LBTF_DEB_USB);
|
lbtf_deb_leave(LBTF_DEB_USB);
|
||||||
|
@ -522,14 +530,14 @@ static void if_usb_receive_fwload(struct urb *urb)
|
||||||
}
|
}
|
||||||
} else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
|
} else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
|
||||||
pr_info("boot cmd response cmd_tag error (%d)\n",
|
pr_info("boot cmd response cmd_tag error (%d)\n",
|
||||||
bcmdresp.cmd);
|
bcmdresp.cmd);
|
||||||
} else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
|
} else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
|
||||||
pr_info("boot cmd response result error (%d)\n",
|
pr_info("boot cmd response result error (%d)\n",
|
||||||
bcmdresp.result);
|
bcmdresp.result);
|
||||||
} else {
|
} else {
|
||||||
cardp->bootcmdresp = 1;
|
cardp->bootcmdresp = 1;
|
||||||
lbtf_deb_usbd(&cardp->udev->dev,
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
"Received valid boot command response\n");
|
"Received valid boot command response\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -541,19 +549,23 @@ static void if_usb_receive_fwload(struct urb *urb)
|
||||||
syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
|
syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
if (!syncfwheader) {
|
if (!syncfwheader) {
|
||||||
lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
|
"Failure to allocate syncfwheader\n");
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
lbtf_deb_leave(LBTF_DEB_USB);
|
lbtf_deb_leave(LBTF_DEB_USB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!syncfwheader->cmd) {
|
if (!syncfwheader->cmd) {
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
|
lbtf_deb_usb2(&cardp->udev->dev,
|
||||||
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
|
"FW received Blk with correct CRC\n");
|
||||||
le32_to_cpu(syncfwheader->seqnum));
|
lbtf_deb_usb2(&cardp->udev->dev,
|
||||||
|
"FW received Blk seqnum = %d\n",
|
||||||
|
le32_to_cpu(syncfwheader->seqnum));
|
||||||
cardp->CRC_OK = 1;
|
cardp->CRC_OK = 1;
|
||||||
} else {
|
} else {
|
||||||
lbtf_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
|
"FW received Blk with CRC error\n");
|
||||||
cardp->CRC_OK = 0;
|
cardp->CRC_OK = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +678,8 @@ static void if_usb_receive(struct urb *urb)
|
||||||
{
|
{
|
||||||
/* Event cause handling */
|
/* Event cause handling */
|
||||||
u32 event_cause = le32_to_cpu(pkt[1]);
|
u32 event_cause = le32_to_cpu(pkt[1]);
|
||||||
lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event_cause);
|
lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n",
|
||||||
|
event_cause);
|
||||||
|
|
||||||
/* Icky undocumented magic special case */
|
/* Icky undocumented magic special case */
|
||||||
if (event_cause & 0xffff0000) {
|
if (event_cause & 0xffff0000) {
|
||||||
|
@ -689,7 +702,7 @@ static void if_usb_receive(struct urb *urb)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
lbtf_deb_usbd(&cardp->udev->dev,
|
lbtf_deb_usbd(&cardp->udev->dev,
|
||||||
"libertastf: unknown command type 0x%X\n", recvtype);
|
"libertastf: unknown command type 0x%X\n", recvtype);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - IBSS mode simulation (Beacon transmission with competition for "air time")
|
* - Add TSF sync and fix IBSS beacon transmission by adding
|
||||||
|
* competition for "air time" at TBTT
|
||||||
* - RX filtering based on filter configuration (data->rx_filter)
|
* - RX filtering based on filter configuration (data->rx_filter)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -620,7 +621,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
|
||||||
hwsim_check_magic(vif);
|
hwsim_check_magic(vif);
|
||||||
|
|
||||||
if (vif->type != NL80211_IFTYPE_AP &&
|
if (vif->type != NL80211_IFTYPE_AP &&
|
||||||
vif->type != NL80211_IFTYPE_MESH_POINT)
|
vif->type != NL80211_IFTYPE_MESH_POINT &&
|
||||||
|
vif->type != NL80211_IFTYPE_ADHOC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
skb = ieee80211_beacon_get(hw, vif);
|
skb = ieee80211_beacon_get(hw, vif);
|
||||||
|
@ -1295,6 +1297,7 @@ static int __init init_mac80211_hwsim(void)
|
||||||
hw->wiphy->interface_modes =
|
hw->wiphy->interface_modes =
|
||||||
BIT(NL80211_IFTYPE_STATION) |
|
BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_AP) |
|
BIT(NL80211_IFTYPE_AP) |
|
||||||
|
BIT(NL80211_IFTYPE_ADHOC) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||||
|
|
||||||
hw->flags = IEEE80211_HW_MFP_CAPABLE |
|
hw->flags = IEEE80211_HW_MFP_CAPABLE |
|
||||||
|
|
|
@ -2,6 +2,7 @@ config P54_COMMON
|
||||||
tristate "Softmac Prism54 support"
|
tristate "Softmac Prism54 support"
|
||||||
depends on MAC80211 && EXPERIMENTAL
|
depends on MAC80211 && EXPERIMENTAL
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
|
select CRC_CCITT
|
||||||
---help---
|
---help---
|
||||||
This is common code for isl38xx/stlc45xx based modules.
|
This is common code for isl38xx/stlc45xx based modules.
|
||||||
This module does nothing by itself - the USB/PCI/SPI front-ends
|
This module does nothing by itself - the USB/PCI/SPI front-ends
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
|
#include <linux/crc-ccitt.h>
|
||||||
|
|
||||||
#include "p54.h"
|
#include "p54.h"
|
||||||
#include "eeprom.h"
|
#include "eeprom.h"
|
||||||
|
@ -540,6 +541,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
||||||
int err;
|
int err;
|
||||||
u8 *end = (u8 *)eeprom + len;
|
u8 *end = (u8 *)eeprom + len;
|
||||||
u16 synth = 0;
|
u16 synth = 0;
|
||||||
|
u16 crc16 = ~0;
|
||||||
|
|
||||||
wrap = (struct eeprom_pda_wrap *) eeprom;
|
wrap = (struct eeprom_pda_wrap *) eeprom;
|
||||||
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
||||||
|
@ -655,16 +657,29 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PDR_END:
|
case PDR_END:
|
||||||
/* make it overrun */
|
crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
|
||||||
entry_len = len;
|
if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
|
||||||
|
wiphy_err(dev->wiphy, "eeprom failed checksum "
|
||||||
|
"test!\n");
|
||||||
|
err = -ENOMSG;
|
||||||
|
goto err;
|
||||||
|
} else {
|
||||||
|
goto good_eeprom;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = (void *)entry + (entry_len + 1)*2;
|
crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
|
||||||
|
entry = (void *)entry + (entry_len + 1) * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
|
||||||
|
err = -ENODATA;
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
good_eeprom:
|
||||||
if (!synth || !priv->iq_autocal || !priv->output_limit ||
|
if (!synth || !priv->iq_autocal || !priv->output_limit ||
|
||||||
!priv->curve_data) {
|
!priv->curve_data) {
|
||||||
wiphy_err(dev->wiphy,
|
wiphy_err(dev->wiphy,
|
||||||
|
|
|
@ -123,10 +123,14 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
||||||
bootrec = (struct bootrec *)&bootrec->data[len];
|
bootrec = (struct bootrec *)&bootrec->data[len];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fw_version)
|
if (fw_version) {
|
||||||
wiphy_info(priv->hw->wiphy,
|
wiphy_info(priv->hw->wiphy,
|
||||||
"FW rev %s - Softmac protocol %x.%x\n",
|
"FW rev %s - Softmac protocol %x.%x\n",
|
||||||
fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
|
fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
|
||||||
|
snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
|
||||||
|
"%s - %x.%x", fw_version,
|
||||||
|
priv->fw_var >> 8, priv->fw_var & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->fw_var < 0x500)
|
if (priv->fw_var < 0x500)
|
||||||
wiphy_info(priv->hw->wiphy,
|
wiphy_info(priv->hw->wiphy,
|
||||||
|
|
|
@ -429,8 +429,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
|
||||||
|
|
||||||
mutex_lock(&priv->conf_mutex);
|
mutex_lock(&priv->conf_mutex);
|
||||||
if (cmd == SET_KEY) {
|
if (cmd == SET_KEY) {
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
|
if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
|
||||||
BR_DESC_PRIV_CAP_TKIP))) {
|
BR_DESC_PRIV_CAP_TKIP))) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
|
@ -439,7 +439,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
algo = P54_CRYPTO_TKIPMICHAEL;
|
algo = P54_CRYPTO_TKIPMICHAEL;
|
||||||
break;
|
break;
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
|
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -447,7 +448,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||||
algo = P54_CRYPTO_WEP;
|
algo = P54_CRYPTO_WEP;
|
||||||
break;
|
break;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
|
if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
|
@ -671,7 +671,7 @@ static unsigned char p54spi_eeprom[] = {
|
||||||
0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
|
0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
|
||||||
|
|
||||||
0x02, 0x00, 0x00, 0x00, /* PDR_END */
|
0x02, 0x00, 0x00, 0x00, /* PDR_END */
|
||||||
0xa8, 0xf5 /* bogus data */
|
0x67, 0x99,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* P54SPI_EEPROM_H */
|
#endif /* P54SPI_EEPROM_H */
|
||||||
|
|
|
@ -683,14 +683,15 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 p54_convert_algo(enum ieee80211_key_alg alg)
|
static u8 p54_convert_algo(u32 cipher)
|
||||||
{
|
{
|
||||||
switch (alg) {
|
switch (cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
return P54_CRYPTO_WEP;
|
return P54_CRYPTO_WEP;
|
||||||
case ALG_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
return P54_CRYPTO_TKIPMICHAEL;
|
return P54_CRYPTO_TKIPMICHAEL;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
return P54_CRYPTO_AESCCMP;
|
return P54_CRYPTO_AESCCMP;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -731,7 +732,7 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||||
|
|
||||||
if (info->control.hw_key) {
|
if (info->control.hw_key) {
|
||||||
crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
|
crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
|
||||||
if (info->control.hw_key->alg == ALG_TKIP) {
|
if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||||
u8 *iv = (u8 *)(skb->data + crypt_offset);
|
u8 *iv = (u8 *)(skb->data + crypt_offset);
|
||||||
/*
|
/*
|
||||||
* The firmware excepts that the IV has to have
|
* The firmware excepts that the IV has to have
|
||||||
|
@ -827,10 +828,10 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||||
hdr->tries = ridx;
|
hdr->tries = ridx;
|
||||||
txhdr->rts_rate_idx = 0;
|
txhdr->rts_rate_idx = 0;
|
||||||
if (info->control.hw_key) {
|
if (info->control.hw_key) {
|
||||||
txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
|
txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
|
||||||
txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
|
txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
|
||||||
memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
|
memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
|
||||||
if (info->control.hw_key->alg == ALG_TKIP) {
|
if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||||
/* reserve space for the MIC key */
|
/* reserve space for the MIC key */
|
||||||
len += 8;
|
len += 8;
|
||||||
memcpy(skb_put(skb, 8), &(info->control.hw_key->key
|
memcpy(skb_put(skb, 8), &(info->control.hw_key->key
|
||||||
|
|
|
@ -3234,7 +3234,7 @@ prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case PRISM54_HOSTAPD:
|
case PRISM54_HOSTAPD:
|
||||||
if (!capable(CAP_NET_ADMIN))
|
if (!capable(CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
ret = prism54_hostapd(ndev, &wrq->u.data);
|
ret = prism54_hostapd(ndev, &wrq->u.data);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,7 +355,9 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
|
||||||
* it is known that not work at least on some hardware.
|
* it is known that not work at least on some hardware.
|
||||||
* SW crypto will be used in that case.
|
* SW crypto will be used in that case.
|
||||||
*/
|
*/
|
||||||
if (key->alg == ALG_WEP && key->keyidx != 0)
|
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||||
|
key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
|
||||||
|
key->keyidx != 0)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1318,7 +1318,25 @@
|
||||||
#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
|
#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TX_STA_FIFO: TX Result for specific PID status fifo register
|
* TX_STA_FIFO: TX Result for specific PID status fifo register.
|
||||||
|
*
|
||||||
|
* This register is implemented as FIFO with 16 entries in the HW. Each
|
||||||
|
* register read fetches the next tx result. If the FIFO is full because
|
||||||
|
* it wasn't read fast enough after the according interrupt (TX_FIFO_STATUS)
|
||||||
|
* triggered, the hw seems to simply drop further tx results.
|
||||||
|
*
|
||||||
|
* VALID: 1: this tx result is valid
|
||||||
|
* 0: no valid tx result -> driver should stop reading
|
||||||
|
* PID_TYPE: The PID latched from the PID field in the TXWI, can be used
|
||||||
|
* to match a frame with its tx result (even though the PID is
|
||||||
|
* only 4 bits wide).
|
||||||
|
* TX_SUCCESS: Indicates tx success (1) or failure (0)
|
||||||
|
* TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0)
|
||||||
|
* TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0)
|
||||||
|
* WCID: The wireless client ID.
|
||||||
|
* MCS: The tx rate used during the last transmission of this frame, be it
|
||||||
|
* successful or not.
|
||||||
|
* PHYMODE: The phymode used for the transmission.
|
||||||
*/
|
*/
|
||||||
#define TX_STA_FIFO 0x1718
|
#define TX_STA_FIFO 0x1718
|
||||||
#define TX_STA_FIFO_VALID FIELD32(0x00000001)
|
#define TX_STA_FIFO_VALID FIELD32(0x00000001)
|
||||||
|
@ -1945,6 +1963,13 @@ struct mac_iveiv_entry {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Word1
|
* Word1
|
||||||
|
* ACK: 0: No Ack needed, 1: Ack needed
|
||||||
|
* NSEQ: 0: Don't assign hw sequence number, 1: Assign hw sequence number
|
||||||
|
* BW_WIN_SIZE: BA windows size of the recipient
|
||||||
|
* WIRELESS_CLI_ID: Client ID for WCID table access
|
||||||
|
* MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame
|
||||||
|
* PACKETID: Will be latched into the TX_STA_FIFO register once the according
|
||||||
|
* frame was processed. 0: Don't report tx status for this frame.
|
||||||
*/
|
*/
|
||||||
#define TXWI_W1_ACK FIELD32(0x00000001)
|
#define TXWI_W1_ACK FIELD32(0x00000001)
|
||||||
#define TXWI_W1_NSEQ FIELD32(0x00000002)
|
#define TXWI_W1_NSEQ FIELD32(0x00000002)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
|
||||||
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
|
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
|
||||||
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
|
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
|
||||||
|
@ -427,8 +428,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2800_load_firmware);
|
EXPORT_SYMBOL_GPL(rt2800_load_firmware);
|
||||||
|
|
||||||
void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
|
void rt2800_write_tx_data(struct queue_entry *entry,
|
||||||
|
struct txentry_desc *txdesc)
|
||||||
{
|
{
|
||||||
|
__le32 *txwi = rt2800_drv_get_txwi(entry);
|
||||||
u32 word;
|
u32 word;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -437,7 +440,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
|
||||||
rt2x00_desc_read(txwi, 0, &word);
|
rt2x00_desc_read(txwi, 0, &word);
|
||||||
rt2x00_set_field32(&word, TXWI_W0_FRAG,
|
rt2x00_set_field32(&word, TXWI_W0_FRAG,
|
||||||
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
|
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
|
||||||
rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
|
rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
|
||||||
|
test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
|
||||||
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
|
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
|
||||||
rt2x00_set_field32(&word, TXWI_W0_TS,
|
rt2x00_set_field32(&word, TXWI_W0_TS,
|
||||||
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
|
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
|
||||||
|
@ -478,7 +482,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
|
||||||
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
|
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
|
||||||
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
|
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2800_write_txwi);
|
EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
|
||||||
|
|
||||||
static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
|
static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
|
||||||
{
|
{
|
||||||
|
@ -490,7 +494,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
|
||||||
u8 offset1;
|
u8 offset1;
|
||||||
u8 offset2;
|
u8 offset2;
|
||||||
|
|
||||||
if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
|
if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
|
||||||
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
|
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
|
||||||
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
|
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
|
||||||
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
|
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
|
||||||
|
@ -569,6 +573,122 @@ void rt2800_process_rxwi(struct queue_entry *entry,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
|
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
|
||||||
|
|
||||||
|
void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
struct data_queue *queue;
|
||||||
|
struct queue_entry *entry;
|
||||||
|
__le32 *txwi;
|
||||||
|
struct txdone_entry_desc txdesc;
|
||||||
|
u32 word;
|
||||||
|
u32 reg;
|
||||||
|
int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
|
||||||
|
u16 mcs, real_mcs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
|
||||||
|
* at most X times and also stop processing once the TX_STA_FIFO_VALID
|
||||||
|
* flag is not set anymore.
|
||||||
|
*
|
||||||
|
* The legacy drivers use X=TX_RING_SIZE but state in a comment
|
||||||
|
* that the TX_STA_FIFO stack has a size of 16. We stick to our
|
||||||
|
* tx ring size for now.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < TX_ENTRIES; i++) {
|
||||||
|
rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®);
|
||||||
|
if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
|
||||||
|
break;
|
||||||
|
|
||||||
|
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
|
||||||
|
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
|
||||||
|
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip this entry when it contains an invalid
|
||||||
|
* queue identication number.
|
||||||
|
*/
|
||||||
|
if (pid <= 0 || pid > QID_RX)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
|
||||||
|
if (unlikely(!queue))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inside each queue, we process each entry in a chronological
|
||||||
|
* order. We first check that the queue is not empty.
|
||||||
|
*/
|
||||||
|
entry = NULL;
|
||||||
|
while (!rt2x00queue_empty(queue)) {
|
||||||
|
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
|
||||||
|
if (!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
|
||||||
|
break;
|
||||||
|
|
||||||
|
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry || rt2x00queue_empty(queue))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we got a match by looking at WCID/ACK/PID
|
||||||
|
* fields
|
||||||
|
*/
|
||||||
|
txwi = rt2800_drv_get_txwi(entry);
|
||||||
|
|
||||||
|
rt2x00_desc_read(txwi, 1, &word);
|
||||||
|
tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
|
||||||
|
tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
|
||||||
|
tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
|
||||||
|
|
||||||
|
if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
|
||||||
|
WARNING(rt2x00dev, "invalid TX_STA_FIFO content");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain the status about this packet.
|
||||||
|
*/
|
||||||
|
txdesc.flags = 0;
|
||||||
|
rt2x00_desc_read(txwi, 0, &word);
|
||||||
|
mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
|
||||||
|
mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
|
||||||
|
real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ralink has a retry mechanism using a global fallback
|
||||||
|
* table. We setup this fallback table to try the immediate
|
||||||
|
* lower rate for all rates. In the TX_STA_FIFO, the MCS field
|
||||||
|
* always contains the MCS used for the last transmission, be
|
||||||
|
* it successful or not.
|
||||||
|
*/
|
||||||
|
if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
|
||||||
|
/*
|
||||||
|
* Transmission succeeded. The number of retries is
|
||||||
|
* mcs - real_mcs
|
||||||
|
*/
|
||||||
|
__set_bit(TXDONE_SUCCESS, &txdesc.flags);
|
||||||
|
txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Transmission failed. The number of retries is
|
||||||
|
* always 7 in this case (for a total number of 8
|
||||||
|
* frames sent).
|
||||||
|
*/
|
||||||
|
__set_bit(TXDONE_FAILURE, &txdesc.flags);
|
||||||
|
txdesc.retry = rt2x00dev->long_retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the frame was retried at least once
|
||||||
|
* -> hw used fallback rates
|
||||||
|
*/
|
||||||
|
if (txdesc.retry)
|
||||||
|
__set_bit(TXDONE_FALLBACK, &txdesc.flags);
|
||||||
|
|
||||||
|
rt2x00lib_txdone(entry, &txdesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2800_txdone);
|
||||||
|
|
||||||
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
|
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
|
||||||
{
|
{
|
||||||
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
||||||
|
@ -600,7 +720,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
|
||||||
/*
|
/*
|
||||||
* Add the TXWI for the beacon to the skb.
|
* Add the TXWI for the beacon to the skb.
|
||||||
*/
|
*/
|
||||||
rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
|
rt2800_write_tx_data(entry, txdesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dump beacon to userspace through debugfs.
|
* Dump beacon to userspace through debugfs.
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
|
||||||
|
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
|
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -44,6 +46,7 @@ struct rt2800_ops {
|
||||||
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
|
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
|
||||||
const u8 *data, const size_t len);
|
const u8 *data, const size_t len);
|
||||||
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
|
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
|
||||||
|
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
|
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
|
||||||
|
@ -126,6 +129,13 @@ static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
|
||||||
return rt2800ops->drv_init_registers(rt2x00dev);
|
return rt2800ops->drv_init_registers(rt2x00dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
|
||||||
|
{
|
||||||
|
const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv;
|
||||||
|
|
||||||
|
return rt2800ops->drv_get_txwi(entry);
|
||||||
|
}
|
||||||
|
|
||||||
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
|
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
|
||||||
const u8 command, const u8 token,
|
const u8 command, const u8 token,
|
||||||
const u8 arg0, const u8 arg1);
|
const u8 arg0, const u8 arg1);
|
||||||
|
@ -135,9 +145,12 @@ int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
|
||||||
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
|
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
|
||||||
const u8 *data, const size_t len);
|
const u8 *data, const size_t len);
|
||||||
|
|
||||||
void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
|
void rt2800_write_tx_data(struct queue_entry *entry,
|
||||||
|
struct txentry_desc *txdesc);
|
||||||
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
|
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
|
||||||
|
|
||||||
|
void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
|
||||||
|
|
||||||
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
|
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
|
||||||
|
|
||||||
extern const struct rt2x00debug rt2800_rt2x00debug;
|
extern const struct rt2x00debug rt2800_rt2x00debug;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
|
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
|
||||||
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
|
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
|
||||||
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
|
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
|
||||||
|
@ -566,15 +566,11 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||||
/*
|
/*
|
||||||
* TX descriptor initialization
|
* TX descriptor initialization
|
||||||
*/
|
*/
|
||||||
static void rt2800pci_write_tx_data(struct queue_entry* entry,
|
static __le32 *rt2800pci_get_txwi(struct queue_entry *entry)
|
||||||
struct txentry_desc *txdesc)
|
|
||||||
{
|
{
|
||||||
__le32 *txwi = (__le32 *) entry->skb->data;
|
return (__le32 *) entry->skb->data;
|
||||||
|
|
||||||
rt2800_write_txwi(txwi, txdesc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct txentry_desc *txdesc)
|
struct txentry_desc *txdesc)
|
||||||
|
@ -728,110 +724,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
|
||||||
/*
|
/*
|
||||||
* Interrupt functions.
|
* Interrupt functions.
|
||||||
*/
|
*/
|
||||||
static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
|
|
||||||
{
|
|
||||||
struct data_queue *queue;
|
|
||||||
struct queue_entry *entry;
|
|
||||||
__le32 *txwi;
|
|
||||||
struct txdone_entry_desc txdesc;
|
|
||||||
u32 word;
|
|
||||||
u32 reg;
|
|
||||||
int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
|
|
||||||
u16 mcs, real_mcs;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
|
|
||||||
* at most X times and also stop processing once the TX_STA_FIFO_VALID
|
|
||||||
* flag is not set anymore.
|
|
||||||
*
|
|
||||||
* The legacy drivers use X=TX_RING_SIZE but state in a comment
|
|
||||||
* that the TX_STA_FIFO stack has a size of 16. We stick to our
|
|
||||||
* tx ring size for now.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < TX_ENTRIES; i++) {
|
|
||||||
rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®);
|
|
||||||
if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
|
|
||||||
break;
|
|
||||||
|
|
||||||
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
|
|
||||||
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
|
|
||||||
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip this entry when it contains an invalid
|
|
||||||
* queue identication number.
|
|
||||||
*/
|
|
||||||
if (pid <= 0 || pid > QID_RX)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
|
|
||||||
if (unlikely(!queue))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inside each queue, we process each entry in a chronological
|
|
||||||
* order. We first check that the queue is not empty.
|
|
||||||
*/
|
|
||||||
if (rt2x00queue_empty(queue))
|
|
||||||
continue;
|
|
||||||
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
|
|
||||||
|
|
||||||
/* Check if we got a match by looking at WCID/ACK/PID
|
|
||||||
* fields */
|
|
||||||
txwi = (__le32 *) entry->skb->data;
|
|
||||||
|
|
||||||
rt2x00_desc_read(txwi, 1, &word);
|
|
||||||
tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
|
|
||||||
tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
|
|
||||||
tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
|
|
||||||
|
|
||||||
if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
|
|
||||||
WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Obtain the status about this packet.
|
|
||||||
*/
|
|
||||||
txdesc.flags = 0;
|
|
||||||
rt2x00_desc_read(txwi, 0, &word);
|
|
||||||
mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
|
|
||||||
real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ralink has a retry mechanism using a global fallback
|
|
||||||
* table. We setup this fallback table to try the immediate
|
|
||||||
* lower rate for all rates. In the TX_STA_FIFO, the MCS field
|
|
||||||
* always contains the MCS used for the last transmission, be
|
|
||||||
* it successful or not.
|
|
||||||
*/
|
|
||||||
if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
|
|
||||||
/*
|
|
||||||
* Transmission succeeded. The number of retries is
|
|
||||||
* mcs - real_mcs
|
|
||||||
*/
|
|
||||||
__set_bit(TXDONE_SUCCESS, &txdesc.flags);
|
|
||||||
txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Transmission failed. The number of retries is
|
|
||||||
* always 7 in this case (for a total number of 8
|
|
||||||
* frames sent).
|
|
||||||
*/
|
|
||||||
__set_bit(TXDONE_FAILURE, &txdesc.flags);
|
|
||||||
txdesc.retry = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the frame was retried at least once
|
|
||||||
* -> hw used fallback rates
|
|
||||||
*/
|
|
||||||
if (txdesc.retry)
|
|
||||||
__set_bit(TXDONE_FALLBACK, &txdesc.flags);
|
|
||||||
|
|
||||||
rt2x00lib_txdone(entry, &txdesc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
|
static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
|
||||||
{
|
{
|
||||||
struct ieee80211_conf conf = { .flags = 0 };
|
struct ieee80211_conf conf = { .flags = 0 };
|
||||||
|
@ -867,7 +759,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
|
||||||
* 4 - Tx done interrupt.
|
* 4 - Tx done interrupt.
|
||||||
*/
|
*/
|
||||||
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
|
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
|
||||||
rt2800pci_txdone(rt2x00dev);
|
rt2800_txdone(rt2x00dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 5 - Auto wakeup interrupt.
|
* 5 - Auto wakeup interrupt.
|
||||||
|
@ -1011,6 +903,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
|
||||||
.regbusy_read = rt2x00pci_regbusy_read,
|
.regbusy_read = rt2x00pci_regbusy_read,
|
||||||
.drv_write_firmware = rt2800pci_write_firmware,
|
.drv_write_firmware = rt2800pci_write_firmware,
|
||||||
.drv_init_registers = rt2800pci_init_registers,
|
.drv_init_registers = rt2800pci_init_registers,
|
||||||
|
.drv_get_txwi = rt2800pci_get_txwi,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
|
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
|
||||||
|
@ -1030,7 +923,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
|
||||||
.reset_tuner = rt2800_reset_tuner,
|
.reset_tuner = rt2800_reset_tuner,
|
||||||
.link_tuner = rt2800_link_tuner,
|
.link_tuner = rt2800_link_tuner,
|
||||||
.write_tx_desc = rt2800pci_write_tx_desc,
|
.write_tx_desc = rt2800pci_write_tx_desc,
|
||||||
.write_tx_data = rt2800pci_write_tx_data,
|
.write_tx_data = rt2800_write_tx_data,
|
||||||
.write_beacon = rt2800_write_beacon,
|
.write_beacon = rt2800_write_beacon,
|
||||||
.kick_tx_queue = rt2800pci_kick_tx_queue,
|
.kick_tx_queue = rt2800pci_kick_tx_queue,
|
||||||
.kill_tx_queue = rt2800pci_kill_tx_queue,
|
.kill_tx_queue = rt2800pci_kill_tx_queue,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
|
||||||
|
Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
|
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
|
||||||
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
|
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
|
||||||
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
|
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
|
||||||
|
@ -320,15 +321,14 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
|
||||||
/*
|
/*
|
||||||
* TX descriptor initialization
|
* TX descriptor initialization
|
||||||
*/
|
*/
|
||||||
static void rt2800usb_write_tx_data(struct queue_entry* entry,
|
static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
|
||||||
struct txentry_desc *txdesc)
|
|
||||||
{
|
{
|
||||||
__le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
|
if (entry->queue->qid == QID_BEACON)
|
||||||
|
return (__le32 *) (entry->skb->data);
|
||||||
rt2800_write_txwi(txwi, txdesc);
|
else
|
||||||
|
return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct txentry_desc *txdesc)
|
struct txentry_desc *txdesc)
|
||||||
|
@ -378,6 +378,38 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TX control handlers
|
||||||
|
*/
|
||||||
|
static void rt2800usb_work_txdone(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct rt2x00_dev *rt2x00dev =
|
||||||
|
container_of(work, struct rt2x00_dev, txdone_work);
|
||||||
|
struct data_queue *queue;
|
||||||
|
struct queue_entry *entry;
|
||||||
|
|
||||||
|
rt2800_txdone(rt2x00dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process any trailing TX status reports for IO failures,
|
||||||
|
* we loop until we find the first non-IO error entry. This
|
||||||
|
* can either be a frame which is free, is being uploaded,
|
||||||
|
* or has completed the upload but didn't have an entry
|
||||||
|
* in the TX_STAT_FIFO register yet.
|
||||||
|
*/
|
||||||
|
tx_queue_for_each(rt2x00dev, queue) {
|
||||||
|
while (!rt2x00queue_empty(queue)) {
|
||||||
|
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
|
||||||
|
|
||||||
|
if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
|
||||||
|
!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
|
||||||
|
break;
|
||||||
|
|
||||||
|
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RX control handlers
|
* RX control handlers
|
||||||
*/
|
*/
|
||||||
|
@ -514,6 +546,11 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||||
*/
|
*/
|
||||||
rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
|
rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite TX done handler
|
||||||
|
*/
|
||||||
|
PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +586,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
|
||||||
.regbusy_read = rt2x00usb_regbusy_read,
|
.regbusy_read = rt2x00usb_regbusy_read,
|
||||||
.drv_write_firmware = rt2800usb_write_firmware,
|
.drv_write_firmware = rt2800usb_write_firmware,
|
||||||
.drv_init_registers = rt2800usb_init_registers,
|
.drv_init_registers = rt2800usb_init_registers,
|
||||||
|
.drv_get_txwi = rt2800usb_get_txwi,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
|
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
|
||||||
|
@ -566,7 +604,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
|
||||||
.link_tuner = rt2800_link_tuner,
|
.link_tuner = rt2800_link_tuner,
|
||||||
.watchdog = rt2x00usb_watchdog,
|
.watchdog = rt2x00usb_watchdog,
|
||||||
.write_tx_desc = rt2800usb_write_tx_desc,
|
.write_tx_desc = rt2800usb_write_tx_desc,
|
||||||
.write_tx_data = rt2800usb_write_tx_data,
|
.write_tx_data = rt2800_write_tx_data,
|
||||||
.write_beacon = rt2800_write_beacon,
|
.write_beacon = rt2800_write_beacon,
|
||||||
.get_tx_data_len = rt2800usb_get_tx_data_len,
|
.get_tx_data_len = rt2800usb_get_tx_data_len,
|
||||||
.kick_tx_queue = rt2x00usb_kick_tx_queue,
|
.kick_tx_queue = rt2x00usb_kick_tx_queue,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
|
||||||
|
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
|
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
|
||||||
<http://rt2x00.serialmonkey.com>
|
<http://rt2x00.serialmonkey.com>
|
||||||
|
|
||||||
|
@ -698,6 +699,7 @@ struct rt2x00_dev {
|
||||||
struct ieee80211_hw *hw;
|
struct ieee80211_hw *hw;
|
||||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||||
enum ieee80211_band curr_band;
|
enum ieee80211_band curr_band;
|
||||||
|
int curr_freq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If enabled, the debugfs interface structures
|
* If enabled, the debugfs interface structures
|
||||||
|
@ -849,11 +851,6 @@ struct rt2x00_dev {
|
||||||
*/
|
*/
|
||||||
struct ieee80211_low_level_stats low_level_stats;
|
struct ieee80211_low_level_stats low_level_stats;
|
||||||
|
|
||||||
/*
|
|
||||||
* RX configuration information.
|
|
||||||
*/
|
|
||||||
struct ieee80211_rx_status rx_status;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scheduled work.
|
* Scheduled work.
|
||||||
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
|
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
|
||||||
|
@ -862,6 +859,12 @@ struct rt2x00_dev {
|
||||||
*/
|
*/
|
||||||
struct work_struct intf_work;
|
struct work_struct intf_work;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scheduled work for TX/RX done handling (USB devices)
|
||||||
|
*/
|
||||||
|
struct work_struct rxdone_work;
|
||||||
|
struct work_struct txdone_work;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data queue arrays for RX, TX and Beacon.
|
* Data queue arrays for RX, TX and Beacon.
|
||||||
* The Beacon array also contains the Atim queue
|
* The Beacon array also contains the Atim queue
|
||||||
|
@ -1071,6 +1074,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
|
||||||
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
|
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
|
||||||
void rt2x00lib_txdone(struct queue_entry *entry,
|
void rt2x00lib_txdone(struct queue_entry *entry,
|
||||||
struct txdone_entry_desc *txdesc);
|
struct txdone_entry_desc *txdesc);
|
||||||
|
void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
|
||||||
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||||
struct queue_entry *entry);
|
struct queue_entry *entry);
|
||||||
|
|
||||||
|
|
|
@ -126,11 +126,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
||||||
* ANTENNA_SW_DIVERSITY state to the driver.
|
* ANTENNA_SW_DIVERSITY state to the driver.
|
||||||
* If that happens, fallback to hardware defaults,
|
* If that happens, fallback to hardware defaults,
|
||||||
* or our own default.
|
* or our own default.
|
||||||
* If diversity handling is active for a particular antenna,
|
|
||||||
* we shouldn't overwrite that antenna.
|
|
||||||
* The calls to rt2x00lib_config_antenna_check()
|
|
||||||
* might have caused that we restore back to the already
|
|
||||||
* active setting. If that has happened we can quit.
|
|
||||||
*/
|
*/
|
||||||
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
|
if (!(ant->flags & ANTENNA_RX_DIVERSITY))
|
||||||
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
|
config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
|
||||||
|
@ -142,9 +137,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
|
||||||
else
|
else
|
||||||
config.tx = active->tx;
|
config.tx = active->tx;
|
||||||
|
|
||||||
if (config.rx == active->rx && config.tx == active->tx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Antenna setup changes require the RX to be disabled,
|
* Antenna setup changes require the RX to be disabled,
|
||||||
* else the changes will be ignored by the device.
|
* else the changes will be ignored by the device.
|
||||||
|
@ -209,10 +201,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
|
||||||
rt2x00link_reset_tuner(rt2x00dev, false);
|
rt2x00link_reset_tuner(rt2x00dev, false);
|
||||||
|
|
||||||
rt2x00dev->curr_band = conf->channel->band;
|
rt2x00dev->curr_band = conf->channel->band;
|
||||||
|
rt2x00dev->curr_freq = conf->channel->center_freq;
|
||||||
rt2x00dev->tx_power = conf->power_level;
|
rt2x00dev->tx_power = conf->power_level;
|
||||||
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
|
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
|
||||||
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
|
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
|
||||||
|
|
||||||
rt2x00dev->rx_status.band = conf->channel->band;
|
|
||||||
rt2x00dev->rx_status.freq = conf->channel->center_freq;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,14 @@
|
||||||
|
|
||||||
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
|
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
|
||||||
{
|
{
|
||||||
switch (key->alg) {
|
switch (key->cipher) {
|
||||||
case ALG_WEP:
|
case WLAN_CIPHER_SUITE_WEP40:
|
||||||
if (key->keylen == WLAN_KEY_LEN_WEP40)
|
return CIPHER_WEP64;
|
||||||
return CIPHER_WEP64;
|
case WLAN_CIPHER_SUITE_WEP104:
|
||||||
else
|
return CIPHER_WEP128;
|
||||||
return CIPHER_WEP128;
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
case ALG_TKIP:
|
|
||||||
return CIPHER_TKIP;
|
return CIPHER_TKIP;
|
||||||
case ALG_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
return CIPHER_AES;
|
return CIPHER_AES;
|
||||||
default:
|
default:
|
||||||
return CIPHER_NONE;
|
return CIPHER_NONE;
|
||||||
|
@ -95,7 +94,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
|
||||||
overhead += key->iv_len;
|
overhead += key->iv_len;
|
||||||
|
|
||||||
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
|
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
|
||||||
if (key->alg == ALG_TKIP)
|
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||||
overhead += 8;
|
overhead += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
|
||||||
|
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
|
||||||
<http://rt2x00.serialmonkey.com>
|
<http://rt2x00.serialmonkey.com>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -383,15 +384,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
||||||
* send the status report back.
|
* send the status report back.
|
||||||
*/
|
*/
|
||||||
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
|
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
|
||||||
/*
|
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
|
||||||
* Only PCI and SOC devices process the tx status in process
|
|
||||||
* context. Hence use ieee80211_tx_status for PCI and SOC
|
|
||||||
* devices and stick to ieee80211_tx_status_irqsafe for USB.
|
|
||||||
*/
|
|
||||||
if (rt2x00_is_usb(rt2x00dev))
|
|
||||||
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
|
|
||||||
else
|
|
||||||
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
|
|
||||||
else
|
else
|
||||||
dev_kfree_skb_any(entry->skb);
|
dev_kfree_skb_any(entry->skb);
|
||||||
|
|
||||||
|
@ -403,7 +396,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
||||||
|
|
||||||
rt2x00dev->ops->lib->clear_entry(entry);
|
rt2x00dev->ops->lib->clear_entry(entry);
|
||||||
|
|
||||||
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
|
|
||||||
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -416,6 +408,18 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
|
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
|
||||||
|
|
||||||
|
void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
|
||||||
|
{
|
||||||
|
struct txdone_entry_desc txdesc;
|
||||||
|
|
||||||
|
txdesc.flags = 0;
|
||||||
|
__set_bit(status, &txdesc.flags);
|
||||||
|
txdesc.retry = 0;
|
||||||
|
|
||||||
|
rt2x00lib_txdone(entry, &txdesc);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
|
||||||
|
|
||||||
static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
|
static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
|
||||||
struct rxdone_entry_desc *rxdesc)
|
struct rxdone_entry_desc *rxdesc)
|
||||||
{
|
{
|
||||||
|
@ -460,9 +464,13 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||||
{
|
{
|
||||||
struct rxdone_entry_desc rxdesc;
|
struct rxdone_entry_desc rxdesc;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
|
struct ieee80211_rx_status *rx_status;
|
||||||
unsigned int header_length;
|
unsigned int header_length;
|
||||||
int rate_idx;
|
int rate_idx;
|
||||||
|
|
||||||
|
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
|
||||||
|
goto submit_entry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a new sk_buffer. If no new buffer available, drop the
|
* Allocate a new sk_buffer. If no new buffer available, drop the
|
||||||
* received frame and reuse the existing buffer.
|
* received frame and reuse the existing buffer.
|
||||||
|
@ -527,39 +535,32 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
|
||||||
*/
|
*/
|
||||||
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
|
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
|
||||||
rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
|
rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
|
||||||
|
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize RX status information, and send frame
|
||||||
|
* to mac80211.
|
||||||
|
*/
|
||||||
|
rx_status = IEEE80211_SKB_RXCB(entry->skb);
|
||||||
rx_status->mactime = rxdesc.timestamp;
|
rx_status->mactime = rxdesc.timestamp;
|
||||||
|
rx_status->band = rt2x00dev->curr_band;
|
||||||
|
rx_status->freq = rt2x00dev->curr_freq;
|
||||||
rx_status->rate_idx = rate_idx;
|
rx_status->rate_idx = rate_idx;
|
||||||
rx_status->signal = rxdesc.rssi;
|
rx_status->signal = rxdesc.rssi;
|
||||||
rx_status->flag = rxdesc.flags;
|
rx_status->flag = rxdesc.flags;
|
||||||
rx_status->antenna = rt2x00dev->link.ant.active.rx;
|
rx_status->antenna = rt2x00dev->link.ant.active.rx;
|
||||||
|
|
||||||
/*
|
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
|
||||||
* Send frame to mac80211 & debugfs.
|
|
||||||
* mac80211 will clean up the skb structure.
|
|
||||||
*/
|
|
||||||
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
|
|
||||||
memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Currently only PCI and SOC devices handle rx interrupts in process
|
|
||||||
* context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
|
|
||||||
* for PCI and SOC devices.
|
|
||||||
*/
|
|
||||||
if (rt2x00_is_usb(rt2x00dev))
|
|
||||||
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
|
|
||||||
else
|
|
||||||
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace the skb with the freshly allocated one.
|
* Replace the skb with the freshly allocated one.
|
||||||
*/
|
*/
|
||||||
entry->skb = skb;
|
entry->skb = skb;
|
||||||
entry->flags = 0;
|
|
||||||
|
|
||||||
|
submit_entry:
|
||||||
rt2x00dev->ops->lib->clear_entry(entry);
|
rt2x00dev->ops->lib->clear_entry(entry);
|
||||||
|
|
||||||
rt2x00queue_index_inc(entry->queue, Q_INDEX);
|
rt2x00queue_index_inc(entry->queue, Q_INDEX);
|
||||||
|
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
|
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
|
||||||
|
|
||||||
|
@ -1017,6 +1018,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
||||||
* Stop all work.
|
* Stop all work.
|
||||||
*/
|
*/
|
||||||
cancel_work_sync(&rt2x00dev->intf_work);
|
cancel_work_sync(&rt2x00dev->intf_work);
|
||||||
|
cancel_work_sync(&rt2x00dev->rxdone_work);
|
||||||
|
cancel_work_sync(&rt2x00dev->txdone_work);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Uninitialize device.
|
* Uninitialize device.
|
||||||
|
|
|
@ -63,6 +63,9 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
|
||||||
|
|
||||||
INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
|
INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
|
||||||
fw->data[fw->size - 4], fw->data[fw->size - 3]);
|
fw->data[fw->size - 4], fw->data[fw->size - 3]);
|
||||||
|
snprintf(rt2x00dev->hw->wiphy->fw_version,
|
||||||
|
sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d",
|
||||||
|
fw->data[fw->size - 4], fw->data[fw->size - 3]);
|
||||||
|
|
||||||
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
|
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
|
|
@ -54,6 +54,16 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
|
||||||
*/
|
*/
|
||||||
if (txrate->flags & IEEE80211_TX_RC_MCS) {
|
if (txrate->flags & IEEE80211_TX_RC_MCS) {
|
||||||
txdesc->mcs = txrate->idx;
|
txdesc->mcs = txrate->idx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIMO PS should be set to 1 for STA's using dynamic SM PS
|
||||||
|
* when using more then one tx stream (>MCS7).
|
||||||
|
*/
|
||||||
|
if (tx_info->control.sta && txdesc->mcs > 7 &&
|
||||||
|
(tx_info->control.sta->ht_cap.cap &
|
||||||
|
(WLAN_HT_CAP_SM_PS_DYNAMIC <<
|
||||||
|
IEEE80211_HT_CAP_SM_PS_SHIFT)))
|
||||||
|
__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
|
||||||
} else {
|
} else {
|
||||||
txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
|
txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
|
||||||
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue