Merge branch 'for-davem' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
d72751ede1
|
@ -274,6 +274,7 @@ source "drivers/net/wireless/b43legacy/Kconfig"
|
|||
source "drivers/net/wireless/hostap/Kconfig"
|
||||
source "drivers/net/wireless/ipw2x00/Kconfig"
|
||||
source "drivers/net/wireless/iwlwifi/Kconfig"
|
||||
source "drivers/net/wireless/iwlegacy/Kconfig"
|
||||
source "drivers/net/wireless/iwmc3200wifi/Kconfig"
|
||||
source "drivers/net/wireless/libertas/Kconfig"
|
||||
source "drivers/net/wireless/orinoco/Kconfig"
|
||||
|
|
|
@ -24,7 +24,7 @@ obj-$(CONFIG_B43LEGACY) += b43legacy/
|
|||
obj-$(CONFIG_ZD1211RW) += zd1211rw/
|
||||
obj-$(CONFIG_RTL8180) += rtl818x/
|
||||
obj-$(CONFIG_RTL8187) += rtl818x/
|
||||
obj-$(CONFIG_RTL8192CE) += rtlwifi/
|
||||
obj-$(CONFIG_RTLWIFI) += rtlwifi/
|
||||
|
||||
# 16-bit wireless PCMCIA client drivers
|
||||
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
|
||||
|
@ -41,7 +41,8 @@ obj-$(CONFIG_ADM8211) += adm8211.o
|
|||
|
||||
obj-$(CONFIG_MWL8K) += mwl8k.o
|
||||
|
||||
obj-$(CONFIG_IWLWIFI) += iwlwifi/
|
||||
obj-$(CONFIG_IWLAGN) += iwlwifi/
|
||||
obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/
|
||||
obj-$(CONFIG_RT2X00) += rt2x00/
|
||||
|
||||
obj-$(CONFIG_P54_COMMON) += p54/
|
||||
|
|
|
@ -1658,7 +1658,7 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
/* Put adm8211_tx_hdr on skb and transmit */
|
||||
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
static void adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct adm8211_tx_hdr *txhdr;
|
||||
size_t payload_len, hdrlen;
|
||||
|
@ -1707,8 +1707,6 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
txhdr->retry_limit = info->control.rates[0].count;
|
||||
|
||||
adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int adm8211_alloc_rings(struct ieee80211_hw *dev)
|
||||
|
|
|
@ -1728,7 +1728,7 @@ static void at76_mac80211_tx_callback(struct urb *urb)
|
|||
ieee80211_wake_queues(priv->hw);
|
||||
}
|
||||
|
||||
static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
static void at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct at76_priv *priv = hw->priv;
|
||||
struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
|
||||
|
@ -1741,7 +1741,8 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
if (priv->tx_urb->status == -EINPROGRESS) {
|
||||
wiphy_err(priv->hw->wiphy,
|
||||
"%s called while tx urb is pending\n", __func__);
|
||||
return NETDEV_TX_BUSY;
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The following code lines are important when the device is going to
|
||||
|
@ -1755,7 +1756,8 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
if (compare_ether_addr(priv->bssid, mgmt->bssid)) {
|
||||
memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
|
||||
ieee80211_queue_work(hw, &priv->work_join_bssid);
|
||||
return NETDEV_TX_BUSY;
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1795,8 +1797,6 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
priv->tx_urb,
|
||||
priv->tx_urb->hcpriv, priv->tx_urb->complete);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at76_mac80211_start(struct ieee80211_hw *hw)
|
||||
|
|
|
@ -224,7 +224,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
|
|||
int ar9170_nag_limiter(struct ar9170 *ar);
|
||||
|
||||
/* MAC */
|
||||
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int ar9170_init_mac(struct ar9170 *ar);
|
||||
int ar9170_set_qos(struct ar9170 *ar);
|
||||
int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
|
||||
|
|
|
@ -1475,7 +1475,7 @@ static void ar9170_tx(struct ar9170 *ar)
|
|||
msecs_to_jiffies(AR9170_JANITOR_DELAY));
|
||||
}
|
||||
|
||||
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ar9170 *ar = hw->priv;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
@ -1493,11 +1493,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
skb_queue_tail(&ar->tx_pending[queue], skb);
|
||||
|
||||
ar9170_tx(ar);
|
||||
return NETDEV_TX_OK;
|
||||
return;
|
||||
|
||||
err_free:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int ar9170_op_add_interface(struct ieee80211_hw *hw,
|
||||
|
|
|
@ -1164,8 +1164,8 @@ struct ath5k_txq;
|
|||
|
||||
void set_beacon_filter(struct ieee80211_hw *hw, bool enable);
|
||||
bool ath_any_vif_assoc(struct ath5k_softc *sc);
|
||||
int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ath5k_txq *txq);
|
||||
void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ath5k_txq *txq);
|
||||
int ath5k_init_hw(struct ath5k_softc *sc);
|
||||
int ath5k_stop_hw(struct ath5k_softc *sc);
|
||||
void ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif);
|
||||
|
|
|
@ -1361,7 +1361,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
|
|||
* right now, so it's not too bad...
|
||||
*/
|
||||
rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp);
|
||||
rxs->flag |= RX_FLAG_TSFT;
|
||||
rxs->flag |= RX_FLAG_MACTIME_MPDU;
|
||||
|
||||
rxs->freq = sc->curchan->center_freq;
|
||||
rxs->band = sc->curchan->band;
|
||||
|
@ -1518,7 +1518,7 @@ unlock:
|
|||
* TX Handling *
|
||||
\*************/
|
||||
|
||||
int
|
||||
void
|
||||
ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ath5k_txq *txq)
|
||||
{
|
||||
|
@ -1567,11 +1567,10 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
spin_unlock_irqrestore(&sc->txbuflock, flags);
|
||||
goto drop_packet;
|
||||
}
|
||||
return NETDEV_TX_OK;
|
||||
return;
|
||||
|
||||
drop_packet:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -52,7 +52,7 @@ extern int ath5k_modparam_nohwcrypt;
|
|||
* Mac80211 functions *
|
||||
\********************/
|
||||
|
||||
static int
|
||||
static void
|
||||
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
|
@ -60,10 +60,10 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
|
||||
ath5k_tx_queue(hw, skb, &sc->txqs[qnum]);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -78,15 +78,15 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
|
|||
/* Awake Setting */
|
||||
|
||||
INIT_INI_ARRAY(&ah->iniPcieSerdes,
|
||||
ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1,
|
||||
ARRAY_SIZE(ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1),
|
||||
ar9485_1_1_pcie_phy_clkreq_disable_L1,
|
||||
ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
|
||||
2);
|
||||
|
||||
/* Sleep Setting */
|
||||
|
||||
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
|
||||
ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1,
|
||||
ARRAY_SIZE(ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1),
|
||||
ar9485_1_1_pcie_phy_clkreq_disable_L1,
|
||||
ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
|
||||
2);
|
||||
} else if (AR_SREV_9485(ah)) {
|
||||
/* mac */
|
||||
|
|
|
@ -449,26 +449,21 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
|
|||
|
||||
#define ATH_LED_PIN_DEF 1
|
||||
#define ATH_LED_PIN_9287 8
|
||||
#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
|
||||
#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
|
||||
|
||||
enum ath_led_type {
|
||||
ATH_LED_RADIO,
|
||||
ATH_LED_ASSOC,
|
||||
ATH_LED_TX,
|
||||
ATH_LED_RX
|
||||
};
|
||||
|
||||
struct ath_led {
|
||||
struct ath_softc *sc;
|
||||
struct led_classdev led_cdev;
|
||||
enum ath_led_type led_type;
|
||||
char name[32];
|
||||
bool registered;
|
||||
};
|
||||
#define ATH_LED_PIN_9485 6
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
void ath_init_leds(struct ath_softc *sc);
|
||||
void ath_deinit_leds(struct ath_softc *sc);
|
||||
#else
|
||||
static inline void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Antenna diversity/combining */
|
||||
#define ATH_ANT_RX_CURRENT_SHIFT 4
|
||||
|
@ -620,15 +615,11 @@ struct ath_softc {
|
|||
struct ath_beacon beacon;
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
|
||||
struct ath_led radio_led;
|
||||
struct ath_led assoc_led;
|
||||
struct ath_led tx_led;
|
||||
struct ath_led rx_led;
|
||||
struct delayed_work ath_led_blink_work;
|
||||
int led_on_duration;
|
||||
int led_off_duration;
|
||||
int led_on_cnt;
|
||||
int led_off_cnt;
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
bool led_registered;
|
||||
char led_name[32];
|
||||
struct led_classdev led_cdev;
|
||||
#endif
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
int last_rssi;
|
||||
|
|
|
@ -20,121 +20,31 @@
|
|||
/* LED functions */
|
||||
/********************************/
|
||||
|
||||
static void ath_led_blink_work(struct work_struct *work)
|
||||
{
|
||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
||||
ath_led_blink_work.work);
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
|
||||
return;
|
||||
|
||||
if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
|
||||
(sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
|
||||
else
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
|
||||
|
||||
ieee80211_queue_delayed_work(sc->hw,
|
||||
&sc->ath_led_blink_work,
|
||||
(sc->sc_flags & SC_OP_LED_ON) ?
|
||||
msecs_to_jiffies(sc->led_off_duration) :
|
||||
msecs_to_jiffies(sc->led_on_duration));
|
||||
|
||||
sc->led_on_duration = sc->led_on_cnt ?
|
||||
max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
|
||||
ATH_LED_ON_DURATION_IDLE;
|
||||
sc->led_off_duration = sc->led_off_cnt ?
|
||||
max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
|
||||
ATH_LED_OFF_DURATION_IDLE;
|
||||
sc->led_on_cnt = sc->led_off_cnt = 0;
|
||||
if (sc->sc_flags & SC_OP_LED_ON)
|
||||
sc->sc_flags &= ~SC_OP_LED_ON;
|
||||
else
|
||||
sc->sc_flags |= SC_OP_LED_ON;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
static void ath_led_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
|
||||
struct ath_softc *sc = led->sc;
|
||||
|
||||
switch (brightness) {
|
||||
case LED_OFF:
|
||||
if (led->led_type == ATH_LED_ASSOC ||
|
||||
led->led_type == ATH_LED_RADIO) {
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
(led->led_type == ATH_LED_RADIO));
|
||||
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
|
||||
if (led->led_type == ATH_LED_RADIO)
|
||||
sc->sc_flags &= ~SC_OP_LED_ON;
|
||||
} else {
|
||||
sc->led_off_cnt++;
|
||||
}
|
||||
break;
|
||||
case LED_FULL:
|
||||
if (led->led_type == ATH_LED_ASSOC) {
|
||||
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
|
||||
if (led_blink)
|
||||
ieee80211_queue_delayed_work(sc->hw,
|
||||
&sc->ath_led_blink_work, 0);
|
||||
} else if (led->led_type == ATH_LED_RADIO) {
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
|
||||
sc->sc_flags |= SC_OP_LED_ON;
|
||||
} else {
|
||||
sc->led_on_cnt++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
|
||||
char *trigger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
led->sc = sc;
|
||||
led->led_cdev.name = led->name;
|
||||
led->led_cdev.default_trigger = trigger;
|
||||
led->led_cdev.brightness_set = ath_led_brightness;
|
||||
|
||||
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
|
||||
if (ret)
|
||||
ath_err(ath9k_hw_common(sc->sc_ah),
|
||||
"Failed to register led:%s", led->name);
|
||||
else
|
||||
led->registered = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath_unregister_led(struct ath_led *led)
|
||||
{
|
||||
if (led->registered) {
|
||||
led_classdev_unregister(&led->led_cdev);
|
||||
led->registered = 0;
|
||||
}
|
||||
struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF));
|
||||
}
|
||||
|
||||
void ath_deinit_leds(struct ath_softc *sc)
|
||||
{
|
||||
ath_unregister_led(&sc->assoc_led);
|
||||
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
|
||||
ath_unregister_led(&sc->tx_led);
|
||||
ath_unregister_led(&sc->rx_led);
|
||||
ath_unregister_led(&sc->radio_led);
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
if (!sc->led_registered)
|
||||
return;
|
||||
|
||||
ath_led_brightness(&sc->led_cdev, LED_OFF);
|
||||
led_classdev_unregister(&sc->led_cdev);
|
||||
}
|
||||
|
||||
void ath_init_leds(struct ath_softc *sc)
|
||||
{
|
||||
char *trigger;
|
||||
int ret;
|
||||
|
||||
if (AR_SREV_9287(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9287;
|
||||
else if (AR_SREV_9485(sc->sc_ah))
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_9485;
|
||||
else
|
||||
sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
|
||||
|
||||
|
@ -144,48 +54,22 @@ void ath_init_leds(struct ath_softc *sc)
|
|||
/* LED off, active low */
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
|
||||
if (led_blink)
|
||||
INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
|
||||
if (!led_blink)
|
||||
sc->led_cdev.default_trigger =
|
||||
ieee80211_get_radio_led_name(sc->hw);
|
||||
|
||||
trigger = ieee80211_get_radio_led_name(sc->hw);
|
||||
snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
|
||||
"ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->radio_led, trigger);
|
||||
sc->radio_led.led_type = ATH_LED_RADIO;
|
||||
if (ret)
|
||||
goto fail;
|
||||
snprintf(sc->led_name, sizeof(sc->led_name),
|
||||
"ath9k-%s", wiphy_name(sc->hw->wiphy));
|
||||
sc->led_cdev.name = sc->led_name;
|
||||
sc->led_cdev.brightness_set = ath_led_brightness;
|
||||
|
||||
trigger = ieee80211_get_assoc_led_name(sc->hw);
|
||||
snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
|
||||
"ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->assoc_led, trigger);
|
||||
sc->assoc_led.led_type = ATH_LED_ASSOC;
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
trigger = ieee80211_get_tx_led_name(sc->hw);
|
||||
snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
|
||||
"ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->tx_led, trigger);
|
||||
sc->tx_led.led_type = ATH_LED_TX;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
trigger = ieee80211_get_rx_led_name(sc->hw);
|
||||
snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
|
||||
"ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
|
||||
ret = ath_register_led(sc, &sc->rx_led, trigger);
|
||||
sc->rx_led.led_type = ATH_LED_RX;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (led_blink)
|
||||
cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
||||
ath_deinit_leds(sc);
|
||||
sc->led_registered = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************/
|
||||
/* Rfkill */
|
||||
|
|
|
@ -52,6 +52,9 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
|
|||
{ USB_DEVICE(0x083A, 0xA704),
|
||||
.driver_info = AR9280_USB }, /* SMC Networks */
|
||||
|
||||
{ USB_DEVICE(0x0cf3, 0x20ff),
|
||||
.driver_info = STORAGE_DEVICE },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -914,13 +917,11 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info)
|
|||
if (ret) {
|
||||
dev_err(&hif_dev->udev->dev,
|
||||
"ath9k_htc: Unable to allocate URBs\n");
|
||||
goto err_urb;
|
||||
goto err_fw_download;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_urb:
|
||||
ath9k_hif_usb_dealloc_urbs(hif_dev);
|
||||
err_fw_download:
|
||||
release_firmware(hif_dev->firmware);
|
||||
err_fw_req:
|
||||
|
@ -935,6 +936,61 @@ static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
|
|||
release_firmware(hif_dev->firmware);
|
||||
}
|
||||
|
||||
/*
|
||||
* An exact copy of the function from zd1211rw.
|
||||
*/
|
||||
static int send_eject_command(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_host_interface *iface_desc = &interface->altsetting[0];
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
unsigned char *cmd;
|
||||
u8 bulk_out_ep;
|
||||
int r;
|
||||
|
||||
/* Find bulk out endpoint */
|
||||
for (r = 1; r >= 0; r--) {
|
||||
endpoint = &iface_desc->endpoint[r].desc;
|
||||
if (usb_endpoint_dir_out(endpoint) &&
|
||||
usb_endpoint_xfer_bulk(endpoint)) {
|
||||
bulk_out_ep = endpoint->bEndpointAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r == -1) {
|
||||
dev_err(&udev->dev,
|
||||
"ath9k_htc: Could not find bulk out endpoint\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cmd = kzalloc(31, GFP_KERNEL);
|
||||
if (cmd == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* USB bulk command block */
|
||||
cmd[0] = 0x55; /* bulk command signature */
|
||||
cmd[1] = 0x53; /* bulk command signature */
|
||||
cmd[2] = 0x42; /* bulk command signature */
|
||||
cmd[3] = 0x43; /* bulk command signature */
|
||||
cmd[14] = 6; /* command length */
|
||||
|
||||
cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
|
||||
cmd[19] = 0x2; /* eject disc */
|
||||
|
||||
dev_info(&udev->dev, "Ejecting storage device...\n");
|
||||
r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
|
||||
cmd, 31, NULL, 2000);
|
||||
kfree(cmd);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* At this point, the device disconnects and reconnects with the real
|
||||
* ID numbers. */
|
||||
|
||||
usb_set_intfdata(interface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath9k_hif_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
@ -942,6 +998,9 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
|
|||
struct hif_device_usb *hif_dev;
|
||||
int ret = 0;
|
||||
|
||||
if (id->driver_info == STORAGE_DEVICE)
|
||||
return send_eject_command(interface);
|
||||
|
||||
hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
|
||||
if (!hif_dev) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -1028,12 +1087,13 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
|
|||
struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
|
||||
bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
|
||||
|
||||
if (hif_dev) {
|
||||
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
|
||||
ath9k_htc_hw_free(hif_dev->htc_handle);
|
||||
ath9k_hif_usb_dev_deinit(hif_dev);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
}
|
||||
if (!hif_dev)
|
||||
return;
|
||||
|
||||
ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
|
||||
ath9k_htc_hw_free(hif_dev->htc_handle);
|
||||
ath9k_hif_usb_dev_deinit(hif_dev);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
if (!unplugged && (hif_dev->flags & HIF_USB_START))
|
||||
ath9k_hif_usb_reboot(udev);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "wmi.h"
|
||||
|
||||
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
|
||||
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
|
||||
#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */
|
||||
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
|
||||
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
|
||||
|
@ -204,8 +205,50 @@ struct ath9k_htc_target_stats {
|
|||
__be32 ht_tx_xretries;
|
||||
} __packed;
|
||||
|
||||
#define ATH9K_HTC_MAX_VIF 2
|
||||
#define ATH9K_HTC_MAX_BCN_VIF 2
|
||||
|
||||
#define INC_VIF(_priv, _type) do { \
|
||||
switch (_type) { \
|
||||
case NL80211_IFTYPE_STATION: \
|
||||
_priv->num_sta_vif++; \
|
||||
break; \
|
||||
case NL80211_IFTYPE_ADHOC: \
|
||||
_priv->num_ibss_vif++; \
|
||||
break; \
|
||||
case NL80211_IFTYPE_AP: \
|
||||
_priv->num_ap_vif++; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEC_VIF(_priv, _type) do { \
|
||||
switch (_type) { \
|
||||
case NL80211_IFTYPE_STATION: \
|
||||
_priv->num_sta_vif--; \
|
||||
break; \
|
||||
case NL80211_IFTYPE_ADHOC: \
|
||||
_priv->num_ibss_vif--; \
|
||||
break; \
|
||||
case NL80211_IFTYPE_AP: \
|
||||
_priv->num_ap_vif--; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct ath9k_htc_vif {
|
||||
u8 index;
|
||||
u16 seq_no;
|
||||
bool beacon_configured;
|
||||
};
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
const u8 *hw_macaddr;
|
||||
u8 mask[ETH_ALEN];
|
||||
};
|
||||
|
||||
#define ATH9K_HTC_MAX_STA 8
|
||||
|
@ -310,10 +353,8 @@ struct ath_led {
|
|||
|
||||
struct htc_beacon_config {
|
||||
u16 beacon_interval;
|
||||
u16 listen_interval;
|
||||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
};
|
||||
|
||||
struct ath_btcoex {
|
||||
|
@ -333,13 +374,12 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
|
|||
#define OP_SCANNING BIT(1)
|
||||
#define OP_LED_ASSOCIATED BIT(2)
|
||||
#define OP_LED_ON BIT(3)
|
||||
#define OP_PREAMBLE_SHORT BIT(4)
|
||||
#define OP_PROTECT_ENABLE BIT(5)
|
||||
#define OP_ASSOCIATED BIT(6)
|
||||
#define OP_ENABLE_BEACON BIT(7)
|
||||
#define OP_LED_DEINIT BIT(8)
|
||||
#define OP_BT_PRIORITY_DETECTED BIT(9)
|
||||
#define OP_BT_SCAN BIT(10)
|
||||
#define OP_ENABLE_BEACON BIT(4)
|
||||
#define OP_LED_DEINIT BIT(5)
|
||||
#define OP_BT_PRIORITY_DETECTED BIT(6)
|
||||
#define OP_BT_SCAN BIT(7)
|
||||
#define OP_ANI_RUNNING BIT(8)
|
||||
#define OP_TSF_RESET BIT(9)
|
||||
|
||||
struct ath9k_htc_priv {
|
||||
struct device *dev;
|
||||
|
@ -358,13 +398,22 @@ struct ath9k_htc_priv {
|
|||
enum htc_endpoint_id data_vi_ep;
|
||||
enum htc_endpoint_id data_vo_ep;
|
||||
|
||||
u8 vif_slot;
|
||||
u8 mon_vif_idx;
|
||||
u8 sta_slot;
|
||||
u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
|
||||
u8 num_ibss_vif;
|
||||
u8 num_sta_vif;
|
||||
u8 num_ap_vif;
|
||||
|
||||
u16 op_flags;
|
||||
u16 curtxpow;
|
||||
u16 txpowlimit;
|
||||
u16 nvifs;
|
||||
u16 nstations;
|
||||
u16 seq_no;
|
||||
u32 bmiss_cnt;
|
||||
bool rearm_ani;
|
||||
bool reconfig_beacon;
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
|
||||
|
@ -382,7 +431,7 @@ struct ath9k_htc_priv {
|
|||
struct ath9k_htc_rx rx;
|
||||
struct tasklet_struct tx_tasklet;
|
||||
struct sk_buff_head tx_queue;
|
||||
struct delayed_work ath9k_ani_work;
|
||||
struct delayed_work ani_work;
|
||||
struct work_struct ps_work;
|
||||
struct work_struct fatal_work;
|
||||
|
||||
|
@ -424,6 +473,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv);
|
|||
void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_vif *vif);
|
||||
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
|
||||
|
||||
void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
|
||||
|
@ -436,8 +486,9 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
|
|||
int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_station_work(struct work_struct *work);
|
||||
void ath9k_htc_aggr_work(struct work_struct *work);
|
||||
void ath9k_ani_work(struct work_struct *work);;
|
||||
void ath_start_ani(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_ani_work(struct work_struct *work);
|
||||
void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
|
||||
|
||||
int ath9k_tx_init(struct ath9k_htc_priv *priv);
|
||||
void ath9k_tx_tasklet(unsigned long data);
|
||||
|
|
|
@ -123,8 +123,9 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
/* TSF out of range threshold fixed at 1 second */
|
||||
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
|
||||
|
||||
ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
|
||||
ath_dbg(common, ATH_DBG_BEACON,
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
|
||||
intval, tsf, tsftu);
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
|
||||
bs.bs_bmissthreshold, bs.bs_sleepduration,
|
||||
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
|
||||
|
@ -138,25 +139,81 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
||||
}
|
||||
|
||||
static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
|
||||
struct htc_beacon_config *bss_conf)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
enum ath9k_int imask = 0;
|
||||
u32 nexttbtt, intval, tsftu;
|
||||
__be32 htc_imask = 0;
|
||||
int ret;
|
||||
u8 cmd_rsp;
|
||||
u64 tsf;
|
||||
|
||||
intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
intval /= ATH9K_HTC_MAX_BCN_VIF;
|
||||
nexttbtt = intval;
|
||||
|
||||
if (priv->op_flags & OP_TSF_RESET) {
|
||||
intval |= ATH9K_BEACON_RESET_TSF;
|
||||
priv->op_flags &= ~OP_TSF_RESET;
|
||||
} else {
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current TSF.
|
||||
*/
|
||||
tsf = ath9k_hw_gettsf64(priv->ah);
|
||||
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
} while (nexttbtt < tsftu);
|
||||
}
|
||||
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
|
||||
if (priv->op_flags & OP_ENABLE_BEACON)
|
||||
imask |= ATH9K_INT_SWBA;
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
|
||||
bss_conf->beacon_interval, nexttbtt, imask);
|
||||
|
||||
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||
ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
|
||||
priv->bmiss_cnt = 0;
|
||||
htc_imask = cpu_to_be32(imask);
|
||||
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
||||
}
|
||||
|
||||
static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
|
||||
struct htc_beacon_config *bss_conf)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
enum ath9k_int imask = 0;
|
||||
u32 nexttbtt, intval;
|
||||
u32 nexttbtt, intval, tsftu;
|
||||
__be32 htc_imask = 0;
|
||||
int ret;
|
||||
u8 cmd_rsp;
|
||||
u64 tsf;
|
||||
|
||||
intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
nexttbtt = intval;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current TSF.
|
||||
*/
|
||||
tsf = ath9k_hw_gettsf64(priv->ah);
|
||||
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
} while (nexttbtt < tsftu);
|
||||
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
if (priv->op_flags & OP_ENABLE_BEACON)
|
||||
imask |= ATH9K_INT_SWBA;
|
||||
|
||||
ath_dbg(common, ATH_DBG_BEACON,
|
||||
"IBSS Beacon config, intval: %d, imask: 0x%x\n",
|
||||
bss_conf->beacon_interval, imask);
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n",
|
||||
bss_conf->beacon_interval, nexttbtt, imask);
|
||||
|
||||
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||
ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
|
||||
|
@ -207,9 +264,9 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
|
|||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
||||
struct ieee80211_hdr *hdr =
|
||||
(struct ieee80211_hdr *) beacon->data;
|
||||
priv->seq_no += 0x10;
|
||||
avp->seq_no += 0x10;
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(priv->seq_no);
|
||||
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
|
||||
}
|
||||
|
||||
tx_ctl.type = ATH9K_HTC_NORMAL;
|
||||
|
@ -253,30 +310,123 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
bool *beacon_configured = (bool *)data;
|
||||
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
avp->beacon_configured)
|
||||
*beacon_configured = true;
|
||||
}
|
||||
|
||||
static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
bool beacon_configured;
|
||||
|
||||
/*
|
||||
* Changing the beacon interval when multiple AP interfaces
|
||||
* are configured will affect beacon transmission of all
|
||||
* of them.
|
||||
*/
|
||||
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
||||
(priv->num_ap_vif > 1) &&
|
||||
(vif->type == NL80211_IFTYPE_AP) &&
|
||||
(cur_conf->beacon_interval != bss_conf->beacon_int)) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Changing beacon interval of multiple AP interfaces !\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the HW is operating in AP mode, any new station interfaces that
|
||||
* are added cannot change the beacon parameters.
|
||||
*/
|
||||
if (priv->num_ap_vif &&
|
||||
(vif->type != NL80211_IFTYPE_AP)) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"HW in AP mode, cannot set STA beacon parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The beacon parameters are configured only for the first
|
||||
* station interface.
|
||||
*/
|
||||
if ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
|
||||
(priv->num_sta_vif > 1) &&
|
||||
(vif->type == NL80211_IFTYPE_STATION)) {
|
||||
beacon_configured = false;
|
||||
ieee80211_iterate_active_interfaces_atomic(priv->hw,
|
||||
ath9k_htc_beacon_iter,
|
||||
&beacon_configured);
|
||||
|
||||
if (beacon_configured) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
|
||||
|
||||
if (!ath9k_htc_check_beacon_config(priv, vif))
|
||||
return;
|
||||
|
||||
cur_conf->beacon_interval = bss_conf->beacon_int;
|
||||
if (cur_conf->beacon_interval == 0)
|
||||
cur_conf->beacon_interval = 100;
|
||||
|
||||
cur_conf->dtim_period = bss_conf->dtim_period;
|
||||
cur_conf->listen_interval = 1;
|
||||
cur_conf->dtim_count = 1;
|
||||
cur_conf->bmiss_timeout =
|
||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ath9k_htc_beacon_config_sta(priv, cur_conf);
|
||||
avp->beacon_configured = true;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
ath9k_htc_beacon_config_ap(priv, cur_conf);
|
||||
break;
|
||||
default:
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Unsupported beaconing mode\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
|
||||
|
||||
switch (priv->ah->opmode) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ath9k_htc_beacon_config_sta(priv, cur_conf);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
ath9k_htc_beacon_config_ap(priv, cur_conf);
|
||||
break;
|
||||
default:
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Unsupported beaconing mode\n");
|
||||
|
|
|
@ -679,7 +679,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
|||
(unsigned long)priv);
|
||||
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
|
||||
(unsigned long)priv);
|
||||
INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
|
||||
INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
|
||||
INIT_WORK(&priv->ps_work, ath9k_ps_work);
|
||||
INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
|
||||
|
||||
|
@ -787,6 +787,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
|
|||
struct ath_hw *ah;
|
||||
int error = 0;
|
||||
struct ath_regulatory *reg;
|
||||
char hw_name[64];
|
||||
|
||||
/* Bring up device */
|
||||
error = ath9k_init_priv(priv, devid, product, drv_info);
|
||||
|
@ -827,6 +828,22 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
|
|||
goto err_world;
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
|
||||
"BE:%d, BK:%d, VI:%d, VO:%d\n",
|
||||
priv->wmi_cmd_ep,
|
||||
priv->beacon_ep,
|
||||
priv->cab_ep,
|
||||
priv->uapsd_ep,
|
||||
priv->mgmt_ep,
|
||||
priv->data_be_ep,
|
||||
priv->data_bk_ep,
|
||||
priv->data_vi_ep,
|
||||
priv->data_vo_ep);
|
||||
|
||||
ath9k_hw_name(priv->ah, hw_name, sizeof(hw_name));
|
||||
wiphy_info(hw->wiphy, "%s\n", hw_name);
|
||||
|
||||
ath9k_init_leds(priv);
|
||||
ath9k_start_rfkill_poll(priv);
|
||||
|
||||
|
|
|
@ -105,6 +105,82 @@ void ath9k_ps_work(struct work_struct *work)
|
|||
ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
|
||||
}
|
||||
|
||||
static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = data;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon)
|
||||
priv->reconfig_beacon = true;
|
||||
|
||||
if (bss_conf->assoc) {
|
||||
priv->rearm_ani = true;
|
||||
priv->reconfig_beacon = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
priv->rearm_ani = false;
|
||||
priv->reconfig_beacon = false;
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(priv->hw,
|
||||
ath9k_htc_vif_iter, priv);
|
||||
if (priv->rearm_ani)
|
||||
ath9k_htc_start_ani(priv);
|
||||
|
||||
if (priv->reconfig_beacon) {
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
ath9k_htc_beacon_reconfig(priv);
|
||||
ath9k_htc_ps_restore(priv);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath9k_vif_iter_data *iter_data = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
|
||||
}
|
||||
|
||||
static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct ath9k_vif_iter_data iter_data;
|
||||
|
||||
/*
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
* together with the BSSID mask when matching addresses.
|
||||
*/
|
||||
iter_data.hw_macaddr = common->macaddr;
|
||||
memset(&iter_data.mask, 0xff, ETH_ALEN);
|
||||
|
||||
if (vif)
|
||||
ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);
|
||||
|
||||
/* Get list of all active MAC addresses */
|
||||
ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter,
|
||||
&iter_data);
|
||||
|
||||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||||
ath_hw_setbssidmask(common);
|
||||
}
|
||||
|
||||
static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
if (priv->num_ibss_vif)
|
||||
priv->ah->opmode = NL80211_IFTYPE_ADHOC;
|
||||
else if (priv->num_ap_vif)
|
||||
priv->ah->opmode = NL80211_IFTYPE_AP;
|
||||
else
|
||||
priv->ah->opmode = NL80211_IFTYPE_STATION;
|
||||
|
||||
ath9k_hw_setopmode(priv->ah);
|
||||
}
|
||||
|
||||
void ath9k_htc_reset(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_hw *ah = priv->ah;
|
||||
|
@ -119,9 +195,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
|
|||
mutex_lock(&priv->mutex);
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
|
||||
if (priv->op_flags & OP_ASSOCIATED)
|
||||
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
||||
|
||||
ath9k_htc_stop_ani(priv);
|
||||
ieee80211_stop_queues(priv->hw);
|
||||
htc_stop(priv->htc);
|
||||
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||
|
@ -148,12 +222,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
|
|||
|
||||
WMI_CMD(WMI_ENABLE_INTR_CMDID);
|
||||
htc_start(priv->htc);
|
||||
|
||||
if (priv->op_flags & OP_ASSOCIATED) {
|
||||
ath9k_htc_beacon_config(priv, priv->vif);
|
||||
ath_start_ani(priv);
|
||||
}
|
||||
|
||||
ath9k_htc_vif_reconfig(priv);
|
||||
ieee80211_wake_queues(priv->hw);
|
||||
|
||||
ath9k_htc_ps_restore(priv);
|
||||
|
@ -222,11 +291,23 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
|
|||
goto err;
|
||||
|
||||
htc_start(priv->htc);
|
||||
|
||||
if (!(priv->op_flags & OP_SCANNING) &&
|
||||
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
|
||||
ath9k_htc_vif_reconfig(priv);
|
||||
|
||||
err:
|
||||
ath9k_htc_ps_restore(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitor mode handling is a tad complicated because the firmware requires
|
||||
* an interface to be created exclusively, while mac80211 doesn't associate
|
||||
* an interface with the mode.
|
||||
*
|
||||
* So, for now, only one monitor interface can be configured.
|
||||
*/
|
||||
static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
|
@ -236,9 +317,10 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
|
|||
|
||||
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
|
||||
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
|
||||
hvif.index = 0; /* Should do for now */
|
||||
hvif.index = priv->mon_vif_idx;
|
||||
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
|
||||
priv->nvifs--;
|
||||
priv->vif_slot &= ~(1 << priv->mon_vif_idx);
|
||||
}
|
||||
|
||||
static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
|
||||
|
@ -246,70 +328,87 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
|
|||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct ath9k_htc_target_vif hvif;
|
||||
struct ath9k_htc_target_sta tsta;
|
||||
int ret = 0;
|
||||
int ret = 0, sta_idx;
|
||||
u8 cmd_rsp;
|
||||
|
||||
if (priv->nvifs > 0)
|
||||
return -ENOBUFS;
|
||||
if ((priv->nvifs >= ATH9K_HTC_MAX_VIF) ||
|
||||
(priv->nstations >= ATH9K_HTC_MAX_STA)) {
|
||||
ret = -ENOBUFS;
|
||||
goto err_vif;
|
||||
}
|
||||
|
||||
if (priv->nstations >= ATH9K_HTC_MAX_STA)
|
||||
return -ENOBUFS;
|
||||
sta_idx = ffz(priv->sta_slot);
|
||||
if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) {
|
||||
ret = -ENOBUFS;
|
||||
goto err_vif;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an interface.
|
||||
*/
|
||||
|
||||
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
|
||||
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
|
||||
|
||||
hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
|
||||
priv->ah->opmode = NL80211_IFTYPE_MONITOR;
|
||||
hvif.index = priv->nvifs;
|
||||
hvif.index = ffz(priv->vif_slot);
|
||||
|
||||
WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_vif;
|
||||
|
||||
/*
|
||||
* Assign the monitor interface index as a special case here.
|
||||
* This is needed when the interface is brought down.
|
||||
*/
|
||||
priv->mon_vif_idx = hvif.index;
|
||||
priv->vif_slot |= (1 << hvif.index);
|
||||
|
||||
/*
|
||||
* Set the hardware mode to monitor only if there are no
|
||||
* other interfaces.
|
||||
*/
|
||||
if (!priv->nvifs)
|
||||
priv->ah->opmode = NL80211_IFTYPE_MONITOR;
|
||||
|
||||
priv->nvifs++;
|
||||
|
||||
/*
|
||||
* Associate a station with the interface for packet injection.
|
||||
*/
|
||||
|
||||
memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
|
||||
|
||||
memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN);
|
||||
|
||||
tsta.is_vif_sta = 1;
|
||||
tsta.sta_index = priv->nstations;
|
||||
tsta.sta_index = sta_idx;
|
||||
tsta.vif_index = hvif.index;
|
||||
tsta.maxampdu = 0xffff;
|
||||
|
||||
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
|
||||
if (ret) {
|
||||
ath_err(common, "Unable to add station entry for monitor mode\n");
|
||||
goto err_vif;
|
||||
goto err_sta;
|
||||
}
|
||||
|
||||
priv->sta_slot |= (1 << sta_idx);
|
||||
priv->nstations++;
|
||||
|
||||
/*
|
||||
* Set chainmask etc. on the target.
|
||||
*/
|
||||
ret = ath9k_htc_update_cap_target(priv);
|
||||
if (ret)
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Failed to update capability in target\n");
|
||||
|
||||
priv->vif_sta_pos[priv->mon_vif_idx] = sta_idx;
|
||||
priv->ah->is_monitoring = true;
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Attached a monitor interface at idx: %d, sta idx: %d\n",
|
||||
priv->mon_vif_idx, sta_idx);
|
||||
|
||||
return 0;
|
||||
|
||||
err_vif:
|
||||
err_sta:
|
||||
/*
|
||||
* Remove the interface from the target.
|
||||
*/
|
||||
__ath9k_htc_remove_monitor_interface(priv);
|
||||
err_vif:
|
||||
ath_dbg(common, ATH_DBG_FATAL, "Unable to attach a monitor interface\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -321,7 +420,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
|
|||
|
||||
__ath9k_htc_remove_monitor_interface(priv);
|
||||
|
||||
sta_idx = 0; /* Only single interface, for now */
|
||||
sta_idx = priv->vif_sta_pos[priv->mon_vif_idx];
|
||||
|
||||
WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
|
||||
if (ret) {
|
||||
|
@ -329,9 +428,14 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
priv->sta_slot &= ~(1 << sta_idx);
|
||||
priv->nstations--;
|
||||
priv->ah->is_monitoring = false;
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Removed a monitor interface at idx: %d, sta idx: %d\n",
|
||||
priv->mon_vif_idx, sta_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -343,12 +447,16 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
|
|||
struct ath9k_htc_target_sta tsta;
|
||||
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
|
||||
struct ath9k_htc_sta *ista;
|
||||
int ret;
|
||||
int ret, sta_idx;
|
||||
u8 cmd_rsp;
|
||||
|
||||
if (priv->nstations >= ATH9K_HTC_MAX_STA)
|
||||
return -ENOBUFS;
|
||||
|
||||
sta_idx = ffz(priv->sta_slot);
|
||||
if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA))
|
||||
return -ENOBUFS;
|
||||
|
||||
memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
|
||||
|
||||
if (sta) {
|
||||
|
@ -358,13 +466,13 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
|
|||
tsta.associd = common->curaid;
|
||||
tsta.is_vif_sta = 0;
|
||||
tsta.valid = true;
|
||||
ista->index = priv->nstations;
|
||||
ista->index = sta_idx;
|
||||
} else {
|
||||
memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
|
||||
tsta.is_vif_sta = 1;
|
||||
}
|
||||
|
||||
tsta.sta_index = priv->nstations;
|
||||
tsta.sta_index = sta_idx;
|
||||
tsta.vif_index = avp->index;
|
||||
tsta.maxampdu = 0xffff;
|
||||
if (sta && sta->ht_cap.ht_supported)
|
||||
|
@ -379,12 +487,21 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (sta)
|
||||
if (sta) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Added a station entry for: %pM (idx: %d)\n",
|
||||
sta->addr, tsta.sta_index);
|
||||
} else {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Added a station entry for VIF %d (idx: %d)\n",
|
||||
avp->index, tsta.sta_index);
|
||||
}
|
||||
|
||||
priv->sta_slot |= (1 << sta_idx);
|
||||
priv->nstations++;
|
||||
if (!sta)
|
||||
priv->vif_sta_pos[avp->index] = sta_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -393,6 +510,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
|
||||
struct ath9k_htc_sta *ista;
|
||||
int ret;
|
||||
u8 cmd_rsp, sta_idx;
|
||||
|
@ -401,7 +519,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
|
|||
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
||||
sta_idx = ista->index;
|
||||
} else {
|
||||
sta_idx = 0;
|
||||
sta_idx = priv->vif_sta_pos[avp->index];
|
||||
}
|
||||
|
||||
WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
|
||||
|
@ -413,12 +531,19 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (sta)
|
||||
if (sta) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Removed a station entry for: %pM (idx: %d)\n",
|
||||
sta->addr, sta_idx);
|
||||
} else {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Removed a station entry for VIF %d (idx: %d)\n",
|
||||
avp->index, sta_idx);
|
||||
}
|
||||
|
||||
priv->sta_slot &= ~(1 << sta_idx);
|
||||
priv->nstations--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -800,7 +925,7 @@ void ath9k_htc_debug_remove_root(void)
|
|||
/* ANI */
|
||||
/*******/
|
||||
|
||||
void ath_start_ani(struct ath9k_htc_priv *priv)
|
||||
void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
unsigned long timestamp = jiffies_to_msecs(jiffies);
|
||||
|
@ -809,15 +934,22 @@ void ath_start_ani(struct ath9k_htc_priv *priv)
|
|||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
|
||||
ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
|
||||
priv->op_flags |= OP_ANI_RUNNING;
|
||||
|
||||
ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
|
||||
msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||
}
|
||||
|
||||
void ath9k_ani_work(struct work_struct *work)
|
||||
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
cancel_delayed_work_sync(&priv->ani_work);
|
||||
priv->op_flags &= ~OP_ANI_RUNNING;
|
||||
}
|
||||
|
||||
void ath9k_htc_ani_work(struct work_struct *work)
|
||||
{
|
||||
struct ath9k_htc_priv *priv =
|
||||
container_of(work, struct ath9k_htc_priv,
|
||||
ath9k_ani_work.work);
|
||||
container_of(work, struct ath9k_htc_priv, ani_work.work);
|
||||
struct ath_hw *ah = priv->ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool longcal = false;
|
||||
|
@ -826,7 +958,8 @@ void ath9k_ani_work(struct work_struct *work)
|
|||
unsigned int timestamp = jiffies_to_msecs(jiffies);
|
||||
u32 cal_interval, short_cal_interval;
|
||||
|
||||
short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
|
||||
short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
|
||||
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
|
||||
|
||||
/* Only calibrate if awake */
|
||||
if (ah->power_mode != ATH9K_PM_AWAKE)
|
||||
|
@ -895,7 +1028,7 @@ set_timer:
|
|||
if (!common->ani.caldone)
|
||||
cal_interval = min(cal_interval, (u32)short_cal_interval);
|
||||
|
||||
ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
|
||||
ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
|
||||
msecs_to_jiffies(cal_interval));
|
||||
}
|
||||
|
||||
|
@ -903,7 +1036,7 @@ set_timer:
|
|||
/* mac80211 Callbacks */
|
||||
/**********************/
|
||||
|
||||
static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
|
@ -916,7 +1049,7 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
padsize = padpos & 3;
|
||||
if (padsize && skb->len > padpos) {
|
||||
if (skb_headroom(skb) < padsize)
|
||||
return -1;
|
||||
goto fail_tx;
|
||||
skb_push(skb, padsize);
|
||||
memmove(skb->data, skb->data + padsize, padpos);
|
||||
}
|
||||
|
@ -937,11 +1070,10 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
goto fail_tx;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
fail_tx:
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath9k_htc_start(struct ieee80211_hw *hw)
|
||||
|
@ -990,6 +1122,11 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
|
|||
|
||||
ath9k_host_rx_init(priv);
|
||||
|
||||
ret = ath9k_htc_update_cap_target(priv);
|
||||
if (ret)
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Failed to update capability in target\n");
|
||||
|
||||
priv->op_flags &= ~OP_INVALID;
|
||||
htc_start(priv->htc);
|
||||
|
||||
|
@ -1044,26 +1181,21 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
|
|||
cancel_work_sync(&priv->fatal_work);
|
||||
cancel_work_sync(&priv->ps_work);
|
||||
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
|
||||
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
||||
ath9k_htc_stop_ani(priv);
|
||||
ath9k_led_stop_brightness(priv);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* Remove monitor interface here */
|
||||
if (ah->opmode == NL80211_IFTYPE_MONITOR) {
|
||||
if (ath9k_htc_remove_monitor_interface(priv))
|
||||
ath_err(common, "Unable to remove monitor interface\n");
|
||||
else
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"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);
|
||||
}
|
||||
|
||||
/* Remove a monitor interface if it's present. */
|
||||
if (priv->ah->is_monitoring)
|
||||
ath9k_htc_remove_monitor_interface(priv);
|
||||
|
||||
ath9k_hw_phy_disable(ah);
|
||||
ath9k_hw_disable(ah);
|
||||
ath9k_htc_ps_restore(priv);
|
||||
|
@ -1087,10 +1219,24 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* Only one interface for now */
|
||||
if (priv->nvifs > 0) {
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
if (priv->nvifs >= ATH9K_HTC_MAX_VIF) {
|
||||
mutex_unlock(&priv->mutex);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (priv->num_ibss_vif ||
|
||||
(priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
|
||||
ath_err(common, "IBSS coexistence with other modes is not allowed\n");
|
||||
mutex_unlock(&priv->mutex);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (((vif->type == NL80211_IFTYPE_AP) ||
|
||||
(vif->type == NL80211_IFTYPE_ADHOC)) &&
|
||||
((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) {
|
||||
ath_err(common, "Max. number of beaconing interfaces reached\n");
|
||||
mutex_unlock(&priv->mutex);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
|
@ -1104,6 +1250,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
|
|||
case NL80211_IFTYPE_ADHOC:
|
||||
hvif.opmode = cpu_to_be32(HTC_M_IBSS);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
hvif.opmode = cpu_to_be32(HTC_M_HOSTAP);
|
||||
break;
|
||||
default:
|
||||
ath_err(common,
|
||||
"Interface type %d not yet supported\n", vif->type);
|
||||
|
@ -1111,34 +1260,39 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Attach a VIF of type: %d\n", vif->type);
|
||||
|
||||
priv->ah->opmode = vif->type;
|
||||
|
||||
/* Index starts from zero on the target */
|
||||
avp->index = hvif.index = priv->nvifs;
|
||||
avp->index = hvif.index = ffz(priv->vif_slot);
|
||||
hvif.rtsthreshold = cpu_to_be16(2304);
|
||||
WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
priv->nvifs++;
|
||||
|
||||
/*
|
||||
* We need a node in target to tx mgmt frames
|
||||
* before association.
|
||||
*/
|
||||
ret = ath9k_htc_add_station(priv, vif, NULL);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath9k_htc_update_cap_target(priv);
|
||||
if (ret)
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Failed to update capability in target\n");
|
||||
ath9k_htc_set_bssid_mask(priv, vif);
|
||||
|
||||
priv->vif_slot |= (1 << avp->index);
|
||||
priv->nvifs++;
|
||||
priv->vif = vif;
|
||||
|
||||
INC_VIF(priv, vif->type);
|
||||
ath9k_htc_set_opmode(priv);
|
||||
|
||||
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
||||
!(priv->op_flags & OP_ANI_RUNNING))
|
||||
ath9k_htc_start_ani(priv);
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index);
|
||||
|
||||
out:
|
||||
ath9k_htc_ps_restore(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
@ -1156,8 +1310,6 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
|
|||
int ret = 0;
|
||||
u8 cmd_rsp;
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
|
||||
|
@ -1166,10 +1318,27 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
|
|||
hvif.index = avp->index;
|
||||
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
|
||||
priv->nvifs--;
|
||||
priv->vif_slot &= ~(1 << avp->index);
|
||||
|
||||
ath9k_htc_remove_station(priv, vif, NULL);
|
||||
priv->vif = NULL;
|
||||
|
||||
DEC_VIF(priv, vif->type);
|
||||
ath9k_htc_set_opmode(priv);
|
||||
|
||||
/*
|
||||
* Stop ANI only if there are no associated station interfaces.
|
||||
*/
|
||||
if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
|
||||
priv->rearm_ani = false;
|
||||
ieee80211_iterate_active_interfaces_atomic(priv->hw,
|
||||
ath9k_htc_vif_iter, priv);
|
||||
if (!priv->rearm_ani)
|
||||
ath9k_htc_stop_ani(priv);
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface at idx: %d\n", avp->index);
|
||||
|
||||
ath9k_htc_ps_restore(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
@ -1205,13 +1374,11 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
|
|||
* IEEE80211_CONF_CHANGE_CHANNEL is handled.
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
|
||||
if (conf->flags & IEEE80211_CONF_MONITOR) {
|
||||
if (ath9k_htc_add_monitor_interface(priv))
|
||||
ath_err(common, "Failed to set monitor mode\n");
|
||||
else
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"HW opmode set to Monitor mode\n");
|
||||
}
|
||||
if ((conf->flags & IEEE80211_CONF_MONITOR) &&
|
||||
!priv->ah->is_monitoring)
|
||||
ath9k_htc_add_monitor_interface(priv);
|
||||
else if (priv->ah->is_monitoring)
|
||||
ath9k_htc_remove_monitor_interface(priv);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
|
@ -1434,68 +1601,83 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
|
|||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
struct ath_hw *ah = priv->ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool set_assoc;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC) {
|
||||
common->curaid = bss_conf->assoc ?
|
||||
bss_conf->aid : 0;
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
|
||||
bss_conf->assoc);
|
||||
/*
|
||||
* Set the HW AID/BSSID only for the first station interface
|
||||
* or in IBSS mode.
|
||||
*/
|
||||
set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) ||
|
||||
((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
|
||||
(priv->num_sta_vif == 1)));
|
||||
|
||||
if (bss_conf->assoc) {
|
||||
priv->op_flags |= OP_ASSOCIATED;
|
||||
ath_start_ani(priv);
|
||||
} else {
|
||||
priv->op_flags &= ~OP_ASSOCIATED;
|
||||
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC) {
|
||||
if (set_assoc) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
|
||||
bss_conf->assoc);
|
||||
|
||||
common->curaid = bss_conf->assoc ?
|
||||
bss_conf->aid : 0;
|
||||
|
||||
if (bss_conf->assoc)
|
||||
ath9k_htc_start_ani(priv);
|
||||
else
|
||||
ath9k_htc_stop_ani(priv);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
/* Set BSSID */
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
ath9k_hw_write_associd(ah);
|
||||
if (set_assoc) {
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
ath9k_hw_write_associd(ah);
|
||||
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"BSSID: %pM aid: 0x%x\n",
|
||||
common->curbssid, common->curaid);
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"BSSID: %pM aid: 0x%x\n",
|
||||
common->curbssid, common->curaid);
|
||||
}
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BEACON_INT) ||
|
||||
(changed & BSS_CHANGED_BEACON) ||
|
||||
((changed & BSS_CHANGED_BEACON_ENABLED) &&
|
||||
bss_conf->enable_beacon)) {
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
|
||||
priv->op_flags |= OP_ENABLE_BEACON;
|
||||
ath9k_htc_beacon_config(priv, vif);
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
|
||||
!bss_conf->enable_beacon) {
|
||||
priv->op_flags &= ~OP_ENABLE_BEACON;
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
|
||||
/*
|
||||
* Disable SWBA interrupt only if there are no
|
||||
* AP/IBSS interfaces.
|
||||
*/
|
||||
if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Beacon disabled for BSS: %pM\n",
|
||||
bss_conf->bssid);
|
||||
priv->op_flags &= ~OP_ENABLE_BEACON;
|
||||
ath9k_htc_beacon_config(priv, vif);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
/*
|
||||
* Reset the HW TSF for the first AP interface.
|
||||
*/
|
||||
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
|
||||
(priv->nvifs == 1) &&
|
||||
(priv->num_ap_vif == 1) &&
|
||||
(vif->type == NL80211_IFTYPE_AP)) {
|
||||
priv->op_flags |= OP_TSF_RESET;
|
||||
}
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Beacon interval changed for BSS: %pM\n",
|
||||
bss_conf->bssid);
|
||||
ath9k_htc_beacon_config(priv, vif);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
|
||||
bss_conf->use_short_preamble);
|
||||
if (bss_conf->use_short_preamble)
|
||||
priv->op_flags |= OP_PREAMBLE_SHORT;
|
||||
else
|
||||
priv->op_flags &= ~OP_PREAMBLE_SHORT;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
|
||||
bss_conf->use_cts_prot);
|
||||
if (bss_conf->use_cts_prot &&
|
||||
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
|
||||
priv->op_flags |= OP_PROTECT_ENABLE;
|
||||
else
|
||||
priv->op_flags &= ~OP_PROTECT_ENABLE;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
if (bss_conf->use_short_slot)
|
||||
ah->slottime = 9;
|
||||
|
@ -1558,6 +1740,8 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|||
struct ath9k_htc_sta *ista;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
break;
|
||||
|
@ -1582,6 +1766,8 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
|||
ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1594,8 +1780,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
|
|||
priv->op_flags |= OP_SCANNING;
|
||||
spin_unlock_bh(&priv->beacon_lock);
|
||||
cancel_work_sync(&priv->ps_work);
|
||||
if (priv->op_flags & OP_ASSOCIATED)
|
||||
cancel_delayed_work_sync(&priv->ath9k_ani_work);
|
||||
ath9k_htc_stop_ani(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
|
@ -1604,14 +1789,11 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
|
|||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
spin_lock_bh(&priv->beacon_lock);
|
||||
priv->op_flags &= ~OP_SCANNING;
|
||||
spin_unlock_bh(&priv->beacon_lock);
|
||||
if (priv->op_flags & OP_ASSOCIATED) {
|
||||
ath9k_htc_beacon_config(priv, priv->vif);
|
||||
ath_start_ani(priv);
|
||||
}
|
||||
ath9k_htc_ps_wakeup(priv);
|
||||
ath9k_htc_vif_reconfig(priv);
|
||||
ath9k_htc_ps_restore(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,9 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
|
|||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = tx_info->control.sta;
|
||||
struct ieee80211_vif *vif = tx_info->control.vif;
|
||||
struct ath9k_htc_sta *ista;
|
||||
struct ath9k_htc_vif *avp;
|
||||
struct ath9k_htc_tx_ctl tx_ctl;
|
||||
enum htc_endpoint_id epid;
|
||||
u16 qnum;
|
||||
|
@ -95,18 +97,31 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
|
|||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if (tx_info->control.vif &&
|
||||
(struct ath9k_htc_vif *) tx_info->control.vif->drv_priv)
|
||||
vif_idx = ((struct ath9k_htc_vif *)
|
||||
tx_info->control.vif->drv_priv)->index;
|
||||
else
|
||||
vif_idx = priv->nvifs;
|
||||
/*
|
||||
* Find out on which interface this packet has to be
|
||||
* sent out.
|
||||
*/
|
||||
if (vif) {
|
||||
avp = (struct ath9k_htc_vif *) vif->drv_priv;
|
||||
vif_idx = avp->index;
|
||||
} else {
|
||||
if (!priv->ah->is_monitoring) {
|
||||
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
|
||||
"VIF is null, but no monitor interface !\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vif_idx = priv->mon_vif_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out which station this packet is destined for.
|
||||
*/
|
||||
if (sta) {
|
||||
ista = (struct ath9k_htc_sta *) sta->drv_priv;
|
||||
sta_idx = ista->index;
|
||||
} else {
|
||||
sta_idx = 0;
|
||||
sta_idx = priv->vif_sta_pos[vif_idx];
|
||||
}
|
||||
|
||||
memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
|
||||
|
@ -141,7 +156,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
|
|||
|
||||
/* CTS-to-self */
|
||||
if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
|
||||
(priv->op_flags & OP_PROTECT_ENABLE))
|
||||
(vif && vif->bss_conf.use_cts_prot))
|
||||
flags |= ATH9K_HTC_TX_CTSONLY;
|
||||
|
||||
tx_hdr.flags = cpu_to_be32(flags);
|
||||
|
@ -217,6 +232,7 @@ static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
|
|||
void ath9k_tx_tasklet(unsigned long data)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
|
@ -228,12 +244,16 @@ void ath9k_tx_tasklet(unsigned long data)
|
|||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
fc = hdr->frame_control;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
vif = tx_info->control.vif;
|
||||
|
||||
memset(&tx_info->status, 0, sizeof(tx_info->status));
|
||||
|
||||
if (!vif)
|
||||
goto send_mac80211;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = ieee80211_find_sta(priv->vif, hdr->addr1);
|
||||
sta = ieee80211_find_sta(vif, hdr->addr1);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
ieee80211_tx_status(priv->hw, skb);
|
||||
|
@ -263,6 +283,7 @@ void ath9k_tx_tasklet(unsigned long data)
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
send_mac80211:
|
||||
/* Send status to mac80211 */
|
||||
ieee80211_tx_status(priv->hw, skb);
|
||||
}
|
||||
|
@ -386,7 +407,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
|
|||
*/
|
||||
if (((ah->opmode != NL80211_IFTYPE_AP) &&
|
||||
(priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
|
||||
(ah->opmode == NL80211_IFTYPE_MONITOR))
|
||||
ah->is_monitoring)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
|
||||
if (priv->rxfilter & FIF_CONTROL)
|
||||
|
@ -398,8 +419,13 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
|
|||
else
|
||||
rfilt |= ATH9K_RX_FILTER_BEACON;
|
||||
|
||||
if (conf_is_ht(&priv->hw->conf))
|
||||
if (conf_is_ht(&priv->hw->conf)) {
|
||||
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
|
||||
rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR;
|
||||
}
|
||||
|
||||
if (priv->rxfilter & FIF_PSPOLL)
|
||||
rfilt |= ATH9K_RX_FILTER_PSPOLL;
|
||||
|
||||
return rfilt;
|
||||
|
||||
|
@ -412,20 +438,12 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
|
|||
static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_hw *ah = priv->ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
u32 rfilt, mfilt[2];
|
||||
|
||||
/* configure rx filter */
|
||||
rfilt = ath9k_htc_calcrxfilter(priv);
|
||||
ath9k_hw_setrxfilter(ah, rfilt);
|
||||
|
||||
/* configure bssid mask */
|
||||
ath_hw_setbssidmask(common);
|
||||
|
||||
/* configure operational mode */
|
||||
ath9k_hw_setopmode(ah);
|
||||
|
||||
/* calculate and install multicast filter */
|
||||
mfilt[0] = mfilt[1] = ~0;
|
||||
ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
|
||||
|
@ -576,31 +594,29 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
|
|||
ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
|
||||
rxbuf->rxstatus.rs_flags);
|
||||
|
||||
if (priv->op_flags & OP_ASSOCIATED) {
|
||||
if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
|
||||
!rxbuf->rxstatus.rs_moreaggr)
|
||||
ATH_RSSI_LPF(priv->rx.last_rssi,
|
||||
rxbuf->rxstatus.rs_rssi);
|
||||
if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
|
||||
!rxbuf->rxstatus.rs_moreaggr)
|
||||
ATH_RSSI_LPF(priv->rx.last_rssi,
|
||||
rxbuf->rxstatus.rs_rssi);
|
||||
|
||||
last_rssi = priv->rx.last_rssi;
|
||||
last_rssi = priv->rx.last_rssi;
|
||||
|
||||
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||||
rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
|
||||
ATH_RSSI_EP_MULTIPLIER);
|
||||
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||||
rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
|
||||
ATH_RSSI_EP_MULTIPLIER);
|
||||
|
||||
if (rxbuf->rxstatus.rs_rssi < 0)
|
||||
rxbuf->rxstatus.rs_rssi = 0;
|
||||
if (rxbuf->rxstatus.rs_rssi < 0)
|
||||
rxbuf->rxstatus.rs_rssi = 0;
|
||||
|
||||
if (ieee80211_is_beacon(fc))
|
||||
priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
|
||||
}
|
||||
if (ieee80211_is_beacon(fc))
|
||||
priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
|
||||
|
||||
rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
|
||||
rx_status->band = hw->conf.channel->band;
|
||||
rx_status->freq = hw->conf.channel->center_freq;
|
||||
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
|
||||
rx_status->antenna = rxbuf->rxstatus.rs_antenna;
|
||||
rx_status->flag |= RX_FLAG_TSFT;
|
||||
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
@ -140,6 +140,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
|
|||
RATE(540, 0x0c, 0),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
|
||||
{ .throughput = 0 * 1024, .blink_time = 334 },
|
||||
{ .throughput = 1 * 1024, .blink_time = 260 },
|
||||
{ .throughput = 5 * 1024, .blink_time = 220 },
|
||||
{ .throughput = 10 * 1024, .blink_time = 190 },
|
||||
{ .throughput = 20 * 1024, .blink_time = 170 },
|
||||
{ .throughput = 50 * 1024, .blink_time = 150 },
|
||||
{ .throughput = 70 * 1024, .blink_time = 130 },
|
||||
{ .throughput = 100 * 1024, .blink_time = 110 },
|
||||
{ .throughput = 200 * 1024, .blink_time = 80 },
|
||||
{ .throughput = 300 * 1024, .blink_time = 50 },
|
||||
};
|
||||
#endif
|
||||
|
||||
static void ath9k_deinit_softc(struct ath_softc *sc);
|
||||
|
||||
/*
|
||||
|
@ -731,6 +746,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
|||
|
||||
ath9k_init_txpower_limits(sc);
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
/* must be initialized before ieee80211_register_hw */
|
||||
sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
|
||||
IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
|
||||
ARRAY_SIZE(ath9k_tpt_blink));
|
||||
#endif
|
||||
|
||||
/* Register with mac80211 */
|
||||
error = ieee80211_register_hw(hw);
|
||||
if (error)
|
||||
|
|
|
@ -910,6 +910,8 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
|
||||
|
||||
ieee80211_wake_queues(hw);
|
||||
ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
|
@ -923,6 +925,8 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
int r;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
ieee80211_stop_queues(hw);
|
||||
|
@ -1142,8 +1146,7 @@ mutex_unlock:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int ath9k_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
@ -1200,10 +1203,9 @@ static int ath9k_tx(struct ieee80211_hw *hw,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
exit:
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
|
@ -1214,9 +1216,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
if (led_blink)
|
||||
cancel_delayed_work_sync(&sc->ath_led_blink_work);
|
||||
|
||||
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||
cancel_work_sync(&sc->paprd_work);
|
||||
|
@ -2131,7 +2130,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
|
|||
{
|
||||
#define ATH_FLUSH_TIMEOUT 60 /* ms */
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_txq *txq;
|
||||
struct ath_txq *txq = NULL;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
int i, j, npend = 0;
|
||||
|
|
|
@ -983,7 +983,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
|
|||
rx_status->freq = hw->conf.channel->center_freq;
|
||||
rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
|
||||
rx_status->antenna = rx_stats->rs_antenna;
|
||||
rx_status->flag |= RX_FLAG_TSFT;
|
||||
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -878,6 +878,7 @@
|
|||
enum ath_usb_dev {
|
||||
AR9280_USB = 1, /* AR7010 + AR9280, UB94 */
|
||||
AR9287_USB = 2, /* AR7010 + AR9287, UB95 */
|
||||
STORAGE_DEVICE = 3,
|
||||
};
|
||||
|
||||
#define AR_DEVID_7010(_ah) \
|
||||
|
|
|
@ -123,12 +123,8 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
|
|||
void ath9k_swba_tasklet(unsigned long data)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
|
||||
ath_dbg(common, ATH_DBG_WMI, "SWBA Event received\n");
|
||||
|
||||
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
|
||||
|
||||
}
|
||||
|
||||
void ath9k_fatal_work(struct work_struct *work)
|
||||
|
|
|
@ -534,7 +534,7 @@ void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len);
|
|||
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
|
||||
|
||||
/* TX */
|
||||
int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void carl9170_tx_janitor(struct work_struct *work);
|
||||
void carl9170_tx_process_status(struct ar9170 *ar,
|
||||
const struct carl9170_rsp *cmd);
|
||||
|
|
|
@ -1339,7 +1339,7 @@ err_unlock_rcu:
|
|||
return false;
|
||||
}
|
||||
|
||||
int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ar9170 *ar = hw->priv;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
@ -1373,12 +1373,11 @@ int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
carl9170_tx(ar);
|
||||
return NETDEV_TX_OK;
|
||||
return;
|
||||
|
||||
err_free:
|
||||
ar->tx_dropped++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
void carl9170_tx_scheduler(struct ar9170 *ar)
|
||||
|
|
|
@ -3203,7 +3203,7 @@ static void b43_tx_work(struct work_struct *work)
|
|||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static int b43_op_tx(struct ieee80211_hw *hw,
|
||||
static void b43_op_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct b43_wl *wl = hw_to_b43_wl(hw);
|
||||
|
@ -3211,14 +3211,12 @@ static int b43_op_tx(struct ieee80211_hw *hw,
|
|||
if (unlikely(skb->len < 2 + 2 + 6)) {
|
||||
/* Too short, this can't be a valid frame. */
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
return;
|
||||
}
|
||||
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
|
||||
|
||||
skb_queue_tail(&wl->tx_queue, skb);
|
||||
ieee80211_queue_work(wl->hw, &wl->tx_work);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static void b43_qos_params_upload(struct b43_wldev *dev,
|
||||
|
|
|
@ -430,9 +430,9 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
|
|||
bool workaround = false;
|
||||
|
||||
if (sprom->revision < 4)
|
||||
workaround = (binfo->vendor != PCI_VENDOR_ID_BROADCOM ||
|
||||
binfo->type != 0x46D ||
|
||||
binfo->rev < 0x41);
|
||||
workaround = (binfo->vendor != PCI_VENDOR_ID_BROADCOM &&
|
||||
binfo->type == 0x46D &&
|
||||
binfo->rev >= 0x41);
|
||||
else
|
||||
workaround =
|
||||
!(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS);
|
||||
|
@ -1281,17 +1281,17 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
|
|||
B43_NPHY_TABLE_DATALO, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
b43_nphy_set_rf_sequence(dev, 5,
|
||||
rfseq_events, rfseq_delays, 3);
|
||||
b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
|
||||
~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
|
||||
0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
b43_phy_maskset(dev, B43_PHY_N(0xC5D),
|
||||
0xFF80, 4);
|
||||
}
|
||||
|
||||
b43_nphy_set_rf_sequence(dev, 5,
|
||||
rfseq_events, rfseq_delays, 3);
|
||||
b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
|
||||
~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
|
||||
0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
|
||||
|
||||
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
|
||||
b43_phy_maskset(dev, B43_PHY_N(0xC5D),
|
||||
0xFF80, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2128,7 +2128,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
|
|||
save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
|
||||
save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
|
||||
save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
|
||||
} else if (dev->phy.rev == 2) {
|
||||
} else {
|
||||
save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
|
||||
save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
|
||||
save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
|
||||
|
@ -2179,7 +2179,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
|
|||
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
|
||||
b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
|
||||
b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
|
||||
} else if (dev->phy.rev == 2) {
|
||||
} else {
|
||||
b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[0]);
|
||||
b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[1]);
|
||||
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[2]);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -109,6 +109,33 @@ b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq);
|
|||
#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
|
||||
#define B43_NTAB_C1_LOFEEDTH_SIZE 128
|
||||
|
||||
/* Static N-PHY tables, PHY revision >= 3 */
|
||||
#define B43_NTAB_FRAMESTRUCT_R3 B43_NTAB32(10, 000) /* frame struct */
|
||||
#define B43_NTAB_PILOT_R3 B43_NTAB16(11, 000) /* pilot */
|
||||
#define B43_NTAB_TMAP_R3 B43_NTAB32(12, 000) /* TM AP */
|
||||
#define B43_NTAB_INTLEVEL_R3 B43_NTAB32(13, 000) /* INT LV */
|
||||
#define B43_NTAB_TDTRN_R3 B43_NTAB32(14, 000) /* TD TRN */
|
||||
#define B43_NTAB_NOISEVAR0_R3 B43_NTAB32(16, 000) /* noise variance 0 */
|
||||
#define B43_NTAB_NOISEVAR1_R3 B43_NTAB32(16, 128) /* noise variance 1 */
|
||||
#define B43_NTAB_MCS_R3 B43_NTAB16(18, 000) /* MCS */
|
||||
#define B43_NTAB_TDI20A0_R3 B43_NTAB32(19, 128) /* TDI 20/0 */
|
||||
#define B43_NTAB_TDI20A1_R3 B43_NTAB32(19, 256) /* TDI 20/1 */
|
||||
#define B43_NTAB_TDI40A0_R3 B43_NTAB32(19, 640) /* TDI 40/0 */
|
||||
#define B43_NTAB_TDI40A1_R3 B43_NTAB32(19, 768) /* TDI 40/1 */
|
||||
#define B43_NTAB_PILOTLT_R3 B43_NTAB32(20, 000) /* PLT lookup */
|
||||
#define B43_NTAB_CHANEST_R3 B43_NTAB32(22, 000) /* channel estimate */
|
||||
#define B43_NTAB_FRAMELT_R3 B43_NTAB8 (24, 000) /* frame lookup */
|
||||
#define B43_NTAB_C0_ESTPLT_R3 B43_NTAB8 (26, 000) /* estimated power lookup 0 */
|
||||
#define B43_NTAB_C1_ESTPLT_R3 B43_NTAB8 (27, 000) /* estimated power lookup 1 */
|
||||
#define B43_NTAB_C0_ADJPLT_R3 B43_NTAB8 (26, 064) /* adjusted power lookup 0 */
|
||||
#define B43_NTAB_C1_ADJPLT_R3 B43_NTAB8 (27, 064) /* adjusted power lookup 1 */
|
||||
#define B43_NTAB_C0_GAINCTL_R3 B43_NTAB32(26, 192) /* gain control lookup 0 */
|
||||
#define B43_NTAB_C1_GAINCTL_R3 B43_NTAB32(27, 192) /* gain control lookup 1 */
|
||||
#define B43_NTAB_C0_IQLT_R3 B43_NTAB32(26, 320) /* I/Q lookup 0 */
|
||||
#define B43_NTAB_C1_IQLT_R3 B43_NTAB32(27, 320) /* I/Q lookup 1 */
|
||||
#define B43_NTAB_C0_LOFEEDTH_R3 B43_NTAB16(26, 448) /* Local Oscillator Feed Through lookup 0 */
|
||||
#define B43_NTAB_C1_LOFEEDTH_R3 B43_NTAB16(27, 448) /* Local Oscillator Feed Through lookup 1 */
|
||||
|
||||
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18
|
||||
#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18
|
||||
|
|
|
@ -32,6 +32,36 @@
|
|||
#include "dma.h"
|
||||
#include "pio.h"
|
||||
|
||||
static const struct b43_tx_legacy_rate_phy_ctl_entry b43_tx_legacy_rate_phy_ctl[] = {
|
||||
{ B43_CCK_RATE_1MB, 0x0, 0x0 },
|
||||
{ B43_CCK_RATE_2MB, 0x0, 0x1 },
|
||||
{ B43_CCK_RATE_5MB, 0x0, 0x2 },
|
||||
{ B43_CCK_RATE_11MB, 0x0, 0x3 },
|
||||
{ B43_OFDM_RATE_6MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_BPSK },
|
||||
{ B43_OFDM_RATE_9MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_BPSK },
|
||||
{ B43_OFDM_RATE_12MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_QPSK },
|
||||
{ B43_OFDM_RATE_18MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QPSK },
|
||||
{ B43_OFDM_RATE_24MB, B43_TXH_PHY1_CRATE_1_2, B43_TXH_PHY1_MODUL_QAM16 },
|
||||
{ B43_OFDM_RATE_36MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QAM16 },
|
||||
{ B43_OFDM_RATE_48MB, B43_TXH_PHY1_CRATE_2_3, B43_TXH_PHY1_MODUL_QAM64 },
|
||||
{ B43_OFDM_RATE_54MB, B43_TXH_PHY1_CRATE_3_4, B43_TXH_PHY1_MODUL_QAM64 },
|
||||
};
|
||||
|
||||
static const struct b43_tx_legacy_rate_phy_ctl_entry *
|
||||
b43_tx_legacy_rate_phy_ctl_ent(u8 bitrate)
|
||||
{
|
||||
const struct b43_tx_legacy_rate_phy_ctl_entry *e;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(b43_tx_legacy_rate_phy_ctl); i++) {
|
||||
e = &(b43_tx_legacy_rate_phy_ctl[i]);
|
||||
if (e->bitrate == bitrate)
|
||||
return e;
|
||||
}
|
||||
|
||||
B43_WARN_ON(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extract the bitrate index out of a CCK PLCP header. */
|
||||
static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
|
||||
|
@ -145,6 +175,34 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
|
|||
}
|
||||
}
|
||||
|
||||
static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate)
|
||||
{
|
||||
const struct b43_phy *phy = &dev->phy;
|
||||
const struct b43_tx_legacy_rate_phy_ctl_entry *e;
|
||||
u16 control = 0;
|
||||
u16 bw;
|
||||
|
||||
if (phy->type == B43_PHYTYPE_LP)
|
||||
bw = B43_TXH_PHY1_BW_20;
|
||||
else /* FIXME */
|
||||
bw = B43_TXH_PHY1_BW_20;
|
||||
|
||||
if (0) { /* FIXME: MIMO */
|
||||
} else if (b43_is_cck_rate(bitrate) && phy->type != B43_PHYTYPE_LP) {
|
||||
control = bw;
|
||||
} else {
|
||||
control = bw;
|
||||
e = b43_tx_legacy_rate_phy_ctl_ent(bitrate);
|
||||
if (e) {
|
||||
control |= e->coding_rate;
|
||||
control |= e->modulation;
|
||||
}
|
||||
control |= B43_TXH_PHY1_MODE_SISO;
|
||||
}
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
static u8 b43_calc_fallback_rate(u8 bitrate)
|
||||
{
|
||||
switch (bitrate) {
|
||||
|
@ -437,6 +495,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
|
||||
else
|
||||
extra_ft |= B43_TXH_EFT_RTSFB_CCK;
|
||||
|
||||
if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS &&
|
||||
phy->type == B43_PHYTYPE_N) {
|
||||
txhdr->phy_ctl1_rts = cpu_to_le16(
|
||||
b43_generate_tx_phy_ctl1(dev, rts_rate));
|
||||
txhdr->phy_ctl1_rts_fb = cpu_to_le16(
|
||||
b43_generate_tx_phy_ctl1(dev, rts_rate_fb));
|
||||
}
|
||||
}
|
||||
|
||||
/* Magic cookie */
|
||||
|
@ -445,6 +511,13 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
else
|
||||
txhdr->new_format.cookie = cpu_to_le16(cookie);
|
||||
|
||||
if (phy->type == B43_PHYTYPE_N) {
|
||||
txhdr->phy_ctl1 =
|
||||
cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate));
|
||||
txhdr->phy_ctl1_fb =
|
||||
cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate_fb));
|
||||
}
|
||||
|
||||
/* Apply the bitfields */
|
||||
txhdr->mac_ctl = cpu_to_le32(mac_ctl);
|
||||
txhdr->phy_ctl = cpu_to_le16(phy_ctl);
|
||||
|
@ -652,7 +725,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
|||
status.mactime += mactime;
|
||||
if (low_mactime_now <= mactime)
|
||||
status.mactime -= 0x10000;
|
||||
status.flag |= RX_FLAG_TSFT;
|
||||
status.flag |= RX_FLAG_MACTIME_MPDU;
|
||||
}
|
||||
|
||||
chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
|
||||
|
|
|
@ -73,6 +73,12 @@ struct b43_txhdr {
|
|||
} __packed;
|
||||
} __packed;
|
||||
|
||||
struct b43_tx_legacy_rate_phy_ctl_entry {
|
||||
u8 bitrate;
|
||||
u16 coding_rate;
|
||||
u16 modulation;
|
||||
};
|
||||
|
||||
/* MAC TX control */
|
||||
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
|
||||
#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */
|
||||
|
|
|
@ -2442,8 +2442,8 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int b43legacy_op_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
static void b43legacy_op_tx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
||||
struct b43legacy_wldev *dev = wl->current_dev;
|
||||
|
@ -2466,7 +2466,6 @@ out:
|
|||
/* Drop the packet. */
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
|
|
|
@ -572,7 +572,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
|
|||
status.mactime += mactime;
|
||||
if (low_mactime_now <= mactime)
|
||||
status.mactime -= 0x10000;
|
||||
status.flag |= RX_FLAG_TSFT;
|
||||
status.flag |= RX_FLAG_MACTIME_MPDU;
|
||||
}
|
||||
|
||||
chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
config IWLWIFI_LEGACY
|
||||
tristate "Intel Wireless Wifi legacy devices"
|
||||
depends on PCI && MAC80211
|
||||
select FW_LOADER
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select MAC80211_LEDS
|
||||
|
||||
menu "Debugging Options"
|
||||
depends on IWLWIFI_LEGACY
|
||||
|
||||
config IWLWIFI_LEGACY_DEBUG
|
||||
bool "Enable full debugging output in 4965 and 3945 drivers"
|
||||
depends on IWLWIFI_LEGACY
|
||||
---help---
|
||||
This option will enable debug tracing output for the iwlwifilegacy
|
||||
drivers.
|
||||
|
||||
This will result in the kernel module being ~100k larger. You can
|
||||
control which debug output is sent to the kernel log by setting the
|
||||
value in
|
||||
|
||||
/sys/class/net/wlan0/device/debug_level
|
||||
|
||||
This entry will only exist if this option is enabled.
|
||||
|
||||
To set a value, simply echo an 8-byte hex value to the same file:
|
||||
|
||||
% echo 0x43fff > /sys/class/net/wlan0/device/debug_level
|
||||
|
||||
You can find the list of debug mask values in:
|
||||
drivers/net/wireless/iwlwifilegacy/iwl-debug.h
|
||||
|
||||
If this is your first time using this driver, you should say Y here
|
||||
as the debug information can assist others in helping you resolve
|
||||
any problems you may encounter.
|
||||
|
||||
config IWLWIFI_LEGACY_DEBUGFS
|
||||
bool "4965 and 3945 debugfs support"
|
||||
depends on IWLWIFI_LEGACY && MAC80211_DEBUGFS
|
||||
---help---
|
||||
Enable creation of debugfs files for the iwlwifilegacy drivers. This
|
||||
is a low-impact option that allows getting insight into the
|
||||
driver's state at runtime.
|
||||
|
||||
config IWLWIFI_LEGACY_DEVICE_TRACING
|
||||
bool "iwlwifilegacy legacy device access tracing"
|
||||
depends on IWLWIFI_LEGACY
|
||||
depends on EVENT_TRACING
|
||||
help
|
||||
Say Y here to trace all commands, including TX frames and IO
|
||||
accesses, sent to the device. If you say yes, iwlwifilegacy will
|
||||
register with the ftrace framework for event tracing and dump
|
||||
all this information to the ringbuffer, you may need to
|
||||
increase the ringbuffer size. See the ftrace documentation
|
||||
for more information.
|
||||
|
||||
When tracing is not enabled, this option still has some
|
||||
(though rather small) overhead.
|
||||
|
||||
If unsure, say Y so we can help you better when problems
|
||||
occur.
|
||||
endmenu
|
||||
|
||||
config IWL4965
|
||||
tristate "Intel Wireless WiFi 4965AGN (iwl4965)"
|
||||
depends on IWLWIFI_LEGACY
|
||||
---help---
|
||||
This option enables support for
|
||||
|
||||
Select to build the driver supporting the:
|
||||
|
||||
Intel Wireless WiFi Link 4965AGN
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
|
||||
If you want to compile the driver as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want),
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwl4965.
|
||||
|
||||
config IWL3945
|
||||
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
|
||||
depends on IWLWIFI_LEGACY
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
Intel PRO/Wireless 3945ABG/BG Network Connection
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
|
||||
If you want to compile the driver as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want),
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwl3945.
|
|
@ -0,0 +1,25 @@
|
|||
obj-$(CONFIG_IWLWIFI_LEGACY) += iwl-legacy.o
|
||||
iwl-legacy-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
|
||||
iwl-legacy-objs += iwl-rx.o iwl-tx.o iwl-sta.o
|
||||
iwl-legacy-objs += iwl-scan.o iwl-led.o
|
||||
iwl-legacy-$(CONFIG_IWLWIFI_LEGACY_DEBUGFS) += iwl-debugfs.o
|
||||
iwl-legacy-$(CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING) += iwl-devtrace.o
|
||||
|
||||
iwl-legacy-objs += $(iwl-legacy-m)
|
||||
|
||||
CFLAGS_iwl-devtrace.o := -I$(src)
|
||||
|
||||
# 4965
|
||||
obj-$(CONFIG_IWL4965) += iwl4965.o
|
||||
iwl4965-objs := iwl-4965.o iwl4965-base.o iwl-4965-rs.o iwl-4965-led.o
|
||||
iwl4965-objs += iwl-4965-ucode.o iwl-4965-tx.o
|
||||
iwl4965-objs += iwl-4965-lib.o iwl-4965-rx.o iwl-4965-calib.o
|
||||
iwl4965-objs += iwl-4965-sta.o iwl-4965-eeprom.o
|
||||
iwl4965-$(CONFIG_IWLWIFI_LEGACY_DEBUGFS) += iwl-4965-debugfs.o
|
||||
|
||||
# 3945
|
||||
obj-$(CONFIG_IWL3945) += iwl3945.o
|
||||
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
|
||||
iwl3945-$(CONFIG_IWLWIFI_LEGACY_DEBUGFS) += iwl-3945-debugfs.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -60,12 +60,13 @@ ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
|
|||
int bufsz = sizeof(struct iwl39_statistics_rx_phy) * 40 +
|
||||
sizeof(struct iwl39_statistics_rx_non_phy) * 40 + 400;
|
||||
ssize_t ret;
|
||||
struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
|
||||
struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm,
|
||||
*max_ofdm;
|
||||
struct iwl39_statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
|
||||
struct iwl39_statistics_rx_non_phy *general, *accum_general;
|
||||
struct iwl39_statistics_rx_non_phy *delta_general, *max_general;
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
|
@ -335,7 +336,7 @@ ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
|
|||
ssize_t ret;
|
||||
struct iwl39_statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
|
@ -434,7 +435,7 @@ ssize_t iwl3945_ucode_general_stats_read(struct file *file,
|
|||
struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
|
||||
struct iwl39_statistics_div *div, *accum_div, *delta_div, *max_div;
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
#include "iwl-core.h"
|
||||
#include "iwl-debug.h"
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
ssize_t iwl3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t iwl3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -185,4 +185,3 @@ struct iwl3945_tfd {
|
|||
|
||||
|
||||
#endif /* __iwl_3945_fh_h__ */
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -164,12 +164,11 @@ struct iwl3945_eeprom {
|
|||
/*
|
||||
* Per-channel regulatory data.
|
||||
*
|
||||
* Each channel that *might* be supported by 3945 or 4965 has a fixed location
|
||||
* Each channel that *might* be supported by 3945 has a fixed location
|
||||
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
|
||||
* txpower (MSB).
|
||||
*
|
||||
* Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
|
||||
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
|
||||
* Entries immediately below are for 20 MHz channel width.
|
||||
*
|
||||
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
*/
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -56,7 +56,7 @@ static int iwl3945_send_led_cmd(struct iwl_priv *priv,
|
|||
.callback = NULL,
|
||||
};
|
||||
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
return iwl_legacy_send_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
const struct iwl_led_ops iwl3945_led_ops = {
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -89,7 +89,7 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
|
|||
};
|
||||
|
||||
#define IWL_RATE_MAX_WINDOW 62
|
||||
#define IWL_RATE_FLUSH (3*HZ)
|
||||
#define IWL_RATE_FLUSH (3*HZ)
|
||||
#define IWL_RATE_WIN_FLUSH (HZ/2)
|
||||
#define IWL39_RATE_HIGH_TH 11520
|
||||
#define IWL_SUCCESS_UP_TH 8960
|
||||
|
@ -394,18 +394,18 @@ out:
|
|||
IWL_DEBUG_INFO(priv, "leave\n");
|
||||
}
|
||||
|
||||
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
static void *iwl3945_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||
{
|
||||
return hw->priv;
|
||||
}
|
||||
|
||||
/* rate scale requires free function to be implemented */
|
||||
static void rs_free(void *priv)
|
||||
static void iwl3945_rs_free(void *priv)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp)
|
||||
static void *iwl3945_rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp)
|
||||
{
|
||||
struct iwl3945_rs_sta *rs_sta;
|
||||
struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
|
||||
|
@ -423,7 +423,7 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp)
|
|||
return rs_sta;
|
||||
}
|
||||
|
||||
static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta,
|
||||
static void iwl3945_rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta,
|
||||
void *priv_sta)
|
||||
{
|
||||
struct iwl3945_rs_sta *rs_sta = priv_sta;
|
||||
|
@ -438,12 +438,12 @@ static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta,
|
|||
|
||||
|
||||
/**
|
||||
* rs_tx_status - Update rate control values based on Tx results
|
||||
* iwl3945_rs_tx_status - Update rate control values based on Tx results
|
||||
*
|
||||
* NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
|
||||
* the hardware for each rate.
|
||||
*/
|
||||
static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
|
||||
static void iwl3945_rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -612,7 +612,7 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
|
|||
}
|
||||
|
||||
/**
|
||||
* rs_get_rate - find the rate for the requested packet
|
||||
* iwl3945_rs_get_rate - find the rate for the requested packet
|
||||
*
|
||||
* Returns the ieee80211_rate structure allocated by the driver.
|
||||
*
|
||||
|
@ -627,7 +627,7 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
|
|||
* rate table and must reference the driver allocated rate table
|
||||
*
|
||||
*/
|
||||
static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
||||
static void iwl3945_rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
||||
void *priv_sta, struct ieee80211_tx_rate_control *txrc)
|
||||
{
|
||||
struct ieee80211_supported_band *sband = txrc->sband;
|
||||
|
@ -644,7 +644,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
|||
u32 fail_count;
|
||||
s8 scale_action = 0;
|
||||
unsigned long flags;
|
||||
u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
|
||||
u16 rate_mask;
|
||||
s8 max_rate_idx = -1;
|
||||
struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
@ -899,7 +899,8 @@ static void iwl3945_remove_debugfs(void *priv, void *priv_sta)
|
|||
* the station is added. Since mac80211 calls this function before a
|
||||
* station is added we ignore it.
|
||||
*/
|
||||
static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
|
||||
static void iwl3945_rs_rate_init_stub(void *priv_r,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta)
|
||||
{
|
||||
}
|
||||
|
@ -907,13 +908,13 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba
|
|||
static struct rate_control_ops rs_ops = {
|
||||
.module = NULL,
|
||||
.name = RS_NAME,
|
||||
.tx_status = rs_tx_status,
|
||||
.get_rate = rs_get_rate,
|
||||
.rate_init = rs_rate_init_stub,
|
||||
.alloc = rs_alloc,
|
||||
.free = rs_free,
|
||||
.alloc_sta = rs_alloc_sta,
|
||||
.free_sta = rs_free_sta,
|
||||
.tx_status = iwl3945_rs_tx_status,
|
||||
.get_rate = iwl3945_rs_get_rate,
|
||||
.rate_init = iwl3945_rs_rate_init_stub,
|
||||
.alloc = iwl3945_rs_alloc,
|
||||
.free = iwl3945_rs_free,
|
||||
.alloc_sta = iwl3945_rs_alloc_sta,
|
||||
.free_sta = iwl3945_rs_free_sta,
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
.add_sta_debugfs = iwl3945_add_debugfs,
|
||||
.remove_sta_debugfs = iwl3945_remove_debugfs,
|
||||
|
@ -991,5 +992,3 @@ void iwl3945_rate_control_unregister(void)
|
|||
{
|
||||
ieee80211_rate_control_unregister(&rs_ops);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -51,7 +51,6 @@
|
|||
#include "iwl-led.h"
|
||||
#include "iwl-3945-led.h"
|
||||
#include "iwl-3945-debugfs.h"
|
||||
#include "iwl-legacy.h"
|
||||
|
||||
#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
|
||||
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
|
||||
|
@ -172,14 +171,14 @@ void iwl3945_disable_events(struct iwl_priv *priv)
|
|||
return;
|
||||
}
|
||||
|
||||
disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32)));
|
||||
array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32)));
|
||||
disable_ptr = iwl_legacy_read_targ_mem(priv, base + (4 * sizeof(u32)));
|
||||
array_size = iwl_legacy_read_targ_mem(priv, base + (5 * sizeof(u32)));
|
||||
|
||||
if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
|
||||
IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n",
|
||||
disable_ptr);
|
||||
for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
|
||||
iwl_write_targ_mem(priv,
|
||||
iwl_legacy_write_targ_mem(priv,
|
||||
disable_ptr + (i * sizeof(u32)),
|
||||
evt_disable[i]);
|
||||
|
||||
|
@ -202,7 +201,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
|
||||
|
||||
static const char *iwl3945_get_tx_fail_reason(u32 status)
|
||||
|
@ -255,7 +254,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
|
|||
break;
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
|
||||
iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
|
||||
iwl_legacy_is_associated(priv, IWL_RXON_CTX_BSS)) {
|
||||
if (rate == IWL_RATE_11M_INDEX)
|
||||
next_rate = IWL_RATE_5M_INDEX;
|
||||
}
|
||||
|
@ -285,8 +284,9 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
|
|||
|
||||
BUG_ON(txq_id == IWL39_CMD_QUEUE_NUM);
|
||||
|
||||
for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
|
||||
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||
for (index = iwl_legacy_queue_inc_wrap(index, q->n_bd);
|
||||
q->read_ptr != index;
|
||||
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||
|
||||
tx_info = &txq->txb[txq->q.read_ptr];
|
||||
ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
|
||||
|
@ -294,10 +294,10 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
|
|||
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
|
||||
}
|
||||
|
||||
if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
|
||||
if (iwl_legacy_queue_space(q) > q->low_mark && (txq_id >= 0) &&
|
||||
(txq_id != IWL39_CMD_QUEUE_NUM) &&
|
||||
priv->mac80211_registered)
|
||||
iwl_wake_queue(priv, txq);
|
||||
iwl_legacy_wake_queue(priv, txq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -317,7 +317,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
|
|||
int rate_idx;
|
||||
int fail;
|
||||
|
||||
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
|
||||
if ((index >= txq->q.n_bd) || (iwl_legacy_queue_used(&txq->q, index) == 0)) {
|
||||
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
|
||||
"is out of range [0-%d] %d %d\n", txq_id,
|
||||
index, txq->q.n_bd, txq->q.write_ptr,
|
||||
|
@ -363,12 +363,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
|
|||
* RX handler implementations
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/*
|
||||
* based on the assumption of all statistics counter are in DWORD
|
||||
* FIXME: This function is for debugging, do not deal with
|
||||
* the case of counters roll-over.
|
||||
*/
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
|
||||
__le32 *stats)
|
||||
{
|
||||
|
@ -410,10 +405,10 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
|
|||
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
|
||||
(int)sizeof(struct iwl3945_notif_statistics),
|
||||
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
|
||||
#endif
|
||||
iwl_recover_from_statistics(priv, pkt);
|
||||
iwl_legacy_recover_from_statistics(priv, pkt);
|
||||
|
||||
memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
|
||||
}
|
||||
|
@ -425,7 +420,7 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
|
|||
__le32 *flag = (__le32 *)&pkt->u.raw;
|
||||
|
||||
if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
memset(&priv->_3945.accum_statistics, 0,
|
||||
sizeof(struct iwl3945_notif_statistics));
|
||||
memset(&priv->_3945.delta_statistics, 0,
|
||||
|
@ -496,14 +491,14 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
|
|||
}
|
||||
|
||||
if (!iwl3945_mod_params.sw_crypto)
|
||||
iwl_set_decrypted_flag(priv,
|
||||
iwl_legacy_set_decrypted_flag(priv,
|
||||
(struct ieee80211_hdr *)rxb_addr(rxb),
|
||||
le32_to_cpu(rx_end->status), stats);
|
||||
|
||||
skb_add_rx_frag(skb, 0, rxb->page,
|
||||
(void *)rx_hdr->payload - (void *)pkt, len);
|
||||
|
||||
iwl_update_stats(priv, false, fc, len);
|
||||
iwl_legacy_update_stats(priv, false, fc, len);
|
||||
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
|
||||
|
||||
ieee80211_rx(priv->hw, skb);
|
||||
|
@ -576,7 +571,8 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
|
|||
rx_status.signal, rx_status.signal,
|
||||
rx_status.rate_idx);
|
||||
|
||||
iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
|
||||
iwl_legacy_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len),
|
||||
header);
|
||||
|
||||
if (network_packet) {
|
||||
priv->_3945.last_beacon_time =
|
||||
|
@ -744,7 +740,7 @@ static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
|
|||
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
|
||||
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
|
||||
station->sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
iwl_send_add_sta(priv, &station->sta, CMD_ASYNC);
|
||||
iwl_legacy_send_add_sta(priv, &station->sta, CMD_ASYNC);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
|
||||
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
|
||||
|
@ -759,7 +755,7 @@ static void iwl3945_set_pwr_vmain(struct iwl_priv *priv)
|
|||
* to set power to V_AUX, do
|
||||
|
||||
if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) {
|
||||
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
iwl_legacy_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
|
||||
~APMG_PS_CTRL_MSK_PWR_SRC);
|
||||
|
||||
|
@ -769,7 +765,7 @@ static void iwl3945_set_pwr_vmain(struct iwl_priv *priv)
|
|||
}
|
||||
*/
|
||||
|
||||
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
iwl_legacy_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
|
||||
~APMG_PS_CTRL_MSK_PWR_SRC);
|
||||
|
||||
|
@ -779,10 +775,11 @@ static void iwl3945_set_pwr_vmain(struct iwl_priv *priv)
|
|||
|
||||
static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
||||
{
|
||||
iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
|
||||
iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma);
|
||||
iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
|
||||
iwl_write_direct32(priv, FH39_RCSR_CONFIG(0),
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0),
|
||||
rxq->rb_stts_dma);
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_CONFIG(0),
|
||||
FH39_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
|
||||
FH39_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
|
||||
FH39_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
|
||||
|
@ -793,7 +790,7 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
|||
FH39_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
|
||||
|
||||
/* fake read to flush all prev I/O */
|
||||
iwl_read_direct32(priv, FH39_RSSR_CTRL);
|
||||
iwl_legacy_read_direct32(priv, FH39_RSSR_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -802,23 +799,23 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
|
|||
{
|
||||
|
||||
/* bypass mode */
|
||||
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
|
||||
|
||||
/* RA 0 is active */
|
||||
iwl_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01);
|
||||
|
||||
/* all 6 fifo are active */
|
||||
iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f);
|
||||
|
||||
iwl_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
|
||||
iwl_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
|
||||
iwl_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004);
|
||||
iwl_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
|
||||
|
||||
iwl_write_direct32(priv, FH39_TSSR_CBB_BASE,
|
||||
iwl_legacy_write_direct32(priv, FH39_TSSR_CBB_BASE,
|
||||
priv->_3945.shared_phys);
|
||||
|
||||
iwl_write_direct32(priv, FH39_TSSR_MSG_CONFIG,
|
||||
iwl_legacy_write_direct32(priv, FH39_TSSR_MSG_CONFIG,
|
||||
FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
|
||||
FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
|
||||
FH39_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
|
||||
|
@ -844,7 +841,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
|
|||
iwl3945_hw_txq_ctx_free(priv);
|
||||
|
||||
/* allocate tx queue structure */
|
||||
rc = iwl_alloc_txq_mem(priv);
|
||||
rc = iwl_legacy_alloc_txq_mem(priv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -857,8 +854,8 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
|
|||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
|
||||
slots_num = (txq_id == IWL39_CMD_QUEUE_NUM) ?
|
||||
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
|
||||
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
|
||||
txq_id);
|
||||
rc = iwl_legacy_tx_queue_init(priv, &priv->txq[txq_id],
|
||||
slots_num, txq_id);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
|
||||
goto error;
|
||||
|
@ -875,21 +872,23 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
|
|||
|
||||
/*
|
||||
* Start up 3945's basic functionality after it has been reset
|
||||
* (e.g. after platform boot, or shutdown via iwl_apm_stop())
|
||||
* (e.g. after platform boot, or shutdown via iwl_legacy_apm_stop())
|
||||
* NOTE: This does not load uCode nor start the embedded processor
|
||||
*/
|
||||
static int iwl3945_apm_init(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = iwl_apm_init(priv);
|
||||
int ret = iwl_legacy_apm_init(priv);
|
||||
|
||||
/* Clear APMG (NIC's internal power management) interrupts */
|
||||
iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
|
||||
iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
|
||||
iwl_legacy_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
|
||||
iwl_legacy_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
|
||||
|
||||
/* Reset radio chip */
|
||||
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
iwl_legacy_set_bits_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
udelay(5);
|
||||
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
iwl_legacy_clear_bits_prph(priv, APMG_PS_CTRL_REG,
|
||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -909,17 +908,17 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
|
|||
IWL_DEBUG_INFO(priv, "RTP type\n");
|
||||
else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
|
||||
IWL_DEBUG_INFO(priv, "3945 RADIO-MB type\n");
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BIT_3945_MB);
|
||||
} else {
|
||||
IWL_DEBUG_INFO(priv, "3945 RADIO-MM type\n");
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BIT_3945_MM);
|
||||
}
|
||||
|
||||
if (EEPROM_SKU_CAP_OP_MODE_MRC == eeprom->sku_cap) {
|
||||
IWL_DEBUG_INFO(priv, "SKU OP mode is mrc\n");
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
|
||||
} else
|
||||
IWL_DEBUG_INFO(priv, "SKU OP mode is basic\n");
|
||||
|
@ -927,24 +926,24 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
|
|||
if ((eeprom->board_revision & 0xF0) == 0xD0) {
|
||||
IWL_DEBUG_INFO(priv, "3945ABG revision is 0x%X\n",
|
||||
eeprom->board_revision);
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
|
||||
} else {
|
||||
IWL_DEBUG_INFO(priv, "3945ABG revision is 0x%X\n",
|
||||
eeprom->board_revision);
|
||||
iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
|
||||
}
|
||||
|
||||
if (eeprom->almgor_m_version <= 1) {
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
|
||||
IWL_DEBUG_INFO(priv, "Card M type A version is 0x%X\n",
|
||||
eeprom->almgor_m_version);
|
||||
} else {
|
||||
IWL_DEBUG_INFO(priv, "Card M type B version is 0x%X\n",
|
||||
eeprom->almgor_m_version);
|
||||
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
@ -972,7 +971,7 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
|
|||
|
||||
/* Allocate the RX queue, or reset if it is already allocated */
|
||||
if (!rxq->bd) {
|
||||
rc = iwl_rx_queue_alloc(priv);
|
||||
rc = iwl_legacy_rx_queue_alloc(priv);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Unable to initialize Rx queue\n");
|
||||
return -ENOMEM;
|
||||
|
@ -987,10 +986,10 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
|
|||
|
||||
/* Look at using this instead:
|
||||
rxq->need_update = 1;
|
||||
iwl_rx_queue_update_write_ptr(priv, rxq);
|
||||
iwl_legacy_rx_queue_update_write_ptr(priv, rxq);
|
||||
*/
|
||||
|
||||
iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7);
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7);
|
||||
|
||||
rc = iwl3945_txq_ctx_reset(priv);
|
||||
if (rc)
|
||||
|
@ -1015,12 +1014,12 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
|
|||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
|
||||
txq_id++)
|
||||
if (txq_id == IWL39_CMD_QUEUE_NUM)
|
||||
iwl_cmd_queue_free(priv);
|
||||
iwl_legacy_cmd_queue_free(priv);
|
||||
else
|
||||
iwl_tx_queue_free(priv, txq_id);
|
||||
iwl_legacy_tx_queue_free(priv, txq_id);
|
||||
|
||||
/* free tx queue structure */
|
||||
iwl_free_txq_mem(priv);
|
||||
iwl_legacy_txq_mem(priv);
|
||||
}
|
||||
|
||||
void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
|
||||
|
@ -1028,12 +1027,12 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
|
|||
int txq_id;
|
||||
|
||||
/* stop SCD */
|
||||
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
|
||||
iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_MODE_REG, 0);
|
||||
iwl_legacy_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
|
||||
|
||||
/* reset TFD queues */
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
|
||||
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
|
||||
iwl_legacy_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
|
||||
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
|
||||
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
|
||||
1000);
|
||||
|
@ -1100,12 +1099,12 @@ static int iwl3945_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
|
|||
#define IWL_TEMPERATURE_LIMIT_TIMER 6
|
||||
|
||||
/**
|
||||
* is_temp_calib_needed - determines if new calibration is needed
|
||||
* iwl3945_is_temp_calib_needed - determines if new calibration is needed
|
||||
*
|
||||
* records new temperature in tx_mgr->temperature.
|
||||
* replaces tx_mgr->last_temperature *only* if calib needed
|
||||
* (assumes caller will actually do the calibration!). */
|
||||
static int is_temp_calib_needed(struct iwl_priv *priv)
|
||||
static int iwl3945_is_temp_calib_needed(struct iwl_priv *priv)
|
||||
{
|
||||
int temp_diff;
|
||||
|
||||
|
@ -1336,9 +1335,6 @@ static void iwl3945_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_in
|
|||
* based on eeprom channel data) for this channel. */
|
||||
power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX_TABLE]);
|
||||
|
||||
/* further limit to user's max power preference.
|
||||
* FIXME: Other spectrum management power limitations do not
|
||||
* seem to apply?? */
|
||||
power = min(power, priv->tx_power_user_lmt);
|
||||
scan_power_info->requested_power = power;
|
||||
|
||||
|
@ -1392,7 +1388,7 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
|
|||
chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel);
|
||||
|
||||
txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
|
||||
ch_info = iwl_get_channel_info(priv, priv->band, chan);
|
||||
ch_info = iwl_legacy_get_channel_info(priv, priv->band, chan);
|
||||
if (!ch_info) {
|
||||
IWL_ERR(priv,
|
||||
"Failed to get channel info for channel %d [%d]\n",
|
||||
|
@ -1400,7 +1396,7 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_channel_valid(ch_info)) {
|
||||
if (!iwl_legacy_is_channel_valid(ch_info)) {
|
||||
IWL_DEBUG_POWER(priv, "Not calling TX_PWR_TABLE_CMD on "
|
||||
"non-Tx channel.\n");
|
||||
return 0;
|
||||
|
@ -1435,7 +1431,7 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
|
|||
txpower.power[i].rate);
|
||||
}
|
||||
|
||||
return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
|
||||
return iwl_legacy_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
|
||||
sizeof(struct iwl3945_txpowertable_cmd),
|
||||
&txpower);
|
||||
|
||||
|
@ -1569,7 +1565,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
|
|||
/* set up new Tx power info for each and every channel, 2.4 and 5.x */
|
||||
for (i = 0; i < priv->channel_count; i++) {
|
||||
ch_info = &priv->channel_info[i];
|
||||
a_band = is_channel_a_band(ch_info);
|
||||
a_band = iwl_legacy_is_channel_a_band(ch_info);
|
||||
|
||||
/* Get this chnlgrp's factory calibration temperature */
|
||||
ref_temp = (s16)eeprom->groups[ch_info->group_index].
|
||||
|
@ -1635,7 +1631,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
|
|||
|
||||
for (i = 0; i < priv->channel_count; i++) {
|
||||
ch_info = &priv->channel_info[i];
|
||||
a_band = is_channel_a_band(ch_info);
|
||||
a_band = iwl_legacy_is_channel_a_band(ch_info);
|
||||
|
||||
/* find minimum power of all user and regulatory constraints
|
||||
* (does not consider h/w clipping limitations) */
|
||||
|
@ -1651,7 +1647,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
|
|||
|
||||
/* update txpower settings for all channels,
|
||||
* send to NIC if associated. */
|
||||
is_temp_calib_needed(priv);
|
||||
iwl3945_is_temp_calib_needed(priv);
|
||||
iwl3945_hw_reg_comp_txpower_temp(priv);
|
||||
|
||||
return 0;
|
||||
|
@ -1669,8 +1665,8 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
|
|||
.flags = CMD_WANT_SKB,
|
||||
.data = &rxon_assoc,
|
||||
};
|
||||
const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
|
||||
const struct iwl_rxon_cmd *rxon2 = &ctx->active;
|
||||
const struct iwl_legacy_rxon_cmd *rxon1 = &ctx->staging;
|
||||
const struct iwl_legacy_rxon_cmd *rxon2 = &ctx->active;
|
||||
|
||||
if ((rxon1->flags == rxon2->flags) &&
|
||||
(rxon1->filter_flags == rxon2->filter_flags) &&
|
||||
|
@ -1686,7 +1682,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
|
|||
rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
|
||||
rxon_assoc.reserved = 0;
|
||||
|
||||
rc = iwl_send_cmd_sync(priv, &cmd);
|
||||
rc = iwl_legacy_send_cmd_sync(priv, &cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1696,7 +1692,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
|
|||
rc = -EIO;
|
||||
}
|
||||
|
||||
iwl_free_pages(priv, cmd.reply_page);
|
||||
iwl_legacy_free_pages(priv, cmd.reply_page);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -1720,7 +1716,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EINVAL;
|
||||
|
||||
if (!iwl_is_alive(priv))
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -1;
|
||||
|
||||
/* always get timestamp with Rx frame */
|
||||
|
@ -1731,7 +1727,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
|
||||
staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
|
||||
|
||||
rc = iwl_check_rxon_cmd(priv, ctx);
|
||||
rc = iwl_legacy_check_rxon_cmd(priv, ctx);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
|
||||
return -EINVAL;
|
||||
|
@ -1740,8 +1736,9 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
/* If we don't need to send a full RXON, we can use
|
||||
* iwl3945_rxon_assoc_cmd which is used to reconfigure filter
|
||||
* and other flags for the current radio configuration. */
|
||||
if (!iwl_full_rxon_required(priv, &priv->contexts[IWL_RXON_CTX_BSS])) {
|
||||
rc = iwl_send_rxon_assoc(priv,
|
||||
if (!iwl_legacy_full_rxon_required(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS])) {
|
||||
rc = iwl_legacy_send_rxon_assoc(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting RXON_ASSOC "
|
||||
|
@ -1758,7 +1755,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
* an RXON_ASSOC and the new config wants the associated mask enabled,
|
||||
* we must clear the associated from the active configuration
|
||||
* before we apply the new config */
|
||||
if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && new_assoc) {
|
||||
if (iwl_legacy_is_associated(priv, IWL_RXON_CTX_BSS) && new_assoc) {
|
||||
IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
|
||||
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
|
||||
|
@ -1768,7 +1765,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
*/
|
||||
active_rxon->reserved4 = 0;
|
||||
active_rxon->reserved5 = 0;
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
|
||||
rc = iwl_legacy_send_cmd_pdu(priv, REPLY_RXON,
|
||||
sizeof(struct iwl3945_rxon_cmd),
|
||||
&priv->contexts[IWL_RXON_CTX_BSS].active);
|
||||
|
||||
|
@ -1780,9 +1777,10 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
"configuration (%d).\n", rc);
|
||||
return rc;
|
||||
}
|
||||
iwl_clear_ucode_stations(priv,
|
||||
iwl_legacy_clear_ucode_stations(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
iwl_legacy_restore_stations(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Sending RXON\n"
|
||||
|
@ -1800,10 +1798,10 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
staging_rxon->reserved4 = 0;
|
||||
staging_rxon->reserved5 = 0;
|
||||
|
||||
iwl_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto);
|
||||
iwl_legacy_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto);
|
||||
|
||||
/* Apply the new configuration */
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
|
||||
rc = iwl_legacy_send_cmd_pdu(priv, REPLY_RXON,
|
||||
sizeof(struct iwl3945_rxon_cmd),
|
||||
staging_rxon);
|
||||
if (rc) {
|
||||
|
@ -1814,14 +1812,15 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
|||
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
|
||||
|
||||
if (!new_assoc) {
|
||||
iwl_clear_ucode_stations(priv,
|
||||
iwl_legacy_clear_ucode_stations(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
iwl_legacy_restore_stations(priv,
|
||||
&priv->contexts[IWL_RXON_CTX_BSS]);
|
||||
}
|
||||
|
||||
/* If we issue a new RXON command which required a tune then we must
|
||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||
rc = iwl_set_tx_power(priv, priv->tx_power_next, true);
|
||||
rc = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true);
|
||||
if (rc) {
|
||||
IWL_ERR(priv, "Error setting Tx power (%d).\n", rc);
|
||||
return rc;
|
||||
|
@ -1851,7 +1850,7 @@ void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
|
|||
{
|
||||
/* This will kick in the "brute force"
|
||||
* iwl3945_hw_reg_comp_txpower_temp() below */
|
||||
if (!is_temp_calib_needed(priv))
|
||||
if (!iwl3945_is_temp_calib_needed(priv))
|
||||
goto reschedule;
|
||||
|
||||
/* Set up a new set of temp-adjusted TxPowers, send to NIC.
|
||||
|
@ -1898,7 +1897,7 @@ static u16 iwl3945_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
|
|||
u8 grp_channel;
|
||||
|
||||
/* Find the group index for the channel ... don't use index 1(?) */
|
||||
if (is_channel_a_band(ch_info)) {
|
||||
if (iwl_legacy_is_channel_a_band(ch_info)) {
|
||||
for (group = 1; group < 5; group++) {
|
||||
grp_channel = ch_grp[group].group_channel;
|
||||
if (ch_info->channel <= grp_channel) {
|
||||
|
@ -2078,8 +2077,8 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
|
|||
/* initialize Tx power info for each and every channel, 2.4 and 5.x */
|
||||
for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
|
||||
i++, ch_info++) {
|
||||
a_band = is_channel_a_band(ch_info);
|
||||
if (!is_channel_valid(ch_info))
|
||||
a_band = iwl_legacy_is_channel_a_band(ch_info);
|
||||
if (!iwl_legacy_is_channel_valid(ch_info))
|
||||
continue;
|
||||
|
||||
/* find this channel's channel group (*not* "band") index */
|
||||
|
@ -2182,7 +2181,7 @@ int iwl3945_hw_rxq_stop(struct iwl_priv *priv)
|
|||
{
|
||||
int rc;
|
||||
|
||||
iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0);
|
||||
iwl_legacy_write_direct32(priv, FH39_RCSR_CONFIG(0), 0);
|
||||
rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS,
|
||||
FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
|
||||
if (rc < 0)
|
||||
|
@ -2199,10 +2198,10 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
|||
|
||||
shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
|
||||
|
||||
iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0);
|
||||
iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0);
|
||||
iwl_legacy_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0);
|
||||
iwl_legacy_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0);
|
||||
|
||||
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id),
|
||||
iwl_legacy_write_direct32(priv, FH39_TCSR_CONFIG(txq_id),
|
||||
FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
|
||||
FH39_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
|
||||
FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
|
||||
|
@ -2231,7 +2230,8 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len)
|
|||
}
|
||||
|
||||
|
||||
static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
||||
static u16 iwl3945_build_addsta_hcmd(const struct iwl_legacy_addsta_cmd *cmd,
|
||||
u8 *data)
|
||||
{
|
||||
struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data;
|
||||
addsta->mode = cmd->mode;
|
||||
|
@ -2259,7 +2259,7 @@ static int iwl3945_add_bssid_station(struct iwl_priv *priv,
|
|||
if (sta_id_r)
|
||||
*sta_id_r = IWL_INVALID_STATION;
|
||||
|
||||
ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
|
||||
ret = iwl_legacy_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Unable to add station %pM\n", addr);
|
||||
return ret;
|
||||
|
@ -2294,7 +2294,7 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
|
||||
return iwl_legacy_remove_station(priv, vif_priv->ibss_bssid_sta_id,
|
||||
vif->bss_conf.bssid);
|
||||
}
|
||||
|
||||
|
@ -2345,7 +2345,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
|
|||
* 1M CCK rates */
|
||||
|
||||
if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
|
||||
iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
|
||||
iwl_legacy_is_associated(priv, IWL_RXON_CTX_BSS)) {
|
||||
|
||||
index = IWL_FIRST_CCK_RATE;
|
||||
for (i = IWL_RATE_6M_INDEX_TABLE;
|
||||
|
@ -2366,14 +2366,14 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
|
|||
|
||||
/* Update the rate scaling for control frame Tx */
|
||||
rate_cmd.table_id = 0;
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
|
||||
rc = iwl_legacy_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
|
||||
&rate_cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Update the rate scaling for data frame Tx */
|
||||
rate_cmd.table_id = 1;
|
||||
return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
|
||||
return iwl_legacy_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
|
||||
&rate_cmd);
|
||||
}
|
||||
|
||||
|
@ -2473,11 +2473,11 @@ static int iwl3945_verify_bsm(struct iwl_priv *priv)
|
|||
IWL_DEBUG_INFO(priv, "Begin verify bsm\n");
|
||||
|
||||
/* verify BSM SRAM contents */
|
||||
val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
|
||||
val = iwl_legacy_read_prph(priv, BSM_WR_DWCOUNT_REG);
|
||||
for (reg = BSM_SRAM_LOWER_BOUND;
|
||||
reg < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg += sizeof(u32), image++) {
|
||||
val = iwl_read_prph(priv, reg);
|
||||
val = iwl_legacy_read_prph(priv, reg);
|
||||
if (val != le32_to_cpu(*image)) {
|
||||
IWL_ERR(priv, "BSM uCode verification failed at "
|
||||
"addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
|
||||
|
@ -2510,7 +2510,7 @@ static int iwl3945_verify_bsm(struct iwl_priv *priv)
|
|||
*/
|
||||
static int iwl3945_eeprom_acquire_semaphore(struct iwl_priv *priv)
|
||||
{
|
||||
_iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
|
||||
_iwl_legacy_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2581,16 +2581,16 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|||
inst_len = priv->ucode_init.len;
|
||||
data_len = priv->ucode_init_data.len;
|
||||
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
|
||||
iwl_legacy_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
|
||||
iwl_legacy_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
|
||||
iwl_legacy_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
|
||||
iwl_legacy_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
|
||||
|
||||
/* Fill BSM memory with bootstrap instructions */
|
||||
for (reg_offset = BSM_SRAM_LOWER_BOUND;
|
||||
reg_offset < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg_offset += sizeof(u32), image++)
|
||||
_iwl_write_prph(priv, reg_offset,
|
||||
_iwl_legacy_write_prph(priv, reg_offset,
|
||||
le32_to_cpu(*image));
|
||||
|
||||
rc = iwl3945_verify_bsm(priv);
|
||||
|
@ -2598,19 +2598,19 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|||
return rc;
|
||||
|
||||
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
|
||||
iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
|
||||
iwl_write_prph(priv, BSM_WR_MEM_DST_REG,
|
||||
iwl_legacy_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
|
||||
iwl_legacy_write_prph(priv, BSM_WR_MEM_DST_REG,
|
||||
IWL39_RTC_INST_LOWER_BOUND);
|
||||
iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
|
||||
iwl_legacy_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
|
||||
|
||||
/* Load bootstrap code into instruction SRAM now,
|
||||
* to prepare to load "initialize" uCode */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
iwl_legacy_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
BSM_WR_CTRL_REG_BIT_START);
|
||||
|
||||
/* Wait for load of bootstrap uCode to finish */
|
||||
for (i = 0; i < 100; i++) {
|
||||
done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
|
||||
done = iwl_legacy_read_prph(priv, BSM_WR_CTRL_REG);
|
||||
if (!(done & BSM_WR_CTRL_REG_BIT_START))
|
||||
break;
|
||||
udelay(10);
|
||||
|
@ -2624,7 +2624,7 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|||
|
||||
/* Enable future boot loads whenever power management unit triggers it
|
||||
* (e.g. when powering back up after power-save shutdown) */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
iwl_legacy_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
BSM_WR_CTRL_REG_BIT_START_EN);
|
||||
|
||||
return 0;
|
||||
|
@ -2633,7 +2633,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|||
static struct iwl_hcmd_ops iwl3945_hcmd = {
|
||||
.rxon_assoc = iwl3945_send_rxon_assoc,
|
||||
.commit_rxon = iwl3945_commit_rxon,
|
||||
.send_bt_config = iwl_send_bt_config,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl3945_lib = {
|
||||
|
@ -2659,13 +2658,9 @@ static struct iwl_lib_ops iwl3945_lib = {
|
|||
},
|
||||
.acquire_semaphore = iwl3945_eeprom_acquire_semaphore,
|
||||
.release_semaphore = iwl3945_eeprom_release_semaphore,
|
||||
.query_addr = iwlcore_eeprom_query_addr,
|
||||
},
|
||||
.send_tx_power = iwl3945_send_tx_power,
|
||||
.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
|
||||
.isr_ops = {
|
||||
.isr = iwl_isr_legacy,
|
||||
},
|
||||
|
||||
.debugfs_ops = {
|
||||
.rx_stats_read = iwl3945_ucode_rx_stats_read,
|
||||
|
@ -2683,7 +2678,6 @@ static const struct iwl_legacy_ops iwl3945_legacy_ops = {
|
|||
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
||||
.get_hcmd_size = iwl3945_get_hcmd_size,
|
||||
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
|
||||
.tx_cmd_protection = iwl_legacy_tx_cmd_protection,
|
||||
.request_scan = iwl3945_request_scan,
|
||||
.post_scan = iwl3945_post_scan,
|
||||
};
|
||||
|
@ -2703,13 +2697,10 @@ static struct iwl_base_params iwl3945_base_params = {
|
|||
.pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
|
||||
.set_l0s = false,
|
||||
.use_bsm = true,
|
||||
.use_isr_legacy = true,
|
||||
.led_compensation = 64,
|
||||
.broken_powersave = true,
|
||||
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
|
||||
.wd_timeout = IWL_DEF_WD_TIMEOUT,
|
||||
.max_event_log_size = 512,
|
||||
.tx_power_by_driver = true,
|
||||
};
|
||||
|
||||
static struct iwl_cfg iwl3945_bg_cfg = {
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -108,7 +108,7 @@ struct iwl3945_rs_sta {
|
|||
|
||||
/*
|
||||
* The common struct MUST be first because it is shared between
|
||||
* 3945 and agn!
|
||||
* 3945 and 4965!
|
||||
*/
|
||||
struct iwl3945_sta_priv {
|
||||
struct iwl_station_priv_common common;
|
||||
|
@ -201,7 +201,7 @@ struct iwl3945_ibss_seq {
|
|||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Functions implemented in iwl-base.c which are forward declared here
|
||||
* Functions implemented in iwl3945-base.c which are forward declared here
|
||||
* for use by iwl-*.c
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@ -209,7 +209,7 @@ extern int iwl3945_calc_db_from_ratio(int sig_ratio);
|
|||
extern void iwl3945_rx_replenish(void *data);
|
||||
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,int left);
|
||||
struct ieee80211_hdr *hdr, int left);
|
||||
extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
|
||||
char **buf, bool display);
|
||||
extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
|
||||
|
@ -217,7 +217,7 @@ extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
|
|||
/******************************************************************************
|
||||
*
|
||||
* Functions implemented in iwl-[34]*.c which are forward declared here
|
||||
* for use by iwl-base.c
|
||||
* for use by iwl3945-base.c
|
||||
*
|
||||
* NOTE: The implementation of these functions are hardware specific
|
||||
* which is why they are in the hardware specific files (vs. iwl-base.c)
|
||||
|
@ -283,7 +283,7 @@ extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
|
|||
extern struct ieee80211_ops iwl3945_hw_ops;
|
||||
|
||||
/*
|
||||
* Forward declare iwl-3945.c functions for iwl-base.c
|
||||
* Forward declare iwl-3945.c functions for iwl3945-base.c
|
||||
*/
|
||||
extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
|
||||
extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
|
|
@ -0,0 +1,967 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-4965-calib.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* INIT calibrations framework
|
||||
*****************************************************************************/
|
||||
|
||||
struct statistics_general_data {
|
||||
u32 beacon_silence_rssi_a;
|
||||
u32 beacon_silence_rssi_b;
|
||||
u32 beacon_silence_rssi_c;
|
||||
u32 beacon_energy_a;
|
||||
u32 beacon_energy_b;
|
||||
u32 beacon_energy_c;
|
||||
};
|
||||
|
||||
void iwl4965_calib_free_results(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IWL_CALIB_MAX; i++) {
|
||||
kfree(priv->calib_results[i].buf);
|
||||
priv->calib_results[i].buf = NULL;
|
||||
priv->calib_results[i].buf_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* RUNTIME calibrations framework
|
||||
*****************************************************************************/
|
||||
|
||||
/* "false alarms" are signals that our DSP tries to lock onto,
|
||||
* but then determines that they are either noise, or transmissions
|
||||
* from a distant wireless network (also "noise", really) that get
|
||||
* "stepped on" by stronger transmissions within our own network.
|
||||
* This algorithm attempts to set a sensitivity level that is high
|
||||
* enough to receive all of our own network traffic, but not so
|
||||
* high that our DSP gets too busy trying to lock onto non-network
|
||||
* activity/noise. */
|
||||
static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
|
||||
u32 norm_fa,
|
||||
u32 rx_enable_time,
|
||||
struct statistics_general_data *rx_info)
|
||||
{
|
||||
u32 max_nrg_cck = 0;
|
||||
int i = 0;
|
||||
u8 max_silence_rssi = 0;
|
||||
u32 silence_ref = 0;
|
||||
u8 silence_rssi_a = 0;
|
||||
u8 silence_rssi_b = 0;
|
||||
u8 silence_rssi_c = 0;
|
||||
u32 val;
|
||||
|
||||
/* "false_alarms" values below are cross-multiplications to assess the
|
||||
* numbers of false alarms within the measured period of actual Rx
|
||||
* (Rx is off when we're txing), vs the min/max expected false alarms
|
||||
* (some should be expected if rx is sensitive enough) in a
|
||||
* hypothetical listening period of 200 time units (TU), 204.8 msec:
|
||||
*
|
||||
* MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
|
||||
*
|
||||
* */
|
||||
u32 false_alarms = norm_fa * 200 * 1024;
|
||||
u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
|
||||
u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
data->nrg_auto_corr_silence_diff = 0;
|
||||
|
||||
/* Find max silence rssi among all 3 receivers.
|
||||
* This is background noise, which may include transmissions from other
|
||||
* networks, measured during silence before our network's beacon */
|
||||
silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
|
||||
ALL_BAND_FILTER) >> 8);
|
||||
silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
|
||||
ALL_BAND_FILTER) >> 8);
|
||||
silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
|
||||
ALL_BAND_FILTER) >> 8);
|
||||
|
||||
val = max(silence_rssi_b, silence_rssi_c);
|
||||
max_silence_rssi = max(silence_rssi_a, (u8) val);
|
||||
|
||||
/* Store silence rssi in 20-beacon history table */
|
||||
data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
|
||||
data->nrg_silence_idx++;
|
||||
if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
|
||||
data->nrg_silence_idx = 0;
|
||||
|
||||
/* Find max silence rssi across 20 beacon history */
|
||||
for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
|
||||
val = data->nrg_silence_rssi[i];
|
||||
silence_ref = max(silence_ref, val);
|
||||
}
|
||||
IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
|
||||
silence_rssi_a, silence_rssi_b, silence_rssi_c,
|
||||
silence_ref);
|
||||
|
||||
/* Find max rx energy (min value!) among all 3 receivers,
|
||||
* measured during beacon frame.
|
||||
* Save it in 10-beacon history table. */
|
||||
i = data->nrg_energy_idx;
|
||||
val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
|
||||
data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
|
||||
|
||||
data->nrg_energy_idx++;
|
||||
if (data->nrg_energy_idx >= 10)
|
||||
data->nrg_energy_idx = 0;
|
||||
|
||||
/* Find min rx energy (max value) across 10 beacon history.
|
||||
* This is the minimum signal level that we want to receive well.
|
||||
* Add backoff (margin so we don't miss slightly lower energy frames).
|
||||
* This establishes an upper bound (min value) for energy threshold. */
|
||||
max_nrg_cck = data->nrg_value[0];
|
||||
for (i = 1; i < 10; i++)
|
||||
max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
|
||||
max_nrg_cck += 6;
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
|
||||
rx_info->beacon_energy_a, rx_info->beacon_energy_b,
|
||||
rx_info->beacon_energy_c, max_nrg_cck - 6);
|
||||
|
||||
/* Count number of consecutive beacons with fewer-than-desired
|
||||
* false alarms. */
|
||||
if (false_alarms < min_false_alarms)
|
||||
data->num_in_cck_no_fa++;
|
||||
else
|
||||
data->num_in_cck_no_fa = 0;
|
||||
IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
|
||||
data->num_in_cck_no_fa);
|
||||
|
||||
/* If we got too many false alarms this time, reduce sensitivity */
|
||||
if ((false_alarms > max_false_alarms) &&
|
||||
(data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
|
||||
IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
|
||||
false_alarms, max_false_alarms);
|
||||
IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
|
||||
data->nrg_curr_state = IWL_FA_TOO_MANY;
|
||||
/* Store for "fewer than desired" on later beacon */
|
||||
data->nrg_silence_ref = silence_ref;
|
||||
|
||||
/* increase energy threshold (reduce nrg value)
|
||||
* to decrease sensitivity */
|
||||
data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
|
||||
/* Else if we got fewer than desired, increase sensitivity */
|
||||
} else if (false_alarms < min_false_alarms) {
|
||||
data->nrg_curr_state = IWL_FA_TOO_FEW;
|
||||
|
||||
/* Compare silence level with silence level for most recent
|
||||
* healthy number or too many false alarms */
|
||||
data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
|
||||
(s32)silence_ref;
|
||||
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"norm FA %u < min FA %u, silence diff %d\n",
|
||||
false_alarms, min_false_alarms,
|
||||
data->nrg_auto_corr_silence_diff);
|
||||
|
||||
/* Increase value to increase sensitivity, but only if:
|
||||
* 1a) previous beacon did *not* have *too many* false alarms
|
||||
* 1b) AND there's a significant difference in Rx levels
|
||||
* from a previous beacon with too many, or healthy # FAs
|
||||
* OR 2) We've seen a lot of beacons (100) with too few
|
||||
* false alarms */
|
||||
if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
|
||||
((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
|
||||
(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n");
|
||||
/* Increase nrg value to increase sensitivity */
|
||||
val = data->nrg_th_cck + NRG_STEP_CCK;
|
||||
data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
|
||||
} else {
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"... but not changing sensitivity\n");
|
||||
}
|
||||
|
||||
/* Else we got a healthy number of false alarms, keep status quo */
|
||||
} else {
|
||||
IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
|
||||
data->nrg_curr_state = IWL_FA_GOOD_RANGE;
|
||||
|
||||
/* Store for use in "fewer than desired" with later beacon */
|
||||
data->nrg_silence_ref = silence_ref;
|
||||
|
||||
/* If previous beacon had too many false alarms,
|
||||
* give it some extra margin by reducing sensitivity again
|
||||
* (but don't go below measured energy of desired Rx) */
|
||||
if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
|
||||
IWL_DEBUG_CALIB(priv, "... increasing margin\n");
|
||||
if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
|
||||
data->nrg_th_cck -= NRG_MARGIN;
|
||||
else
|
||||
data->nrg_th_cck = max_nrg_cck;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the energy threshold does not go above the measured
|
||||
* energy of the desired Rx signals (reduced by backoff margin),
|
||||
* or else we might start missing Rx frames.
|
||||
* Lower value is higher energy, so we use max()!
|
||||
*/
|
||||
data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
|
||||
IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
|
||||
|
||||
data->nrg_prev_state = data->nrg_curr_state;
|
||||
|
||||
/* Auto-correlation CCK algorithm */
|
||||
if (false_alarms > min_false_alarms) {
|
||||
|
||||
/* increase auto_corr values to decrease sensitivity
|
||||
* so the DSP won't be disturbed by the noise
|
||||
*/
|
||||
if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
|
||||
data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
|
||||
else {
|
||||
val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
|
||||
data->auto_corr_cck =
|
||||
min((u32)ranges->auto_corr_max_cck, val);
|
||||
}
|
||||
val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
|
||||
data->auto_corr_cck_mrc =
|
||||
min((u32)ranges->auto_corr_max_cck_mrc, val);
|
||||
} else if ((false_alarms < min_false_alarms) &&
|
||||
((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
|
||||
(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
|
||||
|
||||
/* Decrease auto_corr values to increase sensitivity */
|
||||
val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
|
||||
data->auto_corr_cck =
|
||||
max((u32)ranges->auto_corr_min_cck, val);
|
||||
val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
|
||||
data->auto_corr_cck_mrc =
|
||||
max((u32)ranges->auto_corr_min_cck_mrc, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
|
||||
u32 norm_fa,
|
||||
u32 rx_enable_time)
|
||||
{
|
||||
u32 val;
|
||||
u32 false_alarms = norm_fa * 200 * 1024;
|
||||
u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
|
||||
u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
/* If we got too many false alarms this time, reduce sensitivity */
|
||||
if (false_alarms > max_false_alarms) {
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u)\n",
|
||||
false_alarms, max_false_alarms);
|
||||
|
||||
val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm =
|
||||
min((u32)ranges->auto_corr_max_ofdm, val);
|
||||
|
||||
val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_mrc =
|
||||
min((u32)ranges->auto_corr_max_ofdm_mrc, val);
|
||||
|
||||
val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_x1 =
|
||||
min((u32)ranges->auto_corr_max_ofdm_x1, val);
|
||||
|
||||
val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_mrc_x1 =
|
||||
min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
|
||||
}
|
||||
|
||||
/* Else if we got fewer than desired, increase sensitivity */
|
||||
else if (false_alarms < min_false_alarms) {
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u\n",
|
||||
false_alarms, min_false_alarms);
|
||||
|
||||
val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm =
|
||||
max((u32)ranges->auto_corr_min_ofdm, val);
|
||||
|
||||
val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_mrc =
|
||||
max((u32)ranges->auto_corr_min_ofdm_mrc, val);
|
||||
|
||||
val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_x1 =
|
||||
max((u32)ranges->auto_corr_min_ofdm_x1, val);
|
||||
|
||||
val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
|
||||
data->auto_corr_ofdm_mrc_x1 =
|
||||
max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
|
||||
} else {
|
||||
IWL_DEBUG_CALIB(priv, "min FA %u < norm FA %u < max FA %u OK\n",
|
||||
min_false_alarms, false_alarms, max_false_alarms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl4965_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
|
||||
struct iwl_sensitivity_data *data,
|
||||
__le16 *tbl)
|
||||
{
|
||||
tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_ofdm);
|
||||
tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
|
||||
tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_ofdm_x1);
|
||||
tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
|
||||
|
||||
tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_cck);
|
||||
tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
|
||||
cpu_to_le16((u16)data->auto_corr_cck_mrc);
|
||||
|
||||
tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
|
||||
cpu_to_le16((u16)data->nrg_th_cck);
|
||||
tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
|
||||
cpu_to_le16((u16)data->nrg_th_ofdm);
|
||||
|
||||
tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
|
||||
cpu_to_le16(data->barker_corr_th_min);
|
||||
tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
|
||||
cpu_to_le16(data->barker_corr_th_min_mrc);
|
||||
tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
|
||||
cpu_to_le16(data->nrg_th_cca);
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
|
||||
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
|
||||
data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
|
||||
data->nrg_th_ofdm);
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
|
||||
data->auto_corr_cck, data->auto_corr_cck_mrc,
|
||||
data->nrg_th_cck);
|
||||
}
|
||||
|
||||
/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
|
||||
static int iwl4965_sensitivity_write(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_sensitivity_cmd cmd;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
struct iwl_host_cmd cmd_out = {
|
||||
.id = SENSITIVITY_CMD,
|
||||
.len = sizeof(struct iwl_sensitivity_cmd),
|
||||
.flags = CMD_ASYNC,
|
||||
.data = &cmd,
|
||||
};
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
iwl4965_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
|
||||
|
||||
/* Update uCode's "work" table, and copy it to DSP */
|
||||
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
|
||||
|
||||
/* Don't send command to uCode if nothing has changed */
|
||||
if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
|
||||
sizeof(u16)*HD_TABLE_SIZE)) {
|
||||
IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy table for comparison next time */
|
||||
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
|
||||
sizeof(u16)*HD_TABLE_SIZE);
|
||||
|
||||
return iwl_legacy_send_cmd(priv, &cmd_out);
|
||||
}
|
||||
|
||||
void iwl4965_init_sensitivity(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
|
||||
|
||||
if (priv->disable_sens_cal)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "Start iwl4965_init_sensitivity\n");
|
||||
|
||||
/* Clear driver's sensitivity algo data */
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
if (ranges == NULL)
|
||||
return;
|
||||
|
||||
memset(data, 0, sizeof(struct iwl_sensitivity_data));
|
||||
|
||||
data->num_in_cck_no_fa = 0;
|
||||
data->nrg_curr_state = IWL_FA_TOO_MANY;
|
||||
data->nrg_prev_state = IWL_FA_TOO_MANY;
|
||||
data->nrg_silence_ref = 0;
|
||||
data->nrg_silence_idx = 0;
|
||||
data->nrg_energy_idx = 0;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
data->nrg_value[i] = 0;
|
||||
|
||||
for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
|
||||
data->nrg_silence_rssi[i] = 0;
|
||||
|
||||
data->auto_corr_ofdm = ranges->auto_corr_min_ofdm;
|
||||
data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
|
||||
data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1;
|
||||
data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
|
||||
data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
|
||||
data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
|
||||
data->nrg_th_cck = ranges->nrg_th_cck;
|
||||
data->nrg_th_ofdm = ranges->nrg_th_ofdm;
|
||||
data->barker_corr_th_min = ranges->barker_corr_th_min;
|
||||
data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
|
||||
data->nrg_th_cca = ranges->nrg_th_cca;
|
||||
|
||||
data->last_bad_plcp_cnt_ofdm = 0;
|
||||
data->last_fa_cnt_ofdm = 0;
|
||||
data->last_bad_plcp_cnt_cck = 0;
|
||||
data->last_fa_cnt_cck = 0;
|
||||
|
||||
ret |= iwl4965_sensitivity_write(priv);
|
||||
IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
|
||||
}
|
||||
|
||||
void iwl4965_sensitivity_calibration(struct iwl_priv *priv, void *resp)
|
||||
{
|
||||
u32 rx_enable_time;
|
||||
u32 fa_cck;
|
||||
u32 fa_ofdm;
|
||||
u32 bad_plcp_cck;
|
||||
u32 bad_plcp_ofdm;
|
||||
u32 norm_fa_ofdm;
|
||||
u32 norm_fa_cck;
|
||||
struct iwl_sensitivity_data *data = NULL;
|
||||
struct statistics_rx_non_phy *rx_info;
|
||||
struct statistics_rx_phy *ofdm, *cck;
|
||||
unsigned long flags;
|
||||
struct statistics_general_data statis;
|
||||
|
||||
if (priv->disable_sens_cal)
|
||||
return;
|
||||
|
||||
data = &(priv->sensitivity_data);
|
||||
|
||||
if (!iwl_legacy_is_any_associated(priv)) {
|
||||
IWL_DEBUG_CALIB(priv, "<< - not associated\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
|
||||
ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
|
||||
cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
|
||||
|
||||
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
|
||||
IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract Statistics: */
|
||||
rx_enable_time = le32_to_cpu(rx_info->channel_load);
|
||||
fa_cck = le32_to_cpu(cck->false_alarm_cnt);
|
||||
fa_ofdm = le32_to_cpu(ofdm->false_alarm_cnt);
|
||||
bad_plcp_cck = le32_to_cpu(cck->plcp_err);
|
||||
bad_plcp_ofdm = le32_to_cpu(ofdm->plcp_err);
|
||||
|
||||
statis.beacon_silence_rssi_a =
|
||||
le32_to_cpu(rx_info->beacon_silence_rssi_a);
|
||||
statis.beacon_silence_rssi_b =
|
||||
le32_to_cpu(rx_info->beacon_silence_rssi_b);
|
||||
statis.beacon_silence_rssi_c =
|
||||
le32_to_cpu(rx_info->beacon_silence_rssi_c);
|
||||
statis.beacon_energy_a =
|
||||
le32_to_cpu(rx_info->beacon_energy_a);
|
||||
statis.beacon_energy_b =
|
||||
le32_to_cpu(rx_info->beacon_energy_b);
|
||||
statis.beacon_energy_c =
|
||||
le32_to_cpu(rx_info->beacon_energy_c);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
|
||||
|
||||
if (!rx_enable_time) {
|
||||
IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* These statistics increase monotonically, and do not reset
|
||||
* at each beacon. Calculate difference from last value, or just
|
||||
* use the new statistics value if it has reset or wrapped around. */
|
||||
if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
|
||||
data->last_bad_plcp_cnt_cck = bad_plcp_cck;
|
||||
else {
|
||||
bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
|
||||
data->last_bad_plcp_cnt_cck += bad_plcp_cck;
|
||||
}
|
||||
|
||||
if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
|
||||
data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
|
||||
else {
|
||||
bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
|
||||
data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
|
||||
}
|
||||
|
||||
if (data->last_fa_cnt_ofdm > fa_ofdm)
|
||||
data->last_fa_cnt_ofdm = fa_ofdm;
|
||||
else {
|
||||
fa_ofdm -= data->last_fa_cnt_ofdm;
|
||||
data->last_fa_cnt_ofdm += fa_ofdm;
|
||||
}
|
||||
|
||||
if (data->last_fa_cnt_cck > fa_cck)
|
||||
data->last_fa_cnt_cck = fa_cck;
|
||||
else {
|
||||
fa_cck -= data->last_fa_cnt_cck;
|
||||
data->last_fa_cnt_cck += fa_cck;
|
||||
}
|
||||
|
||||
/* Total aborted signal locks */
|
||||
norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
|
||||
norm_fa_cck = fa_cck + bad_plcp_cck;
|
||||
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck,
|
||||
bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
|
||||
|
||||
iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
|
||||
iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
|
||||
|
||||
iwl4965_sensitivity_write(priv);
|
||||
}
|
||||
|
||||
static inline u8 iwl4965_find_first_chain(u8 mask)
|
||||
{
|
||||
if (mask & ANT_A)
|
||||
return CHAIN_A;
|
||||
if (mask & ANT_B)
|
||||
return CHAIN_B;
|
||||
return CHAIN_C;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run disconnected antenna algorithm to find out which antennas are
|
||||
* disconnected.
|
||||
*/
|
||||
static void
|
||||
iwl4965_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
|
||||
struct iwl_chain_noise_data *data)
|
||||
{
|
||||
u32 active_chains = 0;
|
||||
u32 max_average_sig;
|
||||
u16 max_average_sig_antenna_i;
|
||||
u8 num_tx_chains;
|
||||
u8 first_chain;
|
||||
u16 i = 0;
|
||||
|
||||
average_sig[0] = data->chain_signal_a /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
average_sig[1] = data->chain_signal_b /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
average_sig[2] = data->chain_signal_c /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
|
||||
if (average_sig[0] >= average_sig[1]) {
|
||||
max_average_sig = average_sig[0];
|
||||
max_average_sig_antenna_i = 0;
|
||||
active_chains = (1 << max_average_sig_antenna_i);
|
||||
} else {
|
||||
max_average_sig = average_sig[1];
|
||||
max_average_sig_antenna_i = 1;
|
||||
active_chains = (1 << max_average_sig_antenna_i);
|
||||
}
|
||||
|
||||
if (average_sig[2] >= max_average_sig) {
|
||||
max_average_sig = average_sig[2];
|
||||
max_average_sig_antenna_i = 2;
|
||||
active_chains = (1 << max_average_sig_antenna_i);
|
||||
}
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
|
||||
average_sig[0], average_sig[1], average_sig[2]);
|
||||
IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
|
||||
max_average_sig, max_average_sig_antenna_i);
|
||||
|
||||
/* Compare signal strengths for all 3 receivers. */
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++) {
|
||||
if (i != max_average_sig_antenna_i) {
|
||||
s32 rssi_delta = (max_average_sig - average_sig[i]);
|
||||
|
||||
/* If signal is very weak, compared with
|
||||
* strongest, mark it as disconnected. */
|
||||
if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
|
||||
data->disconn_array[i] = 1;
|
||||
else
|
||||
active_chains |= (1 << i);
|
||||
IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d "
|
||||
"disconn_array[i] = %d\n",
|
||||
i, rssi_delta, data->disconn_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The above algorithm sometimes fails when the ucode
|
||||
* reports 0 for all chains. It's not clear why that
|
||||
* happens to start with, but it is then causing trouble
|
||||
* because this can make us enable more chains than the
|
||||
* hardware really has.
|
||||
*
|
||||
* To be safe, simply mask out any chains that we know
|
||||
* are not on the device.
|
||||
*/
|
||||
active_chains &= priv->hw_params.valid_rx_ant;
|
||||
|
||||
num_tx_chains = 0;
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++) {
|
||||
/* loops on all the bits of
|
||||
* priv->hw_setting.valid_tx_ant */
|
||||
u8 ant_msk = (1 << i);
|
||||
if (!(priv->hw_params.valid_tx_ant & ant_msk))
|
||||
continue;
|
||||
|
||||
num_tx_chains++;
|
||||
if (data->disconn_array[i] == 0)
|
||||
/* there is a Tx antenna connected */
|
||||
break;
|
||||
if (num_tx_chains == priv->hw_params.tx_chains_num &&
|
||||
data->disconn_array[i]) {
|
||||
/*
|
||||
* If all chains are disconnected
|
||||
* connect the first valid tx chain
|
||||
*/
|
||||
first_chain =
|
||||
iwl4965_find_first_chain(priv->cfg->valid_tx_ant);
|
||||
data->disconn_array[first_chain] = 0;
|
||||
active_chains |= BIT(first_chain);
|
||||
IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected \
|
||||
W/A - declare %d as connected\n",
|
||||
first_chain);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_chains != priv->hw_params.valid_rx_ant &&
|
||||
active_chains != priv->chain_noise_data.active_chains)
|
||||
IWL_DEBUG_CALIB(priv,
|
||||
"Detected that not all antennas are connected! "
|
||||
"Connected: %#x, valid: %#x.\n",
|
||||
active_chains, priv->hw_params.valid_rx_ant);
|
||||
|
||||
/* Save for use within RXON, TX, SCAN commands, etc. */
|
||||
data->active_chains = active_chains;
|
||||
IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
|
||||
active_chains);
|
||||
}
|
||||
|
||||
static void iwl4965_gain_computation(struct iwl_priv *priv,
|
||||
u32 *average_noise,
|
||||
u16 min_average_noise_antenna_i,
|
||||
u32 min_average_noise,
|
||||
u8 default_chain)
|
||||
{
|
||||
int i, ret;
|
||||
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
|
||||
|
||||
data->delta_gain_code[min_average_noise_antenna_i] = 0;
|
||||
|
||||
for (i = default_chain; i < NUM_RX_CHAINS; i++) {
|
||||
s32 delta_g = 0;
|
||||
|
||||
if (!(data->disconn_array[i]) &&
|
||||
(data->delta_gain_code[i] ==
|
||||
CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
|
||||
delta_g = average_noise[i] - min_average_noise;
|
||||
data->delta_gain_code[i] = (u8)((delta_g * 10) / 15);
|
||||
data->delta_gain_code[i] =
|
||||
min(data->delta_gain_code[i],
|
||||
(u8) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
|
||||
|
||||
data->delta_gain_code[i] =
|
||||
(data->delta_gain_code[i] | (1 << 2));
|
||||
} else {
|
||||
data->delta_gain_code[i] = 0;
|
||||
}
|
||||
}
|
||||
IWL_DEBUG_CALIB(priv, "delta_gain_codes: a %d b %d c %d\n",
|
||||
data->delta_gain_code[0],
|
||||
data->delta_gain_code[1],
|
||||
data->delta_gain_code[2]);
|
||||
|
||||
/* Differential gain gets sent to uCode only once */
|
||||
if (!data->radio_write) {
|
||||
struct iwl_calib_diff_gain_cmd cmd;
|
||||
data->radio_write = 1;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
|
||||
cmd.diff_gain_a = data->delta_gain_code[0];
|
||||
cmd.diff_gain_b = data->delta_gain_code[1];
|
||||
cmd.diff_gain_c = data->delta_gain_code[2];
|
||||
ret = iwl_legacy_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
|
||||
sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
IWL_DEBUG_CALIB(priv, "fail sending cmd "
|
||||
"REPLY_PHY_CALIBRATION_CMD\n");
|
||||
|
||||
/* TODO we might want recalculate
|
||||
* rx_chain in rxon cmd */
|
||||
|
||||
/* Mark so we run this algo only once! */
|
||||
data->state = IWL_CHAIN_NOISE_CALIBRATED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Accumulate 16 beacons of signal and noise statistics for each of
|
||||
* 3 receivers/antennas/rx-chains, then figure out:
|
||||
* 1) Which antennas are connected.
|
||||
* 2) Differential rx gain settings to balance the 3 receivers.
|
||||
*/
|
||||
void iwl4965_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
|
||||
{
|
||||
struct iwl_chain_noise_data *data = NULL;
|
||||
|
||||
u32 chain_noise_a;
|
||||
u32 chain_noise_b;
|
||||
u32 chain_noise_c;
|
||||
u32 chain_sig_a;
|
||||
u32 chain_sig_b;
|
||||
u32 chain_sig_c;
|
||||
u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
|
||||
u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
|
||||
u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
|
||||
u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
|
||||
u16 i = 0;
|
||||
u16 rxon_chnum = INITIALIZATION_VALUE;
|
||||
u16 stat_chnum = INITIALIZATION_VALUE;
|
||||
u8 rxon_band24;
|
||||
u8 stat_band24;
|
||||
unsigned long flags;
|
||||
struct statistics_rx_non_phy *rx_info;
|
||||
|
||||
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
|
||||
|
||||
if (priv->disable_chain_noise_cal)
|
||||
return;
|
||||
|
||||
data = &(priv->chain_noise_data);
|
||||
|
||||
/*
|
||||
* Accumulate just the first "chain_noise_num_beacons" after
|
||||
* the first association, then we're done forever.
|
||||
*/
|
||||
if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
|
||||
if (data->state == IWL_CHAIN_NOISE_ALIVE)
|
||||
IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
|
||||
rx.general);
|
||||
|
||||
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
|
||||
IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
|
||||
rxon_chnum = le16_to_cpu(ctx->staging.channel);
|
||||
|
||||
stat_band24 = !!(((struct iwl_notif_statistics *)
|
||||
stat_resp)->flag &
|
||||
STATISTICS_REPLY_FLG_BAND_24G_MSK);
|
||||
stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
|
||||
stat_resp)->flag) >> 16;
|
||||
|
||||
/* Make sure we accumulate data for just the associated channel
|
||||
* (even if scanning). */
|
||||
if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
|
||||
IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
|
||||
rxon_chnum, rxon_band24);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate beacon statistics values across
|
||||
* "chain_noise_num_beacons"
|
||||
*/
|
||||
chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
|
||||
IN_BAND_FILTER;
|
||||
chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
|
||||
IN_BAND_FILTER;
|
||||
chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
|
||||
IN_BAND_FILTER;
|
||||
|
||||
chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
|
||||
chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
|
||||
chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
data->beacon_count++;
|
||||
|
||||
data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
|
||||
data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
|
||||
data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
|
||||
|
||||
data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
|
||||
data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
|
||||
data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
|
||||
rxon_chnum, rxon_band24, data->beacon_count);
|
||||
IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
|
||||
chain_sig_a, chain_sig_b, chain_sig_c);
|
||||
IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
|
||||
chain_noise_a, chain_noise_b, chain_noise_c);
|
||||
|
||||
/* If this is the "chain_noise_num_beacons", determine:
|
||||
* 1) Disconnected antennas (using signal strengths)
|
||||
* 2) Differential gain (using silence noise) to balance receivers */
|
||||
if (data->beacon_count !=
|
||||
priv->cfg->base_params->chain_noise_num_beacons)
|
||||
return;
|
||||
|
||||
/* Analyze signal for disconnected antenna */
|
||||
iwl4965_find_disconn_antenna(priv, average_sig, data);
|
||||
|
||||
/* Analyze noise for rx balance */
|
||||
average_noise[0] = data->chain_noise_a /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
average_noise[1] = data->chain_noise_b /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
average_noise[2] = data->chain_noise_c /
|
||||
priv->cfg->base_params->chain_noise_num_beacons;
|
||||
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++) {
|
||||
if (!(data->disconn_array[i]) &&
|
||||
(average_noise[i] <= min_average_noise)) {
|
||||
/* This means that chain i is active and has
|
||||
* lower noise values so far: */
|
||||
min_average_noise = average_noise[i];
|
||||
min_average_noise_antenna_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
|
||||
average_noise[0], average_noise[1],
|
||||
average_noise[2]);
|
||||
|
||||
IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
|
||||
min_average_noise, min_average_noise_antenna_i);
|
||||
|
||||
iwl4965_gain_computation(priv, average_noise,
|
||||
min_average_noise_antenna_i, min_average_noise,
|
||||
iwl4965_find_first_chain(priv->cfg->valid_rx_ant));
|
||||
|
||||
/* Some power changes may have been made during the calibration.
|
||||
* Update and commit the RXON
|
||||
*/
|
||||
if (priv->cfg->ops->lib->update_chain_flags)
|
||||
priv->cfg->ops->lib->update_chain_flags(priv);
|
||||
|
||||
data->state = IWL_CHAIN_NOISE_DONE;
|
||||
iwl_legacy_power_update_mode(priv, false);
|
||||
}
|
||||
|
||||
void iwl4965_reset_run_time_calib(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
memset(&(priv->sensitivity_data), 0,
|
||||
sizeof(struct iwl_sensitivity_data));
|
||||
memset(&(priv->chain_noise_data), 0,
|
||||
sizeof(struct iwl_chain_noise_data));
|
||||
for (i = 0; i < NUM_RX_CHAINS; i++)
|
||||
priv->chain_noise_data.delta_gain_code[i] =
|
||||
CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
|
||||
|
||||
/* Ask for statistics now, the uCode will send notification
|
||||
* periodically after association */
|
||||
iwl_legacy_send_statistics_request(priv, CMD_ASYNC, true);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -59,21 +59,17 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_4965_calib_h__
|
||||
#define __iwl_4965_calib_h__
|
||||
|
||||
#ifndef __iwl_legacy_h__
|
||||
#define __iwl_legacy_h__
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-commands.h"
|
||||
|
||||
/* mac80211 handlers */
|
||||
int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
|
||||
void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
|
||||
void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changes);
|
||||
void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv,
|
||||
struct ieee80211_tx_info *info,
|
||||
__le16 fc, __le32 *tx_flags);
|
||||
void iwl4965_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp);
|
||||
void iwl4965_sensitivity_calibration(struct iwl_priv *priv, void *resp);
|
||||
void iwl4965_init_sensitivity(struct iwl_priv *priv);
|
||||
void iwl4965_reset_run_time_calib(struct iwl_priv *priv);
|
||||
void iwl4965_calib_free_results(struct iwl_priv *priv);
|
||||
|
||||
irqreturn_t iwl_isr_legacy(int irq, void *data);
|
||||
|
||||
#endif /* __iwl_legacy_h__ */
|
||||
#endif /* __iwl_4965_calib_h__ */
|
|
@ -0,0 +1,774 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*****************************************************************************/
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-4965-debugfs.h"
|
||||
|
||||
static const char *fmt_value = " %-30s %10u\n";
|
||||
static const char *fmt_table = " %-30s %10u %10u %10u %10u\n";
|
||||
static const char *fmt_header =
|
||||
"%-32s current cumulative delta max\n";
|
||||
|
||||
static int iwl4965_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
|
||||
{
|
||||
int p = 0;
|
||||
u32 flag;
|
||||
|
||||
flag = le32_to_cpu(priv->_4965.statistics.flag);
|
||||
|
||||
p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
|
||||
if (flag & UCODE_STATISTICS_CLEAR_MSK)
|
||||
p += scnprintf(buf + p, bufsz - p,
|
||||
"\tStatistics have been cleared\n");
|
||||
p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
|
||||
(flag & UCODE_STATISTICS_FREQUENCY_MSK)
|
||||
? "2.4 GHz" : "5.2 GHz");
|
||||
p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
|
||||
(flag & UCODE_STATISTICS_NARROW_BAND_MSK)
|
||||
? "enabled" : "disabled");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
ssize_t iwl4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = sizeof(struct statistics_rx_phy) * 40 +
|
||||
sizeof(struct statistics_rx_non_phy) * 40 +
|
||||
sizeof(struct statistics_rx_ht_phy) * 40 + 400;
|
||||
ssize_t ret;
|
||||
struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
|
||||
struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
|
||||
struct statistics_rx_non_phy *general, *accum_general;
|
||||
struct statistics_rx_non_phy *delta_general, *max_general;
|
||||
struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
|
||||
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
IWL_ERR(priv, "Can not allocate Buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* the statistic information display here is based on
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
ofdm = &priv->_4965.statistics.rx.ofdm;
|
||||
cck = &priv->_4965.statistics.rx.cck;
|
||||
general = &priv->_4965.statistics.rx.general;
|
||||
ht = &priv->_4965.statistics.rx.ofdm_ht;
|
||||
accum_ofdm = &priv->_4965.accum_statistics.rx.ofdm;
|
||||
accum_cck = &priv->_4965.accum_statistics.rx.cck;
|
||||
accum_general = &priv->_4965.accum_statistics.rx.general;
|
||||
accum_ht = &priv->_4965.accum_statistics.rx.ofdm_ht;
|
||||
delta_ofdm = &priv->_4965.delta_statistics.rx.ofdm;
|
||||
delta_cck = &priv->_4965.delta_statistics.rx.cck;
|
||||
delta_general = &priv->_4965.delta_statistics.rx.general;
|
||||
delta_ht = &priv->_4965.delta_statistics.rx.ofdm_ht;
|
||||
max_ofdm = &priv->_4965.max_delta.rx.ofdm;
|
||||
max_cck = &priv->_4965.max_delta.rx.cck;
|
||||
max_general = &priv->_4965.max_delta.rx.general;
|
||||
max_ht = &priv->_4965.max_delta.rx.ofdm_ht;
|
||||
|
||||
pos += iwl4965_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_Rx - OFDM:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ina_cnt:",
|
||||
le32_to_cpu(ofdm->ina_cnt),
|
||||
accum_ofdm->ina_cnt,
|
||||
delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_cnt:",
|
||||
le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
|
||||
delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
|
||||
delta_ofdm->plcp_err, max_ofdm->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
|
||||
delta_ofdm->crc32_err, max_ofdm->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(ofdm->overrun_err),
|
||||
accum_ofdm->overrun_err, delta_ofdm->overrun_err,
|
||||
max_ofdm->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(ofdm->early_overrun_err),
|
||||
accum_ofdm->early_overrun_err,
|
||||
delta_ofdm->early_overrun_err,
|
||||
max_ofdm->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(ofdm->crc32_good),
|
||||
accum_ofdm->crc32_good, delta_ofdm->crc32_good,
|
||||
max_ofdm->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "false_alarm_cnt:",
|
||||
le32_to_cpu(ofdm->false_alarm_cnt),
|
||||
accum_ofdm->false_alarm_cnt,
|
||||
delta_ofdm->false_alarm_cnt,
|
||||
max_ofdm->false_alarm_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_sync_err_cnt:",
|
||||
le32_to_cpu(ofdm->fina_sync_err_cnt),
|
||||
accum_ofdm->fina_sync_err_cnt,
|
||||
delta_ofdm->fina_sync_err_cnt,
|
||||
max_ofdm->fina_sync_err_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sfd_timeout:",
|
||||
le32_to_cpu(ofdm->sfd_timeout),
|
||||
accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
|
||||
max_ofdm->sfd_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_timeout:",
|
||||
le32_to_cpu(ofdm->fina_timeout),
|
||||
accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
|
||||
max_ofdm->fina_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "unresponded_rts:",
|
||||
le32_to_cpu(ofdm->unresponded_rts),
|
||||
accum_ofdm->unresponded_rts,
|
||||
delta_ofdm->unresponded_rts,
|
||||
max_ofdm->unresponded_rts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "rxe_frame_lmt_ovrun:",
|
||||
le32_to_cpu(ofdm->rxe_frame_limit_overrun),
|
||||
accum_ofdm->rxe_frame_limit_overrun,
|
||||
delta_ofdm->rxe_frame_limit_overrun,
|
||||
max_ofdm->rxe_frame_limit_overrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_ack_cnt:",
|
||||
le32_to_cpu(ofdm->sent_ack_cnt),
|
||||
accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
|
||||
max_ofdm->sent_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_cts_cnt:",
|
||||
le32_to_cpu(ofdm->sent_cts_cnt),
|
||||
accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
|
||||
max_ofdm->sent_cts_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_ba_rsp_cnt:",
|
||||
le32_to_cpu(ofdm->sent_ba_rsp_cnt),
|
||||
accum_ofdm->sent_ba_rsp_cnt,
|
||||
delta_ofdm->sent_ba_rsp_cnt,
|
||||
max_ofdm->sent_ba_rsp_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "dsp_self_kill:",
|
||||
le32_to_cpu(ofdm->dsp_self_kill),
|
||||
accum_ofdm->dsp_self_kill,
|
||||
delta_ofdm->dsp_self_kill,
|
||||
max_ofdm->dsp_self_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(ofdm->mh_format_err),
|
||||
accum_ofdm->mh_format_err,
|
||||
delta_ofdm->mh_format_err,
|
||||
max_ofdm->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "re_acq_main_rssi_sum:",
|
||||
le32_to_cpu(ofdm->re_acq_main_rssi_sum),
|
||||
accum_ofdm->re_acq_main_rssi_sum,
|
||||
delta_ofdm->re_acq_main_rssi_sum,
|
||||
max_ofdm->re_acq_main_rssi_sum);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_Rx - CCK:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ina_cnt:",
|
||||
le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
|
||||
delta_cck->ina_cnt, max_cck->ina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_cnt:",
|
||||
le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
|
||||
delta_cck->fina_cnt, max_cck->fina_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
|
||||
delta_cck->plcp_err, max_cck->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
|
||||
delta_cck->crc32_err, max_cck->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(cck->overrun_err),
|
||||
accum_cck->overrun_err, delta_cck->overrun_err,
|
||||
max_cck->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(cck->early_overrun_err),
|
||||
accum_cck->early_overrun_err,
|
||||
delta_cck->early_overrun_err,
|
||||
max_cck->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
|
||||
delta_cck->crc32_good, max_cck->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "false_alarm_cnt:",
|
||||
le32_to_cpu(cck->false_alarm_cnt),
|
||||
accum_cck->false_alarm_cnt,
|
||||
delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_sync_err_cnt:",
|
||||
le32_to_cpu(cck->fina_sync_err_cnt),
|
||||
accum_cck->fina_sync_err_cnt,
|
||||
delta_cck->fina_sync_err_cnt,
|
||||
max_cck->fina_sync_err_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sfd_timeout:",
|
||||
le32_to_cpu(cck->sfd_timeout),
|
||||
accum_cck->sfd_timeout, delta_cck->sfd_timeout,
|
||||
max_cck->sfd_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "fina_timeout:",
|
||||
le32_to_cpu(cck->fina_timeout),
|
||||
accum_cck->fina_timeout, delta_cck->fina_timeout,
|
||||
max_cck->fina_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "unresponded_rts:",
|
||||
le32_to_cpu(cck->unresponded_rts),
|
||||
accum_cck->unresponded_rts, delta_cck->unresponded_rts,
|
||||
max_cck->unresponded_rts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "rxe_frame_lmt_ovrun:",
|
||||
le32_to_cpu(cck->rxe_frame_limit_overrun),
|
||||
accum_cck->rxe_frame_limit_overrun,
|
||||
delta_cck->rxe_frame_limit_overrun,
|
||||
max_cck->rxe_frame_limit_overrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_ack_cnt:",
|
||||
le32_to_cpu(cck->sent_ack_cnt),
|
||||
accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
|
||||
max_cck->sent_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_cts_cnt:",
|
||||
le32_to_cpu(cck->sent_cts_cnt),
|
||||
accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
|
||||
max_cck->sent_cts_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sent_ba_rsp_cnt:",
|
||||
le32_to_cpu(cck->sent_ba_rsp_cnt),
|
||||
accum_cck->sent_ba_rsp_cnt,
|
||||
delta_cck->sent_ba_rsp_cnt,
|
||||
max_cck->sent_ba_rsp_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "dsp_self_kill:",
|
||||
le32_to_cpu(cck->dsp_self_kill),
|
||||
accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
|
||||
max_cck->dsp_self_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(cck->mh_format_err),
|
||||
accum_cck->mh_format_err, delta_cck->mh_format_err,
|
||||
max_cck->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "re_acq_main_rssi_sum:",
|
||||
le32_to_cpu(cck->re_acq_main_rssi_sum),
|
||||
accum_cck->re_acq_main_rssi_sum,
|
||||
delta_cck->re_acq_main_rssi_sum,
|
||||
max_cck->re_acq_main_rssi_sum);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_Rx - GENERAL:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "bogus_cts:",
|
||||
le32_to_cpu(general->bogus_cts),
|
||||
accum_general->bogus_cts, delta_general->bogus_cts,
|
||||
max_general->bogus_cts);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "bogus_ack:",
|
||||
le32_to_cpu(general->bogus_ack),
|
||||
accum_general->bogus_ack, delta_general->bogus_ack,
|
||||
max_general->bogus_ack);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "non_bssid_frames:",
|
||||
le32_to_cpu(general->non_bssid_frames),
|
||||
accum_general->non_bssid_frames,
|
||||
delta_general->non_bssid_frames,
|
||||
max_general->non_bssid_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "filtered_frames:",
|
||||
le32_to_cpu(general->filtered_frames),
|
||||
accum_general->filtered_frames,
|
||||
delta_general->filtered_frames,
|
||||
max_general->filtered_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "non_channel_beacons:",
|
||||
le32_to_cpu(general->non_channel_beacons),
|
||||
accum_general->non_channel_beacons,
|
||||
delta_general->non_channel_beacons,
|
||||
max_general->non_channel_beacons);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "channel_beacons:",
|
||||
le32_to_cpu(general->channel_beacons),
|
||||
accum_general->channel_beacons,
|
||||
delta_general->channel_beacons,
|
||||
max_general->channel_beacons);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "num_missed_bcon:",
|
||||
le32_to_cpu(general->num_missed_bcon),
|
||||
accum_general->num_missed_bcon,
|
||||
delta_general->num_missed_bcon,
|
||||
max_general->num_missed_bcon);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "adc_rx_saturation_time:",
|
||||
le32_to_cpu(general->adc_rx_saturation_time),
|
||||
accum_general->adc_rx_saturation_time,
|
||||
delta_general->adc_rx_saturation_time,
|
||||
max_general->adc_rx_saturation_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ina_detect_search_tm:",
|
||||
le32_to_cpu(general->ina_detection_search_time),
|
||||
accum_general->ina_detection_search_time,
|
||||
delta_general->ina_detection_search_time,
|
||||
max_general->ina_detection_search_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_silence_rssi_a:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_a),
|
||||
accum_general->beacon_silence_rssi_a,
|
||||
delta_general->beacon_silence_rssi_a,
|
||||
max_general->beacon_silence_rssi_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_silence_rssi_b:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_b),
|
||||
accum_general->beacon_silence_rssi_b,
|
||||
delta_general->beacon_silence_rssi_b,
|
||||
max_general->beacon_silence_rssi_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_silence_rssi_c:",
|
||||
le32_to_cpu(general->beacon_silence_rssi_c),
|
||||
accum_general->beacon_silence_rssi_c,
|
||||
delta_general->beacon_silence_rssi_c,
|
||||
max_general->beacon_silence_rssi_c);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "interference_data_flag:",
|
||||
le32_to_cpu(general->interference_data_flag),
|
||||
accum_general->interference_data_flag,
|
||||
delta_general->interference_data_flag,
|
||||
max_general->interference_data_flag);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "channel_load:",
|
||||
le32_to_cpu(general->channel_load),
|
||||
accum_general->channel_load,
|
||||
delta_general->channel_load,
|
||||
max_general->channel_load);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "dsp_false_alarms:",
|
||||
le32_to_cpu(general->dsp_false_alarms),
|
||||
accum_general->dsp_false_alarms,
|
||||
delta_general->dsp_false_alarms,
|
||||
max_general->dsp_false_alarms);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_rssi_a:",
|
||||
le32_to_cpu(general->beacon_rssi_a),
|
||||
accum_general->beacon_rssi_a,
|
||||
delta_general->beacon_rssi_a,
|
||||
max_general->beacon_rssi_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_rssi_b:",
|
||||
le32_to_cpu(general->beacon_rssi_b),
|
||||
accum_general->beacon_rssi_b,
|
||||
delta_general->beacon_rssi_b,
|
||||
max_general->beacon_rssi_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_rssi_c:",
|
||||
le32_to_cpu(general->beacon_rssi_c),
|
||||
accum_general->beacon_rssi_c,
|
||||
delta_general->beacon_rssi_c,
|
||||
max_general->beacon_rssi_c);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_energy_a:",
|
||||
le32_to_cpu(general->beacon_energy_a),
|
||||
accum_general->beacon_energy_a,
|
||||
delta_general->beacon_energy_a,
|
||||
max_general->beacon_energy_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_energy_b:",
|
||||
le32_to_cpu(general->beacon_energy_b),
|
||||
accum_general->beacon_energy_b,
|
||||
delta_general->beacon_energy_b,
|
||||
max_general->beacon_energy_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "beacon_energy_c:",
|
||||
le32_to_cpu(general->beacon_energy_c),
|
||||
accum_general->beacon_energy_c,
|
||||
delta_general->beacon_energy_c,
|
||||
max_general->beacon_energy_c);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_Rx - OFDM_HT:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "plcp_err:",
|
||||
le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
|
||||
delta_ht->plcp_err, max_ht->plcp_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "overrun_err:",
|
||||
le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
|
||||
delta_ht->overrun_err, max_ht->overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "early_overrun_err:",
|
||||
le32_to_cpu(ht->early_overrun_err),
|
||||
accum_ht->early_overrun_err,
|
||||
delta_ht->early_overrun_err,
|
||||
max_ht->early_overrun_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_good:",
|
||||
le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
|
||||
delta_ht->crc32_good, max_ht->crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "crc32_err:",
|
||||
le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
|
||||
delta_ht->crc32_err, max_ht->crc32_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "mh_format_err:",
|
||||
le32_to_cpu(ht->mh_format_err),
|
||||
accum_ht->mh_format_err,
|
||||
delta_ht->mh_format_err, max_ht->mh_format_err);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg_crc32_good:",
|
||||
le32_to_cpu(ht->agg_crc32_good),
|
||||
accum_ht->agg_crc32_good,
|
||||
delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg_mpdu_cnt:",
|
||||
le32_to_cpu(ht->agg_mpdu_cnt),
|
||||
accum_ht->agg_mpdu_cnt,
|
||||
delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg_cnt:",
|
||||
le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
|
||||
delta_ht->agg_cnt, max_ht->agg_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "unsupport_mcs:",
|
||||
le32_to_cpu(ht->unsupport_mcs),
|
||||
accum_ht->unsupport_mcs,
|
||||
delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t iwl4965_ucode_tx_stats_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
|
||||
ssize_t ret;
|
||||
struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
|
||||
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
IWL_ERR(priv, "Can not allocate Buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* the statistic information display here is based on
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
tx = &priv->_4965.statistics.tx;
|
||||
accum_tx = &priv->_4965.accum_statistics.tx;
|
||||
delta_tx = &priv->_4965.delta_statistics.tx;
|
||||
max_tx = &priv->_4965.max_delta.tx;
|
||||
|
||||
pos += iwl4965_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_Tx:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "preamble:",
|
||||
le32_to_cpu(tx->preamble_cnt),
|
||||
accum_tx->preamble_cnt,
|
||||
delta_tx->preamble_cnt, max_tx->preamble_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "rx_detected_cnt:",
|
||||
le32_to_cpu(tx->rx_detected_cnt),
|
||||
accum_tx->rx_detected_cnt,
|
||||
delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "bt_prio_defer_cnt:",
|
||||
le32_to_cpu(tx->bt_prio_defer_cnt),
|
||||
accum_tx->bt_prio_defer_cnt,
|
||||
delta_tx->bt_prio_defer_cnt,
|
||||
max_tx->bt_prio_defer_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "bt_prio_kill_cnt:",
|
||||
le32_to_cpu(tx->bt_prio_kill_cnt),
|
||||
accum_tx->bt_prio_kill_cnt,
|
||||
delta_tx->bt_prio_kill_cnt,
|
||||
max_tx->bt_prio_kill_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "few_bytes_cnt:",
|
||||
le32_to_cpu(tx->few_bytes_cnt),
|
||||
accum_tx->few_bytes_cnt,
|
||||
delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "cts_timeout:",
|
||||
le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
|
||||
delta_tx->cts_timeout, max_tx->cts_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ack_timeout:",
|
||||
le32_to_cpu(tx->ack_timeout),
|
||||
accum_tx->ack_timeout,
|
||||
delta_tx->ack_timeout, max_tx->ack_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "expected_ack_cnt:",
|
||||
le32_to_cpu(tx->expected_ack_cnt),
|
||||
accum_tx->expected_ack_cnt,
|
||||
delta_tx->expected_ack_cnt,
|
||||
max_tx->expected_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "actual_ack_cnt:",
|
||||
le32_to_cpu(tx->actual_ack_cnt),
|
||||
accum_tx->actual_ack_cnt,
|
||||
delta_tx->actual_ack_cnt,
|
||||
max_tx->actual_ack_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "dump_msdu_cnt:",
|
||||
le32_to_cpu(tx->dump_msdu_cnt),
|
||||
accum_tx->dump_msdu_cnt,
|
||||
delta_tx->dump_msdu_cnt,
|
||||
max_tx->dump_msdu_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "abort_nxt_frame_mismatch:",
|
||||
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
|
||||
accum_tx->burst_abort_next_frame_mismatch_cnt,
|
||||
delta_tx->burst_abort_next_frame_mismatch_cnt,
|
||||
max_tx->burst_abort_next_frame_mismatch_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "abort_missing_nxt_frame:",
|
||||
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
|
||||
accum_tx->burst_abort_missing_next_frame_cnt,
|
||||
delta_tx->burst_abort_missing_next_frame_cnt,
|
||||
max_tx->burst_abort_missing_next_frame_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "cts_timeout_collision:",
|
||||
le32_to_cpu(tx->cts_timeout_collision),
|
||||
accum_tx->cts_timeout_collision,
|
||||
delta_tx->cts_timeout_collision,
|
||||
max_tx->cts_timeout_collision);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "ack_ba_timeout_collision:",
|
||||
le32_to_cpu(tx->ack_or_ba_timeout_collision),
|
||||
accum_tx->ack_or_ba_timeout_collision,
|
||||
delta_tx->ack_or_ba_timeout_collision,
|
||||
max_tx->ack_or_ba_timeout_collision);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg ba_timeout:",
|
||||
le32_to_cpu(tx->agg.ba_timeout),
|
||||
accum_tx->agg.ba_timeout,
|
||||
delta_tx->agg.ba_timeout,
|
||||
max_tx->agg.ba_timeout);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg ba_resched_frames:",
|
||||
le32_to_cpu(tx->agg.ba_reschedule_frames),
|
||||
accum_tx->agg.ba_reschedule_frames,
|
||||
delta_tx->agg.ba_reschedule_frames,
|
||||
max_tx->agg.ba_reschedule_frames);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg scd_query_agg_frame:",
|
||||
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
|
||||
accum_tx->agg.scd_query_agg_frame_cnt,
|
||||
delta_tx->agg.scd_query_agg_frame_cnt,
|
||||
max_tx->agg.scd_query_agg_frame_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg scd_query_no_agg:",
|
||||
le32_to_cpu(tx->agg.scd_query_no_agg),
|
||||
accum_tx->agg.scd_query_no_agg,
|
||||
delta_tx->agg.scd_query_no_agg,
|
||||
max_tx->agg.scd_query_no_agg);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg scd_query_agg:",
|
||||
le32_to_cpu(tx->agg.scd_query_agg),
|
||||
accum_tx->agg.scd_query_agg,
|
||||
delta_tx->agg.scd_query_agg,
|
||||
max_tx->agg.scd_query_agg);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg scd_query_mismatch:",
|
||||
le32_to_cpu(tx->agg.scd_query_mismatch),
|
||||
accum_tx->agg.scd_query_mismatch,
|
||||
delta_tx->agg.scd_query_mismatch,
|
||||
max_tx->agg.scd_query_mismatch);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg frame_not_ready:",
|
||||
le32_to_cpu(tx->agg.frame_not_ready),
|
||||
accum_tx->agg.frame_not_ready,
|
||||
delta_tx->agg.frame_not_ready,
|
||||
max_tx->agg.frame_not_ready);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg underrun:",
|
||||
le32_to_cpu(tx->agg.underrun),
|
||||
accum_tx->agg.underrun,
|
||||
delta_tx->agg.underrun, max_tx->agg.underrun);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg bt_prio_kill:",
|
||||
le32_to_cpu(tx->agg.bt_prio_kill),
|
||||
accum_tx->agg.bt_prio_kill,
|
||||
delta_tx->agg.bt_prio_kill,
|
||||
max_tx->agg.bt_prio_kill);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "agg rx_ba_rsp_cnt:",
|
||||
le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
|
||||
accum_tx->agg.rx_ba_rsp_cnt,
|
||||
delta_tx->agg.rx_ba_rsp_cnt,
|
||||
max_tx->agg.rx_ba_rsp_cnt);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
iwl4965_ucode_general_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
int pos = 0;
|
||||
char *buf;
|
||||
int bufsz = sizeof(struct statistics_general) * 10 + 300;
|
||||
ssize_t ret;
|
||||
struct statistics_general_common *general, *accum_general;
|
||||
struct statistics_general_common *delta_general, *max_general;
|
||||
struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
|
||||
struct statistics_div *div, *accum_div, *delta_div, *max_div;
|
||||
|
||||
if (!iwl_legacy_is_alive(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
IWL_ERR(priv, "Can not allocate Buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* the statistic information display here is based on
|
||||
* the last statistics notification from uCode
|
||||
* might not reflect the current uCode activity
|
||||
*/
|
||||
general = &priv->_4965.statistics.general.common;
|
||||
dbg = &priv->_4965.statistics.general.common.dbg;
|
||||
div = &priv->_4965.statistics.general.common.div;
|
||||
accum_general = &priv->_4965.accum_statistics.general.common;
|
||||
accum_dbg = &priv->_4965.accum_statistics.general.common.dbg;
|
||||
accum_div = &priv->_4965.accum_statistics.general.common.div;
|
||||
delta_general = &priv->_4965.delta_statistics.general.common;
|
||||
max_general = &priv->_4965.max_delta.general.common;
|
||||
delta_dbg = &priv->_4965.delta_statistics.general.common.dbg;
|
||||
max_dbg = &priv->_4965.max_delta.general.common.dbg;
|
||||
delta_div = &priv->_4965.delta_statistics.general.common.div;
|
||||
max_div = &priv->_4965.max_delta.general.common.div;
|
||||
|
||||
pos += iwl4965_statistics_flag(priv, buf, bufsz);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_header, "Statistics_General:");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_value, "temperature:",
|
||||
le32_to_cpu(general->temperature));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_value, "ttl_timestamp:",
|
||||
le32_to_cpu(general->ttl_timestamp));
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "burst_check:",
|
||||
le32_to_cpu(dbg->burst_check),
|
||||
accum_dbg->burst_check,
|
||||
delta_dbg->burst_check, max_dbg->burst_check);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "burst_count:",
|
||||
le32_to_cpu(dbg->burst_count),
|
||||
accum_dbg->burst_count,
|
||||
delta_dbg->burst_count, max_dbg->burst_count);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "wait_for_silence_timeout_count:",
|
||||
le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
|
||||
accum_dbg->wait_for_silence_timeout_cnt,
|
||||
delta_dbg->wait_for_silence_timeout_cnt,
|
||||
max_dbg->wait_for_silence_timeout_cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "sleep_time:",
|
||||
le32_to_cpu(general->sleep_time),
|
||||
accum_general->sleep_time,
|
||||
delta_general->sleep_time, max_general->sleep_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "slots_out:",
|
||||
le32_to_cpu(general->slots_out),
|
||||
accum_general->slots_out,
|
||||
delta_general->slots_out, max_general->slots_out);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "slots_idle:",
|
||||
le32_to_cpu(general->slots_idle),
|
||||
accum_general->slots_idle,
|
||||
delta_general->slots_idle, max_general->slots_idle);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "tx_on_a:",
|
||||
le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
|
||||
delta_div->tx_on_a, max_div->tx_on_a);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "tx_on_b:",
|
||||
le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
|
||||
delta_div->tx_on_b, max_div->tx_on_b);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "exec_time:",
|
||||
le32_to_cpu(div->exec_time), accum_div->exec_time,
|
||||
delta_div->exec_time, max_div->exec_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "probe_time:",
|
||||
le32_to_cpu(div->probe_time), accum_div->probe_time,
|
||||
delta_div->probe_time, max_div->probe_time);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "rx_enable_counter:",
|
||||
le32_to_cpu(general->rx_enable_counter),
|
||||
accum_general->rx_enable_counter,
|
||||
delta_general->rx_enable_counter,
|
||||
max_general->rx_enable_counter);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
fmt_table, "num_of_sos_states:",
|
||||
le32_to_cpu(general->num_of_sos_states),
|
||||
accum_general->num_of_sos_states,
|
||||
delta_general->num_of_sos_states,
|
||||
max_general->num_of_sos_states);
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*****************************************************************************/
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-debug.h"
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
ssize_t iwl4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t iwl4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t iwl4965_ucode_general_stats_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos);
|
||||
#else
|
||||
static ssize_t
|
||||
iwl4965_ucode_rx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static ssize_t
|
||||
iwl4965_ucode_tx_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static ssize_t
|
||||
iwl4965_ucode_general_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,154 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-io.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* EEPROM related functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* The device's EEPROM semaphore prevents conflicts between driver and uCode
|
||||
* when accessing the EEPROM; each access is a series of pulses to/from the
|
||||
* EEPROM chip, not a single event, so even reads could conflict if they
|
||||
* weren't arbitrated by the semaphore.
|
||||
*/
|
||||
int iwl4965_eeprom_acquire_semaphore(struct iwl_priv *priv)
|
||||
{
|
||||
u16 count;
|
||||
int ret;
|
||||
|
||||
for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
|
||||
/* Request semaphore */
|
||||
iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
|
||||
|
||||
/* See if we got it */
|
||||
ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
|
||||
EEPROM_SEM_TIMEOUT);
|
||||
if (ret >= 0) {
|
||||
IWL_DEBUG_IO(priv,
|
||||
"Acquired semaphore after %d tries.\n",
|
||||
count+1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl4965_eeprom_release_semaphore(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_legacy_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
|
||||
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
|
||||
|
||||
}
|
||||
|
||||
int iwl4965_eeprom_check_version(struct iwl_priv *priv)
|
||||
{
|
||||
u16 eeprom_ver;
|
||||
u16 calib_ver;
|
||||
|
||||
eeprom_ver = iwl_legacy_eeprom_query16(priv, EEPROM_VERSION);
|
||||
calib_ver = iwl_legacy_eeprom_query16(priv,
|
||||
EEPROM_4965_CALIB_VERSION_OFFSET);
|
||||
|
||||
if (eeprom_ver < priv->cfg->eeprom_ver ||
|
||||
calib_ver < priv->cfg->eeprom_calib_ver)
|
||||
goto err;
|
||||
|
||||
IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
|
||||
eeprom_ver, calib_ver);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
|
||||
"CALIB=0x%x < 0x%x\n",
|
||||
eeprom_ver, priv->cfg->eeprom_ver,
|
||||
calib_ver, priv->cfg->eeprom_calib_ver);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
void iwl4965_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
|
||||
{
|
||||
const u8 *addr = iwl_legacy_eeprom_query_addr(priv,
|
||||
EEPROM_MAC_ADDRESS);
|
||||
memcpy(mac, addr, ETH_ALEN);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -789,4 +789,26 @@ struct iwl4965_scd_bc_tbl {
|
|||
u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
|
||||
} __packed;
|
||||
|
||||
|
||||
#define IWL4965_RTC_INST_LOWER_BOUND (0x000000)
|
||||
|
||||
/* RSSI to dBm */
|
||||
#define IWL4965_RSSI_OFFSET 44
|
||||
|
||||
/* PCI registers */
|
||||
#define PCI_CFG_RETRY_TIMEOUT 0x041
|
||||
|
||||
/* PCI register values */
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02
|
||||
|
||||
#define IWL4965_DEFAULT_TX_RETRY 15
|
||||
|
||||
/* Limit range of txpower output target to be between these values */
|
||||
#define IWL4965_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */
|
||||
|
||||
/* EEPROM */
|
||||
#define IWL4965_FIRST_AMPDU_QUEUE 10
|
||||
|
||||
|
||||
#endif /* !__iwl_4965_hw_h__ */
|
|
@ -0,0 +1,74 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-4965-led.h"
|
||||
|
||||
/* Send led command */
|
||||
static int
|
||||
iwl4965_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_LEDS_CMD,
|
||||
.len = sizeof(struct iwl_led_cmd),
|
||||
.data = led_cmd,
|
||||
.flags = CMD_ASYNC,
|
||||
.callback = NULL,
|
||||
};
|
||||
u32 reg;
|
||||
|
||||
reg = iwl_read32(priv, CSR_LED_REG);
|
||||
if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
|
||||
iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
|
||||
|
||||
return iwl_legacy_send_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
/* Set led register off */
|
||||
void iwl4965_led_enable(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
|
||||
}
|
||||
|
||||
const struct iwl_led_ops iwl4965_led_ops = {
|
||||
.cmd = iwl4965_send_led_cmd,
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2009-2010 Realtek Corporation.
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -19,12 +19,15 @@
|
|||
* file called LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* wlanfae <wlanfae@realtek.com>
|
||||
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
|
||||
* Hsinchu 300, Taiwan.
|
||||
*
|
||||
* Larry Finger <Larry.Finger@lwfinger.net>
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "../rtl8192ce/fw.h"
|
||||
#ifndef __iwl_4965_led_h__
|
||||
#define __iwl_4965_led_h__
|
||||
|
||||
extern const struct iwl_led_ops iwl4965_led_ops;
|
||||
void iwl4965_led_enable(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_4965_led_h__ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -34,14 +34,14 @@
|
|||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-agn-calib.h"
|
||||
#include "iwl-4965-calib.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
#include "iwl-agn.h"
|
||||
#include "iwl-4965-hw.h"
|
||||
#include "iwl-4965.h"
|
||||
|
||||
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
|
||||
void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
|
||||
{
|
||||
|
@ -58,14 +58,14 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
|
|||
le32_to_cpu(missed_beacon->num_recvd_beacons),
|
||||
le32_to_cpu(missed_beacon->num_expected_beacons));
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status))
|
||||
iwl_init_sensitivity(priv);
|
||||
iwl4965_init_sensitivity(priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate noise level, based on measurements during network silence just
|
||||
* before arriving beacon. This measurement can be done only if we know
|
||||
* exactly when to expect beacons, therefore only when we're associated. */
|
||||
static void iwl_rx_calc_noise(struct iwl_priv *priv)
|
||||
static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
|
||||
{
|
||||
struct statistics_rx_non_phy *rx_info;
|
||||
int num_active_rx = 0;
|
||||
|
@ -73,10 +73,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
|
|||
int bcn_silence_a, bcn_silence_b, bcn_silence_c;
|
||||
int last_rx_noise;
|
||||
|
||||
if (iwl_bt_statistics(priv))
|
||||
rx_info = &(priv->_agn.statistics_bt.rx.general.common);
|
||||
else
|
||||
rx_info = &(priv->_agn.statistics.rx.general);
|
||||
rx_info = &(priv->_4965.statistics.rx.general);
|
||||
bcn_silence_a =
|
||||
le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
|
||||
bcn_silence_b =
|
||||
|
@ -108,13 +105,13 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
|
|||
last_rx_noise);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
/*
|
||||
* based on the assumption of all statistics counter are in DWORD
|
||||
* FIXME: This function is for debugging, do not deal with
|
||||
* the case of counters roll-over.
|
||||
*/
|
||||
static void iwl_accumulative_statistics(struct iwl_priv *priv,
|
||||
static void iwl4965_accumulative_statistics(struct iwl_priv *priv,
|
||||
__le32 *stats)
|
||||
{
|
||||
int i, size;
|
||||
|
@ -124,27 +121,16 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
|
|||
struct statistics_general_common *general, *accum_general;
|
||||
struct statistics_tx *tx, *accum_tx;
|
||||
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
prev_stats = (__le32 *)&priv->_agn.statistics_bt;
|
||||
accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
|
||||
size = sizeof(struct iwl_bt_notif_statistics);
|
||||
general = &priv->_agn.statistics_bt.general.common;
|
||||
accum_general = &priv->_agn.accum_statistics_bt.general.common;
|
||||
tx = &priv->_agn.statistics_bt.tx;
|
||||
accum_tx = &priv->_agn.accum_statistics_bt.tx;
|
||||
delta = (u32 *)&priv->_agn.delta_statistics_bt;
|
||||
max_delta = (u32 *)&priv->_agn.max_delta_bt;
|
||||
} else {
|
||||
prev_stats = (__le32 *)&priv->_agn.statistics;
|
||||
accum_stats = (u32 *)&priv->_agn.accum_statistics;
|
||||
size = sizeof(struct iwl_notif_statistics);
|
||||
general = &priv->_agn.statistics.general.common;
|
||||
accum_general = &priv->_agn.accum_statistics.general.common;
|
||||
tx = &priv->_agn.statistics.tx;
|
||||
accum_tx = &priv->_agn.accum_statistics.tx;
|
||||
delta = (u32 *)&priv->_agn.delta_statistics;
|
||||
max_delta = (u32 *)&priv->_agn.max_delta;
|
||||
}
|
||||
prev_stats = (__le32 *)&priv->_4965.statistics;
|
||||
accum_stats = (u32 *)&priv->_4965.accum_statistics;
|
||||
size = sizeof(struct iwl_notif_statistics);
|
||||
general = &priv->_4965.statistics.general.common;
|
||||
accum_general = &priv->_4965.accum_statistics.general.common;
|
||||
tx = &priv->_4965.statistics.tx;
|
||||
accum_tx = &priv->_4965.accum_statistics.tx;
|
||||
delta = (u32 *)&priv->_4965.delta_statistics;
|
||||
max_delta = (u32 *)&priv->_4965.max_delta;
|
||||
|
||||
for (i = sizeof(__le32); i < size;
|
||||
i += sizeof(__le32), stats++, prev_stats++, delta++,
|
||||
max_delta++, accum_stats++) {
|
||||
|
@ -159,23 +145,19 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
|
|||
|
||||
/* reset accumulative statistics for "no-counter" type statistics */
|
||||
accum_general->temperature = general->temperature;
|
||||
accum_general->temperature_m = general->temperature_m;
|
||||
accum_general->ttl_timestamp = general->ttl_timestamp;
|
||||
accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
|
||||
accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
|
||||
accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define REG_RECALIB_PERIOD (60)
|
||||
|
||||
/**
|
||||
* iwl_good_plcp_health - checks for plcp error.
|
||||
* iwl4965_good_plcp_health - checks for plcp error.
|
||||
*
|
||||
* When the plcp error is exceeding the thresholds, reset the radio
|
||||
* to improve the throughput.
|
||||
*/
|
||||
bool iwl_good_plcp_health(struct iwl_priv *priv,
|
||||
bool iwl4965_good_plcp_health(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
bool rc = true;
|
||||
|
@ -205,27 +187,15 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
|
|||
struct statistics_rx_phy *ofdm;
|
||||
struct statistics_rx_ht_phy *ofdm_ht;
|
||||
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
ofdm = &pkt->u.stats_bt.rx.ofdm;
|
||||
ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
|
||||
combined_plcp_delta =
|
||||
(le32_to_cpu(ofdm->plcp_err) -
|
||||
le32_to_cpu(priv->_agn.statistics_bt.
|
||||
rx.ofdm.plcp_err)) +
|
||||
(le32_to_cpu(ofdm_ht->plcp_err) -
|
||||
le32_to_cpu(priv->_agn.statistics_bt.
|
||||
rx.ofdm_ht.plcp_err));
|
||||
} else {
|
||||
ofdm = &pkt->u.stats.rx.ofdm;
|
||||
ofdm_ht = &pkt->u.stats.rx.ofdm_ht;
|
||||
combined_plcp_delta =
|
||||
(le32_to_cpu(ofdm->plcp_err) -
|
||||
le32_to_cpu(priv->_agn.statistics.
|
||||
rx.ofdm.plcp_err)) +
|
||||
(le32_to_cpu(ofdm_ht->plcp_err) -
|
||||
le32_to_cpu(priv->_agn.statistics.
|
||||
rx.ofdm_ht.plcp_err));
|
||||
}
|
||||
ofdm = &pkt->u.stats.rx.ofdm;
|
||||
ofdm_ht = &pkt->u.stats.rx.ofdm_ht;
|
||||
combined_plcp_delta =
|
||||
(le32_to_cpu(ofdm->plcp_err) -
|
||||
le32_to_cpu(priv->_4965.statistics.
|
||||
rx.ofdm.plcp_err)) +
|
||||
(le32_to_cpu(ofdm_ht->plcp_err) -
|
||||
le32_to_cpu(priv->_4965.statistics.
|
||||
rx.ofdm_ht.plcp_err));
|
||||
|
||||
if ((combined_plcp_delta > 0) &&
|
||||
((combined_plcp_delta * 100) / plcp_msec) >
|
||||
|
@ -256,56 +226,32 @@ bool iwl_good_plcp_health(struct iwl_priv *priv,
|
|||
return rc;
|
||||
}
|
||||
|
||||
void iwl_rx_statistics(struct iwl_priv *priv,
|
||||
void iwl4965_rx_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
int change;
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
IWL_DEBUG_RX(priv,
|
||||
"Statistics notification received (%d vs %d).\n",
|
||||
(int)sizeof(struct iwl_bt_notif_statistics),
|
||||
le32_to_cpu(pkt->len_n_flags) &
|
||||
FH_RSCSR_FRAME_SIZE_MSK);
|
||||
IWL_DEBUG_RX(priv,
|
||||
"Statistics notification received (%d vs %d).\n",
|
||||
(int)sizeof(struct iwl_notif_statistics),
|
||||
le32_to_cpu(pkt->len_n_flags) &
|
||||
FH_RSCSR_FRAME_SIZE_MSK);
|
||||
|
||||
change = ((priv->_agn.statistics_bt.general.common.temperature !=
|
||||
pkt->u.stats_bt.general.common.temperature) ||
|
||||
((priv->_agn.statistics_bt.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
|
||||
(pkt->u.stats_bt.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
|
||||
change = ((priv->_4965.statistics.general.common.temperature !=
|
||||
pkt->u.stats.general.common.temperature) ||
|
||||
((priv->_4965.statistics.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
|
||||
(pkt->u.stats.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
iwl4965_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
IWL_DEBUG_RX(priv,
|
||||
"Statistics notification received (%d vs %d).\n",
|
||||
(int)sizeof(struct iwl_notif_statistics),
|
||||
le32_to_cpu(pkt->len_n_flags) &
|
||||
FH_RSCSR_FRAME_SIZE_MSK);
|
||||
iwl_legacy_recover_from_statistics(priv, pkt);
|
||||
|
||||
change = ((priv->_agn.statistics.general.common.temperature !=
|
||||
pkt->u.stats.general.common.temperature) ||
|
||||
((priv->_agn.statistics.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
|
||||
(pkt->u.stats.flag &
|
||||
STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
iwl_recover_from_statistics(priv, pkt);
|
||||
|
||||
if (iwl_bt_statistics(priv))
|
||||
memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
|
||||
sizeof(priv->_agn.statistics_bt));
|
||||
else
|
||||
memcpy(&priv->_agn.statistics, &pkt->u.stats,
|
||||
sizeof(priv->_agn.statistics));
|
||||
memcpy(&priv->_4965.statistics, &pkt->u.stats,
|
||||
sizeof(priv->_4965.statistics));
|
||||
|
||||
set_bit(STATUS_STATISTICS, &priv->status);
|
||||
|
||||
|
@ -318,34 +264,28 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
|||
|
||||
if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
|
||||
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
|
||||
iwl_rx_calc_noise(priv);
|
||||
iwl4965_rx_calc_noise(priv);
|
||||
queue_work(priv->workqueue, &priv->run_time_calib_work);
|
||||
}
|
||||
if (priv->cfg->ops->lib->temp_ops.temperature && change)
|
||||
priv->cfg->ops->lib->temp_ops.temperature(priv);
|
||||
}
|
||||
|
||||
void iwl_reply_statistics(struct iwl_priv *priv,
|
||||
void iwl4965_reply_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
||||
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
memset(&priv->_agn.accum_statistics, 0,
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
memset(&priv->_4965.accum_statistics, 0,
|
||||
sizeof(struct iwl_notif_statistics));
|
||||
memset(&priv->_agn.delta_statistics, 0,
|
||||
memset(&priv->_4965.delta_statistics, 0,
|
||||
sizeof(struct iwl_notif_statistics));
|
||||
memset(&priv->_agn.max_delta, 0,
|
||||
memset(&priv->_4965.max_delta, 0,
|
||||
sizeof(struct iwl_notif_statistics));
|
||||
memset(&priv->_agn.accum_statistics_bt, 0,
|
||||
sizeof(struct iwl_bt_notif_statistics));
|
||||
memset(&priv->_agn.delta_statistics_bt, 0,
|
||||
sizeof(struct iwl_bt_notif_statistics));
|
||||
memset(&priv->_agn.max_delta_bt, 0,
|
||||
sizeof(struct iwl_bt_notif_statistics));
|
||||
#endif
|
||||
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
|
||||
}
|
||||
iwl_rx_statistics(priv, rxb);
|
||||
iwl4965_rx_statistics(priv, rxb);
|
||||
}
|
|
@ -0,0 +1,721 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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 <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-4965.h"
|
||||
|
||||
static struct iwl_link_quality_cmd *
|
||||
iwl4965_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
int i, r;
|
||||
struct iwl_link_quality_cmd *link_cmd;
|
||||
u32 rate_flags = 0;
|
||||
__le32 rate_n_flags;
|
||||
|
||||
link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
|
||||
if (!link_cmd) {
|
||||
IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
|
||||
return NULL;
|
||||
}
|
||||
/* Set up the rate scaling to start at selected rate, fall back
|
||||
* all the way down to 1M in IEEE order, and then spin on 1M */
|
||||
if (priv->band == IEEE80211_BAND_5GHZ)
|
||||
r = IWL_RATE_6M_INDEX;
|
||||
else
|
||||
r = IWL_RATE_1M_INDEX;
|
||||
|
||||
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
|
||||
rate_flags |= iwl4965_first_antenna(priv->hw_params.valid_tx_ant) <<
|
||||
RATE_MCS_ANT_POS;
|
||||
rate_n_flags = iwl4965_hw_set_rate_n_flags(iwlegacy_rates[r].plcp,
|
||||
rate_flags);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
|
||||
|
||||
link_cmd->general_params.single_stream_ant_msk =
|
||||
iwl4965_first_antenna(priv->hw_params.valid_tx_ant);
|
||||
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant &
|
||||
~iwl4965_first_antenna(priv->hw_params.valid_tx_ant);
|
||||
if (!link_cmd->general_params.dual_stream_ant_msk) {
|
||||
link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
|
||||
} else if (iwl4965_num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
|
||||
link_cmd->general_params.dual_stream_ant_msk =
|
||||
priv->hw_params.valid_tx_ant;
|
||||
}
|
||||
|
||||
link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||
link_cmd->agg_params.agg_time_limit =
|
||||
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||
|
||||
link_cmd->sta_id = sta_id;
|
||||
|
||||
return link_cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl4965_add_bssid_station - Add the special IBSS BSSID station
|
||||
*
|
||||
* Function sleeps.
|
||||
*/
|
||||
int
|
||||
iwl4965_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, u8 *sta_id_r)
|
||||
{
|
||||
int ret;
|
||||
u8 sta_id;
|
||||
struct iwl_link_quality_cmd *link_cmd;
|
||||
unsigned long flags;
|
||||
|
||||
if (sta_id_r)
|
||||
*sta_id_r = IWL_INVALID_STATION;
|
||||
|
||||
ret = iwl_legacy_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Unable to add station %pM\n", addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sta_id_r)
|
||||
*sta_id_r = sta_id;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].used |= IWL_STA_LOCAL;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
/* Set up default rate scaling table in device's station table */
|
||||
link_cmd = iwl4965_sta_alloc_lq(priv, sta_id);
|
||||
if (!link_cmd) {
|
||||
IWL_ERR(priv,
|
||||
"Unable to initialize rate scaling for station %pM.\n",
|
||||
addr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = iwl_legacy_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].lq = link_cmd;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl4965_static_wepkey_cmd(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
bool send_if_empty)
|
||||
{
|
||||
int i, not_empty = 0;
|
||||
u8 buff[sizeof(struct iwl_wep_cmd) +
|
||||
sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
|
||||
struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
|
||||
size_t cmd_size = sizeof(struct iwl_wep_cmd);
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = ctx->wep_key_cmd,
|
||||
.data = wep_cmd,
|
||||
.flags = CMD_SYNC,
|
||||
};
|
||||
|
||||
might_sleep();
|
||||
|
||||
memset(wep_cmd, 0, cmd_size +
|
||||
(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
|
||||
|
||||
for (i = 0; i < WEP_KEYS_MAX ; i++) {
|
||||
wep_cmd->key[i].key_index = i;
|
||||
if (ctx->wep_keys[i].key_size) {
|
||||
wep_cmd->key[i].key_offset = i;
|
||||
not_empty = 1;
|
||||
} else {
|
||||
wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
|
||||
}
|
||||
|
||||
wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
|
||||
memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
|
||||
ctx->wep_keys[i].key_size);
|
||||
}
|
||||
|
||||
wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
|
||||
wep_cmd->num_keys = WEP_KEYS_MAX;
|
||||
|
||||
cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
|
||||
|
||||
cmd.len = cmd_size;
|
||||
|
||||
if (not_empty || send_if_empty)
|
||||
return iwl_legacy_send_cmd(priv, &cmd);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl4965_restore_default_wep_keys(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
return iwl4965_static_wepkey_cmd(priv, ctx, false);
|
||||
}
|
||||
|
||||
int iwl4965_remove_default_wep_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
|
||||
keyconf->keyidx);
|
||||
|
||||
memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
|
||||
if (iwl_legacy_is_rfkill(priv)) {
|
||||
IWL_DEBUG_WEP(priv,
|
||||
"Not sending REPLY_WEPKEY command due to RFKILL.\n");
|
||||
/* but keys in device are clear anyway so return success */
|
||||
return 0;
|
||||
}
|
||||
ret = iwl4965_static_wepkey_cmd(priv, ctx, 1);
|
||||
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
|
||||
keyconf->keyidx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl4965_set_default_wep_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (keyconf->keylen != WEP_KEY_LEN_128 &&
|
||||
keyconf->keylen != WEP_KEY_LEN_64) {
|
||||
IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->hw_key_idx = HW_KEY_DEFAULT;
|
||||
priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher;
|
||||
|
||||
ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
|
||||
memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
ret = iwl4965_static_wepkey_cmd(priv, ctx, false);
|
||||
IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
|
||||
keyconf->keylen, keyconf->keyidx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl4965_set_wep_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
__le16 key_flags = 0;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
|
||||
key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (keyconf->keylen == WEP_KEY_LEN_128)
|
||||
key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
|
||||
|
||||
if (sta_id == ctx->bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||
priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
|
||||
|
||||
memcpy(priv->stations[sta_id].keyinfo.key,
|
||||
keyconf->key, keyconf->keylen);
|
||||
|
||||
memcpy(&priv->stations[sta_id].sta.key.key[3],
|
||||
keyconf->key, keyconf->keylen);
|
||||
|
||||
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
||||
== STA_KEY_FLG_NO_ENC)
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_legacy_get_free_ucode_key_index(priv);
|
||||
/* else, we are overriding an existing key => no need to allocated room
|
||||
* in uCode. */
|
||||
|
||||
WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
|
||||
"no space for a new key");
|
||||
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
__le16 key_flags = 0;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (sta_id == ctx->bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
||||
== STA_KEY_FLG_NO_ENC)
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_legacy_get_free_ucode_key_index(priv);
|
||||
/* else, we are overriding an existing key => no need to allocated room
|
||||
* in uCode. */
|
||||
|
||||
WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
|
||||
"no space for a new key");
|
||||
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
__le16 key_flags = 0;
|
||||
|
||||
key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (sta_id == ctx->bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
|
||||
priv->stations[sta_id].keyinfo.keylen = 16;
|
||||
|
||||
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
||||
== STA_KEY_FLG_NO_ENC)
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_legacy_get_free_ucode_key_index(priv);
|
||||
/* else, we are overriding an existing key => no need to allocated room
|
||||
* in uCode. */
|
||||
|
||||
WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
|
||||
"no space for a new key");
|
||||
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
|
||||
|
||||
/* This copy is acutally not needed: we get the key with each TX */
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl4965_update_tkip_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
|
||||
{
|
||||
u8 sta_id;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (iwl_legacy_scan_cancel(priv)) {
|
||||
/* cancel scan failed, just live w/ bad key and rely
|
||||
briefly on SW decryption */
|
||||
return;
|
||||
}
|
||||
|
||||
sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, sta);
|
||||
if (sta_id == IWL_INVALID_STATION)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
|
||||
cpu_to_le16(phase1key[i]);
|
||||
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
iwl_legacy_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
}
|
||||
|
||||
int iwl4965_remove_dynamic_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 key_flags;
|
||||
u8 keyidx;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
ctx->key_mapping_keys--;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
|
||||
keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
|
||||
|
||||
IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
|
||||
keyconf->keyidx, sta_id);
|
||||
|
||||
if (keyconf->keyidx != keyidx) {
|
||||
/* We need to remove a key with index different that the one
|
||||
* in the uCode. This means that the key we need to remove has
|
||||
* been replaced by another one with different index.
|
||||
* Don't do anything and return ok
|
||||
*/
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
|
||||
IWL_WARN(priv, "Removing wrong key %d 0x%x\n",
|
||||
keyconf->keyidx, key_flags);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
|
||||
&priv->ucode_key_table))
|
||||
IWL_ERR(priv, "index %d not used in uCode key table.\n",
|
||||
priv->stations[sta_id].sta.key.key_offset);
|
||||
memset(&priv->stations[sta_id].keyinfo, 0,
|
||||
sizeof(struct iwl_hw_key));
|
||||
memset(&priv->stations[sta_id].sta.key, 0,
|
||||
sizeof(struct iwl4965_keyinfo));
|
||||
priv->stations[sta_id].sta.key.key_flags =
|
||||
STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
|
||||
priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
if (iwl_legacy_is_rfkill(priv)) {
|
||||
IWL_DEBUG_WEP(priv,
|
||||
"Not sending REPLY_ADD_STA command because RFKILL enabled.\n");
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
int iwl4965_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf, u8 sta_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
ctx->key_mapping_keys++;
|
||||
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
|
||||
|
||||
switch (keyconf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
ret = iwl4965_set_ccmp_dynamic_key_info(priv, ctx,
|
||||
keyconf, sta_id);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
ret = iwl4965_set_tkip_dynamic_key_info(priv, ctx,
|
||||
keyconf, sta_id);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
ret = iwl4965_set_wep_dynamic_key_info(priv, ctx,
|
||||
keyconf, sta_id);
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(priv,
|
||||
"Unknown alg: %s cipher = %x\n", __func__,
|
||||
keyconf->cipher);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_WEP(priv,
|
||||
"Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n",
|
||||
keyconf->cipher, keyconf->keylen, keyconf->keyidx,
|
||||
sta_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_alloc_bcast_station - add broadcast station into driver's station table.
|
||||
*
|
||||
* This adds the broadcast station into the driver's station table
|
||||
* and marks it driver active, so that it will be restored to the
|
||||
* device at the next best time.
|
||||
*/
|
||||
int iwl4965_alloc_bcast_station(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct iwl_link_quality_cmd *link_cmd;
|
||||
unsigned long flags;
|
||||
u8 sta_id;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
sta_id = iwl_legacy_prep_station(priv, ctx, iwlegacy_bcast_addr,
|
||||
false, NULL);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_ERR(priv, "Unable to prepare broadcast station\n");
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
|
||||
priv->stations[sta_id].used |= IWL_STA_BCAST;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
link_cmd = iwl4965_sta_alloc_lq(priv, sta_id);
|
||||
if (!link_cmd) {
|
||||
IWL_ERR(priv,
|
||||
"Unable to initialize rate scaling for bcast station.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].lq = link_cmd;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_update_bcast_station - update broadcast station's LQ command
|
||||
*
|
||||
* Only used by iwl4965. Placed here to have all bcast station management
|
||||
* code together.
|
||||
*/
|
||||
static int iwl4965_update_bcast_station(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_link_quality_cmd *link_cmd;
|
||||
u8 sta_id = ctx->bcast_sta_id;
|
||||
|
||||
link_cmd = iwl4965_sta_alloc_lq(priv, sta_id);
|
||||
if (!link_cmd) {
|
||||
IWL_ERR(priv,
|
||||
"Unable to initialize rate scaling for bcast station.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
if (priv->stations[sta_id].lq)
|
||||
kfree(priv->stations[sta_id].lq);
|
||||
else
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Bcast station rate scaling has not been initialized yet.\n");
|
||||
priv->stations[sta_id].lq = link_cmd;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl4965_update_bcast_stations(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
int ret = 0;
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
ret = iwl4965_update_bcast_station(priv, ctx);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
|
||||
*/
|
||||
int iwl4965_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
/* Remove "disable" flag, to enable Tx for this TID */
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
|
||||
priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
int iwl4965_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn)
|
||||
{
|
||||
unsigned long flags;
|
||||
int sta_id;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
sta_id = iwl_legacy_sta_id(sta);
|
||||
if (sta_id == IWL_INVALID_STATION)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].sta.station_flags_msk = 0;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
|
||||
priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
|
||||
priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
int iwl4965_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
|
||||
int tid)
|
||||
{
|
||||
unsigned long flags;
|
||||
int sta_id;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
sta_id = iwl_legacy_sta_id(sta);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].sta.station_flags_msk = 0;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
|
||||
priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
}
|
||||
|
||||
void
|
||||
iwl4965_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.sta.modify_mask =
|
||||
STA_MODIFY_SLEEP_TX_COUNT_MSK;
|
||||
priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
iwl_legacy_send_add_sta(priv,
|
||||
&priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,166 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
#include "iwl-4965-hw.h"
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-4965-calib.h"
|
||||
|
||||
#define IWL_AC_UNSET -1
|
||||
|
||||
/**
|
||||
* iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
|
||||
* using sample data 100 bytes apart. If these sample points are good,
|
||||
* it's a pretty good bet that everything between them is good, too.
|
||||
*/
|
||||
static int
|
||||
iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
|
||||
{
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
u32 errcnt = 0;
|
||||
u32 i;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
|
||||
|
||||
for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
|
||||
/* read data comes through single port, auto-incr addr */
|
||||
/* NOTE: Use the debugless read so we don't flood kernel log
|
||||
* if IWL_DL_IO is set */
|
||||
iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_RADDR,
|
||||
i + IWL4965_RTC_INST_LOWER_BOUND);
|
||||
val = _iwl_legacy_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
if (val != le32_to_cpu(*image)) {
|
||||
ret = -EIO;
|
||||
errcnt++;
|
||||
if (errcnt >= 3)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
|
||||
* looking at all data.
|
||||
*/
|
||||
static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
|
||||
u32 len)
|
||||
{
|
||||
u32 val;
|
||||
u32 save_len = len;
|
||||
int ret = 0;
|
||||
u32 errcnt;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
|
||||
|
||||
iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_RADDR,
|
||||
IWL4965_RTC_INST_LOWER_BOUND);
|
||||
|
||||
errcnt = 0;
|
||||
for (; len > 0; len -= sizeof(u32), image++) {
|
||||
/* read data comes through single port, auto-incr addr */
|
||||
/* NOTE: Use the debugless read so we don't flood kernel log
|
||||
* if IWL_DL_IO is set */
|
||||
val = _iwl_legacy_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
if (val != le32_to_cpu(*image)) {
|
||||
IWL_ERR(priv, "uCode INST section is invalid at "
|
||||
"offset 0x%x, is 0x%x, s/b 0x%x\n",
|
||||
save_len - len, val, le32_to_cpu(*image));
|
||||
ret = -EIO;
|
||||
errcnt++;
|
||||
if (errcnt >= 20)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errcnt)
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"ucode image in INSTRUCTION memory is good\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_verify_ucode - determine which instruction image is in SRAM,
|
||||
* and verify its contents
|
||||
*/
|
||||
int iwl4965_verify_ucode(struct iwl_priv *priv)
|
||||
{
|
||||
__le32 *image;
|
||||
u32 len;
|
||||
int ret;
|
||||
|
||||
/* Try bootstrap */
|
||||
image = (__le32 *)priv->ucode_boot.v_addr;
|
||||
len = priv->ucode_boot.len;
|
||||
ret = iwl4965_verify_inst_sparse(priv, image, len);
|
||||
if (!ret) {
|
||||
IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try initialize */
|
||||
image = (__le32 *)priv->ucode_init.v_addr;
|
||||
len = priv->ucode_init.len;
|
||||
ret = iwl4965_verify_inst_sparse(priv, image, len);
|
||||
if (!ret) {
|
||||
IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try runtime/protocol */
|
||||
image = (__le32 *)priv->ucode_code.v_addr;
|
||||
len = priv->ucode_code.len;
|
||||
ret = iwl4965_verify_inst_sparse(priv, image, len);
|
||||
if (!ret) {
|
||||
IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
|
||||
|
||||
/* Since nothing seems to match, show first several data entries in
|
||||
* instruction SRAM, so maybe visual inspection will give a clue.
|
||||
* Selection of bootstrap image (vs. other images) is arbitrary. */
|
||||
image = (__le32 *)priv->ucode_boot.v_addr;
|
||||
len = priv->ucode_boot.len;
|
||||
ret = iwl4965_verify_inst_full(priv, image, len);
|
||||
|
||||
return ret;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,282 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_4965_h__
|
||||
#define __iwl_4965_h__
|
||||
|
||||
#include "iwl-dev.h"
|
||||
|
||||
/* configuration for the _4965 devices */
|
||||
extern struct iwl_cfg iwl4965_cfg;
|
||||
|
||||
extern struct iwl_mod_params iwl4965_mod_params;
|
||||
|
||||
extern struct ieee80211_ops iwl4965_hw_ops;
|
||||
|
||||
/* tx queue */
|
||||
void iwl4965_free_tfds_in_queue(struct iwl_priv *priv,
|
||||
int sta_id, int tid, int freed);
|
||||
|
||||
/* RXON */
|
||||
void iwl4965_set_rxon_chain(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
|
||||
/* uCode */
|
||||
int iwl4965_verify_ucode(struct iwl_priv *priv);
|
||||
|
||||
/* lib */
|
||||
void iwl4965_check_abort_status(struct iwl_priv *priv,
|
||||
u8 frame_count, u32 status);
|
||||
|
||||
void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
int iwl4965_hw_nic_init(struct iwl_priv *priv);
|
||||
int iwl4965_dump_fh(struct iwl_priv *priv, char **buf, bool display);
|
||||
|
||||
/* rx */
|
||||
void iwl4965_rx_queue_restock(struct iwl_priv *priv);
|
||||
void iwl4965_rx_replenish(struct iwl_priv *priv);
|
||||
void iwl4965_rx_replenish_now(struct iwl_priv *priv);
|
||||
void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
int iwl4965_rxq_stop(struct iwl_priv *priv);
|
||||
int iwl4965_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
|
||||
void iwl4965_rx_reply_rx(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl4965_rx_handle(struct iwl_priv *priv);
|
||||
|
||||
/* tx */
|
||||
void iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
|
||||
int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
dma_addr_t addr, u16 len, u8 reset, u8 pad);
|
||||
int iwl4965_hw_tx_queue_init(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq);
|
||||
void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
|
||||
struct ieee80211_tx_info *info);
|
||||
int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
|
||||
int iwl4965_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
int iwl4965_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, u16 tid);
|
||||
int iwl4965_txq_check_empty(struct iwl_priv *priv,
|
||||
int sta_id, u8 tid, int txq_id);
|
||||
void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
|
||||
void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv);
|
||||
int iwl4965_txq_ctx_alloc(struct iwl_priv *priv);
|
||||
void iwl4965_txq_ctx_reset(struct iwl_priv *priv);
|
||||
void iwl4965_txq_ctx_stop(struct iwl_priv *priv);
|
||||
void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask);
|
||||
|
||||
/*
|
||||
* Acquire priv->lock before calling this function !
|
||||
*/
|
||||
void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index);
|
||||
/**
|
||||
* iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue
|
||||
* @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed
|
||||
* @scd_retry: (1) Indicates queue will be used in aggregation mode
|
||||
*
|
||||
* NOTE: Acquire priv->lock before calling this function !
|
||||
*/
|
||||
void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
int tx_fifo_id, int scd_retry);
|
||||
|
||||
static inline u32 iwl4965_tx_status_to_mac80211(u32 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
|
||||
switch (status) {
|
||||
case TX_STATUS_SUCCESS:
|
||||
case TX_STATUS_DIRECT_DONE:
|
||||
return IEEE80211_TX_STAT_ACK;
|
||||
case TX_STATUS_FAIL_DEST_PS:
|
||||
return IEEE80211_TX_STAT_TX_FILTERED;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool iwl4965_is_tx_success(u32 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
return (status == TX_STATUS_SUCCESS) ||
|
||||
(status == TX_STATUS_DIRECT_DONE);
|
||||
}
|
||||
|
||||
u8 iwl4965_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
|
||||
|
||||
/* rx */
|
||||
void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
bool iwl4965_good_plcp_health(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl4965_rx_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl4965_reply_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
|
||||
/* scan */
|
||||
int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
|
||||
/* station mgmt */
|
||||
int iwl4965_manage_ibss_station(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif, bool add);
|
||||
|
||||
/* hcmd */
|
||||
int iwl4965_send_beacon_cmd(struct iwl_priv *priv);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
const char *iwl4965_get_tx_fail_reason(u32 status);
|
||||
#else
|
||||
static inline const char *
|
||||
iwl4965_get_tx_fail_reason(u32 status) { return ""; }
|
||||
#endif
|
||||
|
||||
/* station management */
|
||||
int iwl4965_alloc_bcast_station(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
int iwl4965_add_bssid_station(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, u8 *sta_id_r);
|
||||
int iwl4965_remove_default_wep_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *key);
|
||||
int iwl4965_set_default_wep_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *key);
|
||||
int iwl4965_restore_default_wep_keys(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
int iwl4965_set_dynamic_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *key, u8 sta_id);
|
||||
int iwl4965_remove_dynamic_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *key, u8 sta_id);
|
||||
void iwl4965_update_tkip_key(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
|
||||
int iwl4965_sta_tx_modify_enable_tid(struct iwl_priv *priv,
|
||||
int sta_id, int tid);
|
||||
int iwl4965_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
|
||||
int tid, u16 ssn);
|
||||
int iwl4965_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
|
||||
int tid);
|
||||
void iwl4965_sta_modify_sleep_tx_count(struct iwl_priv *priv,
|
||||
int sta_id, int cnt);
|
||||
int iwl4965_update_bcast_stations(struct iwl_priv *priv);
|
||||
|
||||
/* rate */
|
||||
static inline u32 iwl4965_ant_idx_to_flags(u8 ant_idx)
|
||||
{
|
||||
return BIT(ant_idx) << RATE_MCS_ANT_POS;
|
||||
}
|
||||
|
||||
static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags)
|
||||
{
|
||||
return le32_to_cpu(rate_n_flags) & 0xFF;
|
||||
}
|
||||
|
||||
static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u32 flags)
|
||||
{
|
||||
return cpu_to_le32(flags|(u32)rate);
|
||||
}
|
||||
|
||||
/* eeprom */
|
||||
void iwl4965_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
|
||||
int iwl4965_eeprom_acquire_semaphore(struct iwl_priv *priv);
|
||||
void iwl4965_eeprom_release_semaphore(struct iwl_priv *priv);
|
||||
int iwl4965_eeprom_check_version(struct iwl_priv *priv);
|
||||
|
||||
/* mac80211 handlers (for 4965) */
|
||||
void iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int iwl4965_mac_start(struct ieee80211_hw *hw);
|
||||
void iwl4965_mac_stop(struct ieee80211_hw *hw);
|
||||
void iwl4965_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *total_flags,
|
||||
u64 multicast);
|
||||
int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 iv32, u16 *phase1key);
|
||||
int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size);
|
||||
int iwl4965_mac_sta_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
|
||||
#endif /* __iwl_4965_h__ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,646 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_legacy_core_h__
|
||||
#define __iwl_legacy_core_h__
|
||||
|
||||
/************************
|
||||
* forward declarations *
|
||||
************************/
|
||||
struct iwl_host_cmd;
|
||||
struct iwl_cmd;
|
||||
|
||||
|
||||
#define IWLWIFI_VERSION "in-tree:"
|
||||
#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
|
||||
#define DRV_AUTHOR "<ilw@linux.intel.com>"
|
||||
|
||||
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
|
||||
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
|
||||
.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
|
||||
.driver_data = (kernel_ulong_t)&(cfg)
|
||||
|
||||
#define TIME_UNIT 1024
|
||||
|
||||
#define IWL_SKU_G 0x1
|
||||
#define IWL_SKU_A 0x2
|
||||
#define IWL_SKU_N 0x8
|
||||
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
|
||||
struct iwl_hcmd_ops {
|
||||
int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
|
||||
void (*set_rxon_chain)(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
};
|
||||
|
||||
struct iwl_hcmd_utils_ops {
|
||||
u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
|
||||
u16 (*build_addsta_hcmd)(const struct iwl_legacy_addsta_cmd *cmd,
|
||||
u8 *data);
|
||||
int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
|
||||
void (*post_scan)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
struct iwl_apm_ops {
|
||||
int (*init)(struct iwl_priv *priv);
|
||||
void (*config)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
struct iwl_debugfs_ops {
|
||||
ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
ssize_t (*general_stats_read)(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos);
|
||||
};
|
||||
|
||||
struct iwl_temp_ops {
|
||||
void (*temperature)(struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
struct iwl_lib_ops {
|
||||
/* set hw dependent parameters */
|
||||
int (*set_hw_params)(struct iwl_priv *priv);
|
||||
/* Handling TX */
|
||||
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
u16 byte_cnt);
|
||||
int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
dma_addr_t addr,
|
||||
u16 len, u8 reset, u8 pad);
|
||||
void (*txq_free_tfd)(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq);
|
||||
int (*txq_init)(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq);
|
||||
/* setup Rx handler */
|
||||
void (*rx_handler_setup)(struct iwl_priv *priv);
|
||||
/* alive notification after init uCode load */
|
||||
void (*init_alive_start)(struct iwl_priv *priv);
|
||||
/* check validity of rtc data address */
|
||||
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||
/* 1st ucode load */
|
||||
int (*load_ucode)(struct iwl_priv *priv);
|
||||
int (*dump_nic_event_log)(struct iwl_priv *priv,
|
||||
bool full_log, char **buf, bool display);
|
||||
void (*dump_nic_error_log)(struct iwl_priv *priv);
|
||||
int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
|
||||
int (*set_channel_switch)(struct iwl_priv *priv,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
/* power management */
|
||||
struct iwl_apm_ops apm_ops;
|
||||
|
||||
/* power */
|
||||
int (*send_tx_power) (struct iwl_priv *priv);
|
||||
void (*update_chain_flags)(struct iwl_priv *priv);
|
||||
|
||||
/* eeprom operations (as defined in iwl-eeprom.h) */
|
||||
struct iwl_eeprom_ops eeprom_ops;
|
||||
|
||||
/* temperature */
|
||||
struct iwl_temp_ops temp_ops;
|
||||
/* check for plcp health */
|
||||
bool (*check_plcp_health)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
struct iwl_debugfs_ops debugfs_ops;
|
||||
|
||||
};
|
||||
|
||||
struct iwl_led_ops {
|
||||
int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
|
||||
};
|
||||
|
||||
struct iwl_legacy_ops {
|
||||
void (*post_associate)(struct iwl_priv *priv);
|
||||
void (*config_ap)(struct iwl_priv *priv);
|
||||
/* station management */
|
||||
int (*update_bcast_stations)(struct iwl_priv *priv);
|
||||
int (*manage_ibss_station)(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif, bool add);
|
||||
};
|
||||
|
||||
struct iwl_ops {
|
||||
const struct iwl_lib_ops *lib;
|
||||
const struct iwl_hcmd_ops *hcmd;
|
||||
const struct iwl_hcmd_utils_ops *utils;
|
||||
const struct iwl_led_ops *led;
|
||||
const struct iwl_nic_ops *nic;
|
||||
const struct iwl_legacy_ops *legacy;
|
||||
const struct ieee80211_ops *ieee80211_ops;
|
||||
};
|
||||
|
||||
struct iwl_mod_params {
|
||||
int sw_crypto; /* def: 0 = using hardware encryption */
|
||||
int disable_hw_scan; /* def: 0 = use h/w scan */
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
int disable_11n; /* def: 0 = 11n capabilities enabled */
|
||||
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
||||
int antenna; /* def: 0 = both antennas (use diversity) */
|
||||
int restart_fw; /* def: 1 = restart firmware */
|
||||
};
|
||||
|
||||
/*
|
||||
* @led_compensation: compensate on the led on/off time per HW according
|
||||
* to the deviation to achieve the desired led frequency.
|
||||
* The detail algorithm is described in iwl-led.c
|
||||
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
||||
* @plcp_delta_threshold: plcp error rate threshold used to trigger
|
||||
* radio tuning when there is a high receiving plcp error rate
|
||||
* @wd_timeout: TX queues watchdog timeout
|
||||
* @temperature_kelvin: temperature report by uCode in kelvin
|
||||
* @max_event_log_size: size of event log buffer size for ucode event logging
|
||||
* @ucode_tracing: support ucode continuous tracing
|
||||
* @sensitivity_calib_by_driver: driver has the capability to perform
|
||||
* sensitivity calibration operation
|
||||
* @chain_noise_calib_by_driver: driver has the capability to perform
|
||||
* chain noise calibration operation
|
||||
*/
|
||||
struct iwl_base_params {
|
||||
int eeprom_size;
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
int num_of_ampdu_queues;/* def: HW dependent */
|
||||
/* for iwl_legacy_apm_init() */
|
||||
u32 pll_cfg_val;
|
||||
bool set_l0s;
|
||||
bool use_bsm;
|
||||
|
||||
u16 led_compensation;
|
||||
int chain_noise_num_beacons;
|
||||
u8 plcp_delta_threshold;
|
||||
unsigned int wd_timeout;
|
||||
bool temperature_kelvin;
|
||||
u32 max_event_log_size;
|
||||
const bool ucode_tracing;
|
||||
const bool sensitivity_calib_by_driver;
|
||||
const bool chain_noise_calib_by_driver;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_cfg
|
||||
* @fw_name_pre: Firmware filename prefix. The api version and extension
|
||||
* (.ucode) will be added to filename before loading from disk. The
|
||||
* filename is constructed as fw_name_pre<api>.ucode.
|
||||
* @ucode_api_max: Highest version of uCode API supported by driver.
|
||||
* @ucode_api_min: Lowest version of uCode API supported by driver.
|
||||
* @scan_antennas: available antenna for scan operation
|
||||
* @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt API version. The
|
||||
* driver specifies which APIs it supports (with @ucode_api_max being the
|
||||
* highest and @ucode_api_min the lowest). Firmware will only be loaded if
|
||||
* it has a supported API version. The firmware's API version will be
|
||||
* stored in @iwl_priv, enabling the driver to make runtime changes based
|
||||
* on firmware version used.
|
||||
*
|
||||
* For example,
|
||||
* if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
|
||||
* Driver interacts with Firmware API version >= 2.
|
||||
* } else {
|
||||
* Driver interacts with Firmware API version 1.
|
||||
* }
|
||||
*
|
||||
* The ideal usage of this infrastructure is to treat a new ucode API
|
||||
* release as a new hardware revision. That is, through utilizing the
|
||||
* iwl_hcmd_utils_ops etc. we accommodate different command structures
|
||||
* and flows between hardware versions as well as their API
|
||||
* versions.
|
||||
*
|
||||
*/
|
||||
struct iwl_cfg {
|
||||
/* params specific to an individual device within a device family */
|
||||
const char *name;
|
||||
const char *fw_name_pre;
|
||||
const unsigned int ucode_api_max;
|
||||
const unsigned int ucode_api_min;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
unsigned int sku;
|
||||
u16 eeprom_ver;
|
||||
u16 eeprom_calib_ver;
|
||||
const struct iwl_ops *ops;
|
||||
/* module based parameters which can be set from modprobe cmd */
|
||||
const struct iwl_mod_params *mod_params;
|
||||
/* params not likely to change within a device family */
|
||||
struct iwl_base_params *base_params;
|
||||
/* params likely to change within a device family */
|
||||
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
|
||||
u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
|
||||
enum iwl_led_mode led_mode;
|
||||
};
|
||||
|
||||
/***************************
|
||||
* L i b *
|
||||
***************************/
|
||||
|
||||
struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg);
|
||||
int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw);
|
||||
void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
int hw_decrypt);
|
||||
int iwl_legacy_check_rxon_cmd(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
int iwl_legacy_full_rxon_required(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
int iwl_legacy_set_rxon_channel(struct iwl_priv *priv,
|
||||
struct ieee80211_channel *ch,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_legacy_set_flags_for_band(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif);
|
||||
u8 iwl_legacy_get_single_channel_number(struct iwl_priv *priv,
|
||||
enum ieee80211_band band);
|
||||
void iwl_legacy_set_rxon_ht(struct iwl_priv *priv,
|
||||
struct iwl_ht_config *ht_conf);
|
||||
bool iwl_legacy_is_ht40_tx_allowed(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
void iwl_legacy_connection_init_rx_config(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_legacy_set_rate(struct iwl_priv *priv);
|
||||
int iwl_legacy_set_decrypted_flag(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,
|
||||
u32 decrypt_res,
|
||||
struct ieee80211_rx_status *stats);
|
||||
void iwl_legacy_irq_handle_error(struct iwl_priv *priv);
|
||||
int iwl_legacy_mac_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_legacy_mac_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
int iwl_legacy_mac_change_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum nl80211_iftype newtype, bool newp2p);
|
||||
int iwl_legacy_alloc_txq_mem(struct iwl_priv *priv);
|
||||
void iwl_legacy_txq_mem(struct iwl_priv *priv);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
int iwl_legacy_alloc_traffic_mem(struct iwl_priv *priv);
|
||||
void iwl_legacy_free_traffic_mem(struct iwl_priv *priv);
|
||||
void iwl_legacy_reset_traffic_log(struct iwl_priv *priv);
|
||||
void iwl_legacy_dbg_log_tx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header);
|
||||
void iwl_legacy_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header);
|
||||
const char *iwl_legacy_get_mgmt_string(int cmd);
|
||||
const char *iwl_legacy_get_ctrl_string(int cmd);
|
||||
void iwl_legacy_clear_traffic_stats(struct iwl_priv *priv);
|
||||
void iwl_legacy_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
|
||||
u16 len);
|
||||
#else
|
||||
static inline int iwl_legacy_alloc_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void iwl_legacy_free_traffic_mem(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
static inline void iwl_legacy_reset_traffic_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
static inline void iwl_legacy_dbg_log_tx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
}
|
||||
static inline void iwl_legacy_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
||||
u16 length, struct ieee80211_hdr *header)
|
||||
{
|
||||
}
|
||||
static inline void iwl_legacy_update_stats(struct iwl_priv *priv, bool is_tx,
|
||||
__le16 fc, u16 len)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/*****************************************************
|
||||
* RX handlers.
|
||||
* **************************************************/
|
||||
void iwl_legacy_rx_pm_sleep_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_legacy_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_legacy_rx_reply_error(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
|
||||
/*****************************************************
|
||||
* RX
|
||||
******************************************************/
|
||||
void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv);
|
||||
void iwl_legacy_cmd_queue_free(struct iwl_priv *priv);
|
||||
int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv);
|
||||
void iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv,
|
||||
struct iwl_rx_queue *q);
|
||||
int iwl_legacy_rx_queue_space(const struct iwl_rx_queue *q);
|
||||
void iwl_legacy_tx_cmd_complete(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
/* Handlers */
|
||||
void iwl_legacy_rx_spectrum_measure_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_legacy_recover_from_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl_legacy_chswitch_done(struct iwl_priv *priv, bool is_success);
|
||||
void iwl_legacy_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
|
||||
|
||||
/* TX helpers */
|
||||
|
||||
/*****************************************************
|
||||
* TX
|
||||
******************************************************/
|
||||
void iwl_legacy_txq_update_write_ptr(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq);
|
||||
int iwl_legacy_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id);
|
||||
void iwl_legacy_tx_queue_reset(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id);
|
||||
void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
|
||||
void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id);
|
||||
void iwl_legacy_setup_watchdog(struct iwl_priv *priv);
|
||||
/*****************************************************
|
||||
* TX power
|
||||
****************************************************/
|
||||
int iwl_legacy_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
|
||||
|
||||
/*******************************************************************************
|
||||
* Rate
|
||||
******************************************************************************/
|
||||
|
||||
u8 iwl_legacy_get_lowest_plcp(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
|
||||
/*******************************************************************************
|
||||
* Scanning
|
||||
******************************************************************************/
|
||||
void iwl_legacy_init_scan_params(struct iwl_priv *priv);
|
||||
int iwl_legacy_scan_cancel(struct iwl_priv *priv);
|
||||
int iwl_legacy_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
|
||||
void iwl_legacy_force_scan_end(struct iwl_priv *priv);
|
||||
int iwl_legacy_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
void iwl_legacy_internal_short_hw_scan(struct iwl_priv *priv);
|
||||
int iwl_legacy_force_reset(struct iwl_priv *priv, int mode, bool external);
|
||||
u16 iwl_legacy_fill_probe_req(struct iwl_priv *priv,
|
||||
struct ieee80211_mgmt *frame,
|
||||
const u8 *ta, const u8 *ie, int ie_len, int left);
|
||||
void iwl_legacy_setup_rx_scan_handlers(struct iwl_priv *priv);
|
||||
u16 iwl_legacy_get_active_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u8 n_probes);
|
||||
u16 iwl_legacy_get_passive_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_legacy_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||
void iwl_legacy_cancel_scan_deferred_work(struct iwl_priv *priv);
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
* ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
|
||||
* time if it's a quiet channel (nothing responded to our probe, and there's
|
||||
* no other traffic).
|
||||
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
|
||||
#define IWL_ACTIVE_QUIET_TIME cpu_to_le16(10) /* msec */
|
||||
#define IWL_PLCP_QUIET_THRESH cpu_to_le16(1) /* packets */
|
||||
|
||||
#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7)
|
||||
|
||||
/*****************************************************
|
||||
* S e n d i n g H o s t C o m m a n d s *
|
||||
*****************************************************/
|
||||
|
||||
const char *iwl_legacy_get_cmd_string(u8 cmd);
|
||||
int __must_check iwl_legacy_send_cmd_sync(struct iwl_priv *priv,
|
||||
struct iwl_host_cmd *cmd);
|
||||
int iwl_legacy_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
||||
int __must_check iwl_legacy_send_cmd_pdu(struct iwl_priv *priv, u8 id,
|
||||
u16 len, const void *data);
|
||||
int iwl_legacy_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
|
||||
const void *data,
|
||||
void (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct iwl_rx_packet *pkt));
|
||||
|
||||
int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* PCI *
|
||||
*****************************************************/
|
||||
|
||||
static inline u16 iwl_legacy_pcie_link_ctl(struct iwl_priv *priv)
|
||||
{
|
||||
int pos;
|
||||
u16 pci_lnk_ctl;
|
||||
pos = pci_find_capability(priv->pci_dev, PCI_CAP_ID_EXP);
|
||||
pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
|
||||
return pci_lnk_ctl;
|
||||
}
|
||||
|
||||
void iwl_legacy_bg_watchdog(unsigned long data);
|
||||
u32 iwl_legacy_usecs_to_beacons(struct iwl_priv *priv,
|
||||
u32 usec, u32 beacon_interval);
|
||||
__le32 iwl_legacy_add_beacon_time(struct iwl_priv *priv, u32 base,
|
||||
u32 addon, u32 beacon_interval);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int iwl_legacy_pci_suspend(struct device *device);
|
||||
int iwl_legacy_pci_resume(struct device *device);
|
||||
extern const struct dev_pm_ops iwl_legacy_pm_ops;
|
||||
|
||||
#define IWL_LEGACY_PM_OPS (&iwl_legacy_pm_ops)
|
||||
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
#define IWL_LEGACY_PM_OPS NULL
|
||||
|
||||
#endif /* !CONFIG_PM */
|
||||
|
||||
/*****************************************************
|
||||
* Error Handling Debugging
|
||||
******************************************************/
|
||||
void iwl4965_dump_nic_error_log(struct iwl_priv *priv);
|
||||
int iwl4965_dump_nic_event_log(struct iwl_priv *priv,
|
||||
bool full_log, char **buf, bool display);
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
void iwl_legacy_print_rx_config_cmd(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
#else
|
||||
static inline void iwl_legacy_print_rx_config_cmd(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void iwl_legacy_clear_isr_stats(struct iwl_priv *priv);
|
||||
|
||||
/*****************************************************
|
||||
* GEOS
|
||||
******************************************************/
|
||||
int iwl_legacy_init_geos(struct iwl_priv *priv);
|
||||
void iwl_legacy_free_geos(struct iwl_priv *priv);
|
||||
|
||||
/*************** DRIVER STATUS FUNCTIONS *****/
|
||||
|
||||
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
|
||||
/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */
|
||||
#define STATUS_INT_ENABLED 2
|
||||
#define STATUS_RF_KILL_HW 3
|
||||
#define STATUS_CT_KILL 4
|
||||
#define STATUS_INIT 5
|
||||
#define STATUS_ALIVE 6
|
||||
#define STATUS_READY 7
|
||||
#define STATUS_TEMPERATURE 8
|
||||
#define STATUS_GEO_CONFIGURED 9
|
||||
#define STATUS_EXIT_PENDING 10
|
||||
#define STATUS_STATISTICS 12
|
||||
#define STATUS_SCANNING 13
|
||||
#define STATUS_SCAN_ABORTING 14
|
||||
#define STATUS_SCAN_HW 15
|
||||
#define STATUS_POWER_PMI 16
|
||||
#define STATUS_FW_ERROR 17
|
||||
|
||||
|
||||
static inline int iwl_legacy_is_ready(struct iwl_priv *priv)
|
||||
{
|
||||
/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
|
||||
* set but EXIT_PENDING is not */
|
||||
return test_bit(STATUS_READY, &priv->status) &&
|
||||
test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
|
||||
!test_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_alive(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_ALIVE, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_init(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_INIT, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_rfkill_hw(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_RF_KILL_HW, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_rfkill(struct iwl_priv *priv)
|
||||
{
|
||||
return iwl_legacy_is_rfkill_hw(priv);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_ctkill(struct iwl_priv *priv)
|
||||
{
|
||||
return test_bit(STATUS_CT_KILL, &priv->status);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_is_ready_rf(struct iwl_priv *priv)
|
||||
{
|
||||
|
||||
if (iwl_legacy_is_rfkill(priv))
|
||||
return 0;
|
||||
|
||||
return iwl_legacy_is_ready(priv);
|
||||
}
|
||||
|
||||
extern void iwl_legacy_send_bt_config(struct iwl_priv *priv);
|
||||
extern int iwl_legacy_send_statistics_request(struct iwl_priv *priv,
|
||||
u8 flags, bool clear);
|
||||
void iwl_legacy_apm_stop(struct iwl_priv *priv);
|
||||
int iwl_legacy_apm_init(struct iwl_priv *priv);
|
||||
|
||||
int iwl_legacy_send_rxon_timing(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
static inline int iwl_legacy_send_rxon_assoc(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
|
||||
}
|
||||
static inline int iwl_legacy_commit_rxon(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
|
||||
}
|
||||
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
|
||||
struct iwl_priv *priv, enum ieee80211_band band)
|
||||
{
|
||||
return priv->hw->wiphy->bands[band];
|
||||
}
|
||||
|
||||
/* mac80211 handlers */
|
||||
int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
|
||||
void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
|
||||
void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changes);
|
||||
void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv,
|
||||
struct ieee80211_tx_info *info,
|
||||
__le16 fc, __le32 *tx_flags);
|
||||
|
||||
irqreturn_t iwl_legacy_isr(int irq, void *data);
|
||||
|
||||
#endif /* __iwl_legacy_core_h__ */
|
|
@ -0,0 +1,422 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_legacy_csr_h__
|
||||
#define __iwl_legacy_csr_h__
|
||||
/*
|
||||
* CSR (control and status registers)
|
||||
*
|
||||
* CSR registers are mapped directly into PCI bus space, and are accessible
|
||||
* whenever platform supplies power to device, even when device is in
|
||||
* low power states due to driver-invoked device resets
|
||||
* (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes.
|
||||
*
|
||||
* Use iwl_write32() and iwl_read32() family to access these registers;
|
||||
* these provide simple PCI bus access, without waking up the MAC.
|
||||
* Do not use iwl_legacy_write_direct32() family for these registers;
|
||||
* no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ.
|
||||
* The MAC (uCode processor, etc.) does not need to be powered up for accessing
|
||||
* the CSR registers.
|
||||
*
|
||||
* NOTE: Device does need to be awake in order to read this memory
|
||||
* via CSR_EEPROM register
|
||||
*/
|
||||
#define CSR_BASE (0x000)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
|
||||
#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
|
||||
#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
|
||||
#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
|
||||
#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
|
||||
#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
|
||||
#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
|
||||
#define CSR_GP_CNTRL (CSR_BASE+0x024)
|
||||
|
||||
/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */
|
||||
#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
|
||||
|
||||
/*
|
||||
* Hardware revision info
|
||||
* Bit fields:
|
||||
* 31-8: Reserved
|
||||
* 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions
|
||||
* 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
|
||||
* 1-0: "Dash" (-) value, as in A-1, etc.
|
||||
*
|
||||
* NOTE: Revision step affects calculation of CCK txpower for 4965.
|
||||
* NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
|
||||
*/
|
||||
#define CSR_HW_REV (CSR_BASE+0x028)
|
||||
|
||||
/*
|
||||
* EEPROM memory reads
|
||||
*
|
||||
* NOTE: Device must be awake, initialized via apm_ops.init(),
|
||||
* in order to read.
|
||||
*/
|
||||
#define CSR_EEPROM_REG (CSR_BASE+0x02c)
|
||||
#define CSR_EEPROM_GP (CSR_BASE+0x030)
|
||||
|
||||
#define CSR_GIO_REG (CSR_BASE+0x03C)
|
||||
#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
|
||||
#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
|
||||
|
||||
/*
|
||||
* UCODE-DRIVER GP (general purpose) mailbox registers.
|
||||
* SET/CLR registers set/clear bit(s) if "1" is written.
|
||||
*/
|
||||
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
|
||||
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
|
||||
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
|
||||
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
|
||||
|
||||
#define CSR_LED_REG (CSR_BASE+0x094)
|
||||
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
|
||||
|
||||
/* GIO Chicken Bits (PCI Express bus link power management) */
|
||||
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
|
||||
|
||||
/* Analog phase-lock-loop configuration */
|
||||
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
|
||||
|
||||
/*
|
||||
* CSR Hardware Revision Workaround Register. Indicates hardware rev;
|
||||
* "step" determines CCK backoff for txpower calculation. Used for 4965 only.
|
||||
* See also CSR_HW_REV register.
|
||||
* Bit fields:
|
||||
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
|
||||
* 1-0: "Dash" (-) value, as in C-1, etc.
|
||||
*/
|
||||
#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
|
||||
|
||||
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
|
||||
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
|
||||
|
||||
/* Bits for CSR_HW_IF_CONFIG_REG */
|
||||
#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
|
||||
#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
|
||||
|
||||
#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
|
||||
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
|
||||
|
||||
#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
|
||||
#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
|
||||
|
||||
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
|
||||
* acknowledged (reset) by host writing "1" to flagged bits. */
|
||||
#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
|
||||
#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
|
||||
#define CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */
|
||||
#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
|
||||
#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
|
||||
#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
|
||||
#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
|
||||
#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
|
||||
#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */
|
||||
#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */
|
||||
#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */
|
||||
|
||||
#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
|
||||
CSR_INT_BIT_HW_ERR | \
|
||||
CSR_INT_BIT_FH_TX | \
|
||||
CSR_INT_BIT_SW_ERR | \
|
||||
CSR_INT_BIT_RF_KILL | \
|
||||
CSR_INT_BIT_SW_RX | \
|
||||
CSR_INT_BIT_WAKEUP | \
|
||||
CSR_INT_BIT_ALIVE)
|
||||
|
||||
/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
|
||||
#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */
|
||||
#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */
|
||||
#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */
|
||||
#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */
|
||||
#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */
|
||||
#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */
|
||||
#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */
|
||||
#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */
|
||||
|
||||
#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
|
||||
CSR39_FH_INT_BIT_RX_CHNL2 | \
|
||||
CSR_FH_INT_BIT_RX_CHNL1 | \
|
||||
CSR_FH_INT_BIT_RX_CHNL0)
|
||||
|
||||
|
||||
#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \
|
||||
CSR_FH_INT_BIT_TX_CHNL1 | \
|
||||
CSR_FH_INT_BIT_TX_CHNL0)
|
||||
|
||||
#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
|
||||
CSR_FH_INT_BIT_RX_CHNL1 | \
|
||||
CSR_FH_INT_BIT_RX_CHNL0)
|
||||
|
||||
#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \
|
||||
CSR_FH_INT_BIT_TX_CHNL0)
|
||||
|
||||
/* GPIO */
|
||||
#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
|
||||
#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
|
||||
#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC (0x00000200)
|
||||
|
||||
/* RESET */
|
||||
#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
|
||||
#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
|
||||
#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
|
||||
#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
|
||||
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
|
||||
#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
|
||||
|
||||
/*
|
||||
* GP (general purpose) CONTROL REGISTER
|
||||
* Bit fields:
|
||||
* 27: HW_RF_KILL_SW
|
||||
* Indicates state of (platform's) hardware RF-Kill switch
|
||||
* 26-24: POWER_SAVE_TYPE
|
||||
* Indicates current power-saving mode:
|
||||
* 000 -- No power saving
|
||||
* 001 -- MAC power-down
|
||||
* 010 -- PHY (radio) power-down
|
||||
* 011 -- Error
|
||||
* 9-6: SYS_CONFIG
|
||||
* Indicates current system configuration, reflecting pins on chip
|
||||
* as forced high/low by device circuit board.
|
||||
* 4: GOING_TO_SLEEP
|
||||
* Indicates MAC is entering a power-saving sleep power-down.
|
||||
* Not a good time to access device-internal resources.
|
||||
* 3: MAC_ACCESS_REQ
|
||||
* Host sets this to request and maintain MAC wakeup, to allow host
|
||||
* access to device-internal resources. Host must wait for
|
||||
* MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR
|
||||
* device registers.
|
||||
* 2: INIT_DONE
|
||||
* Host sets this to put device into fully operational D0 power mode.
|
||||
* Host resets this after SW_RESET to put device into low power mode.
|
||||
* 0: MAC_CLOCK_READY
|
||||
* Indicates MAC (ucode processor, etc.) is powered up and can run.
|
||||
* Internal resources are accessible.
|
||||
* NOTE: This does not indicate that the processor is actually running.
|
||||
* NOTE: This does not indicate that 4965 or 3945 has completed
|
||||
* init or post-power-down restore of internal SRAM memory.
|
||||
* Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
|
||||
* SRAM is restored and uCode is in normal operation mode.
|
||||
* Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
|
||||
* do not need to save/restore it.
|
||||
* NOTE: After device reset, this bit remains "0" until host sets
|
||||
* INIT_DONE
|
||||
*/
|
||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
|
||||
|
||||
#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
|
||||
|
||||
#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
|
||||
|
||||
|
||||
/* EEPROM REG */
|
||||
#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
|
||||
#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
|
||||
#define CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC)
|
||||
#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)
|
||||
|
||||
/* EEPROM GP */
|
||||
#define CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */
|
||||
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
|
||||
|
||||
/* GP REG */
|
||||
#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
|
||||
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
|
||||
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
|
||||
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
|
||||
#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
|
||||
|
||||
|
||||
/* CSR GIO */
|
||||
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
|
||||
|
||||
/*
|
||||
* UCODE-DRIVER GP (general purpose) mailbox register 1
|
||||
* Host driver and uCode write and/or read this register to communicate with
|
||||
* each other.
|
||||
* Bit fields:
|
||||
* 4: UCODE_DISABLE
|
||||
* Host sets this to request permanent halt of uCode, same as
|
||||
* sending CARD_STATE command with "halt" bit set.
|
||||
* 3: CT_KILL_EXIT
|
||||
* Host sets this to request exit from CT_KILL state, i.e. host thinks
|
||||
* device temperature is low enough to continue normal operation.
|
||||
* 2: CMD_BLOCKED
|
||||
* Host sets this during RF KILL power-down sequence (HW, SW, CT KILL)
|
||||
* to release uCode to clear all Tx and command queues, enter
|
||||
* unassociated mode, and power down.
|
||||
* NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit.
|
||||
* 1: SW_BIT_RFKILL
|
||||
* Host sets this when issuing CARD_STATE command to request
|
||||
* device sleep.
|
||||
* 0: MAC_SLEEP
|
||||
* uCode sets this when preparing a power-saving power-down.
|
||||
* uCode resets this when power-up is complete and SRAM is sane.
|
||||
* NOTE: 3945/4965 saves internal SRAM data to host when powering down,
|
||||
* and must restore this data after powering back up.
|
||||
* MAC_SLEEP is the best indication that restore is complete.
|
||||
* Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
|
||||
* do not need to save/restore it.
|
||||
*/
|
||||
#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
|
||||
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
|
||||
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
|
||||
#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
|
||||
|
||||
/* GIO Chicken Bits (PCI Express bus link power management) */
|
||||
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
|
||||
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
|
||||
|
||||
/* LED */
|
||||
#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
|
||||
#define CSR_LED_REG_TRUN_ON (0x78)
|
||||
#define CSR_LED_REG_TRUN_OFF (0x38)
|
||||
|
||||
/* ANA_PLL */
|
||||
#define CSR39_ANA_PLL_CFG_VAL (0x01000000)
|
||||
|
||||
/* HPET MEM debug */
|
||||
#define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000)
|
||||
|
||||
/* DRAM INT TABLE */
|
||||
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
|
||||
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
|
||||
|
||||
/*
|
||||
* HBUS (Host-side Bus)
|
||||
*
|
||||
* HBUS registers are mapped directly into PCI bus space, but are used
|
||||
* to indirectly access device's internal memory or registers that
|
||||
* may be powered-down.
|
||||
*
|
||||
* Use iwl_legacy_write_direct32()/iwl_legacy_read_direct32() family
|
||||
* for these registers;
|
||||
* host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ
|
||||
* to make sure the MAC (uCode processor, etc.) is powered up for accessing
|
||||
* internal resources.
|
||||
*
|
||||
* Do not use iwl_write32()/iwl_read32() family to access these registers;
|
||||
* these provide only simple PCI bus access, without waking up the MAC.
|
||||
*/
|
||||
#define HBUS_BASE (0x400)
|
||||
|
||||
/*
|
||||
* Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
|
||||
* structures, error log, event log, verifying uCode load).
|
||||
* First write to address register, then read from or write to data register
|
||||
* to complete the job. Once the address register is set up, accesses to
|
||||
* data registers auto-increment the address by one dword.
|
||||
* Bit usage for address registers (read or write):
|
||||
* 0-31: memory address within device
|
||||
*/
|
||||
#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
|
||||
#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
|
||||
#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
|
||||
#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
|
||||
|
||||
/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */
|
||||
#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
|
||||
#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
|
||||
|
||||
/*
|
||||
* Registers for accessing device's internal peripheral registers
|
||||
* (e.g. SCD, BSM, etc.). First write to address register,
|
||||
* then read from or write to data register to complete the job.
|
||||
* Bit usage for address registers (read or write):
|
||||
* 0-15: register address (offset) within device
|
||||
* 24-25: (# bytes - 1) to read or write (e.g. 3 for dword)
|
||||
*/
|
||||
#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
|
||||
#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
|
||||
#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
|
||||
#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
|
||||
|
||||
/*
|
||||
* Per-Tx-queue write pointer (index, really!)
|
||||
* Indicates index to next TFD that driver will fill (1 past latest filled).
|
||||
* Bit usage:
|
||||
* 0-7: queue write index
|
||||
* 11-8: queue selector
|
||||
*/
|
||||
#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
|
||||
|
||||
#endif /* !__iwl_legacy_csr_h__ */
|
|
@ -0,0 +1,198 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project.
|
||||
*
|
||||
* 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_legacy_debug_h__
|
||||
#define __iwl_legacy_debug_h__
|
||||
|
||||
struct iwl_priv;
|
||||
extern u32 iwlegacy_debug_level;
|
||||
|
||||
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
|
||||
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
|
||||
#define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
|
||||
#define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
|
||||
|
||||
#define iwl_print_hex_error(priv, p, len) \
|
||||
do { \
|
||||
print_hex_dump(KERN_ERR, "iwl data: ", \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
#define IWL_DEBUG(__priv, level, fmt, args...) \
|
||||
do { \
|
||||
if (iwl_legacy_get_debug_level(__priv) & (level)) \
|
||||
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
|
||||
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
|
||||
__func__ , ## args); \
|
||||
} while (0)
|
||||
|
||||
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
|
||||
do { \
|
||||
if ((iwl_legacy_get_debug_level(__priv) & (level)) && net_ratelimit()) \
|
||||
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
|
||||
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
|
||||
__func__ , ## args); \
|
||||
} while (0)
|
||||
|
||||
#define iwl_print_hex_dump(priv, level, p, len) \
|
||||
do { \
|
||||
if (iwl_legacy_get_debug_level(priv) & level) \
|
||||
print_hex_dump(KERN_DEBUG, "iwl data: ", \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define IWL_DEBUG(__priv, level, fmt, args...)
|
||||
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
|
||||
static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
|
||||
const void *p, u32 len)
|
||||
{}
|
||||
#endif /* CONFIG_IWLWIFI_LEGACY_DEBUG */
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
|
||||
int iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name);
|
||||
void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv);
|
||||
#else
|
||||
static inline int
|
||||
iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_IWLWIFI_LEGACY_DEBUGFS */
|
||||
|
||||
/*
|
||||
* To use the debug system:
|
||||
*
|
||||
* If you are defining a new debug classification, simply add it to the #define
|
||||
* list here in the form of
|
||||
*
|
||||
* #define IWL_DL_xxxx VALUE
|
||||
*
|
||||
* where xxxx should be the name of the classification (for example, WEP).
|
||||
*
|
||||
* You then need to either add a IWL_xxxx_DEBUG() macro definition for your
|
||||
* classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
|
||||
* to send output to that classification.
|
||||
*
|
||||
* The active debug levels can be accessed via files
|
||||
*
|
||||
* /sys/module/iwl4965/parameters/debug{50}
|
||||
* /sys/module/iwl3945/parameters/debug
|
||||
* /sys/class/net/wlan0/device/debug_level
|
||||
*
|
||||
* when CONFIG_IWLWIFI_LEGACY_DEBUG=y.
|
||||
*/
|
||||
|
||||
/* 0x0000000F - 0x00000001 */
|
||||
#define IWL_DL_INFO (1 << 0)
|
||||
#define IWL_DL_MAC80211 (1 << 1)
|
||||
#define IWL_DL_HCMD (1 << 2)
|
||||
#define IWL_DL_STATE (1 << 3)
|
||||
/* 0x000000F0 - 0x00000010 */
|
||||
#define IWL_DL_MACDUMP (1 << 4)
|
||||
#define IWL_DL_HCMD_DUMP (1 << 5)
|
||||
#define IWL_DL_EEPROM (1 << 6)
|
||||
#define IWL_DL_RADIO (1 << 7)
|
||||
/* 0x00000F00 - 0x00000100 */
|
||||
#define IWL_DL_POWER (1 << 8)
|
||||
#define IWL_DL_TEMP (1 << 9)
|
||||
#define IWL_DL_NOTIF (1 << 10)
|
||||
#define IWL_DL_SCAN (1 << 11)
|
||||
/* 0x0000F000 - 0x00001000 */
|
||||
#define IWL_DL_ASSOC (1 << 12)
|
||||
#define IWL_DL_DROP (1 << 13)
|
||||
#define IWL_DL_TXPOWER (1 << 14)
|
||||
#define IWL_DL_AP (1 << 15)
|
||||
/* 0x000F0000 - 0x00010000 */
|
||||
#define IWL_DL_FW (1 << 16)
|
||||
#define IWL_DL_RF_KILL (1 << 17)
|
||||
#define IWL_DL_FW_ERRORS (1 << 18)
|
||||
#define IWL_DL_LED (1 << 19)
|
||||
/* 0x00F00000 - 0x00100000 */
|
||||
#define IWL_DL_RATE (1 << 20)
|
||||
#define IWL_DL_CALIB (1 << 21)
|
||||
#define IWL_DL_WEP (1 << 22)
|
||||
#define IWL_DL_TX (1 << 23)
|
||||
/* 0x0F000000 - 0x01000000 */
|
||||
#define IWL_DL_RX (1 << 24)
|
||||
#define IWL_DL_ISR (1 << 25)
|
||||
#define IWL_DL_HT (1 << 26)
|
||||
#define IWL_DL_IO (1 << 27)
|
||||
/* 0xF0000000 - 0x10000000 */
|
||||
#define IWL_DL_11H (1 << 28)
|
||||
#define IWL_DL_STATS (1 << 29)
|
||||
#define IWL_DL_TX_REPLY (1 << 30)
|
||||
#define IWL_DL_QOS (1 << 31)
|
||||
|
||||
#define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
|
||||
#define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
|
||||
#define IWL_DEBUG_MACDUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_MACDUMP, f, ## a)
|
||||
#define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a)
|
||||
#define IWL_DEBUG_SCAN(p, f, a...) IWL_DEBUG(p, IWL_DL_SCAN, f, ## a)
|
||||
#define IWL_DEBUG_RX(p, f, a...) IWL_DEBUG(p, IWL_DL_RX, f, ## a)
|
||||
#define IWL_DEBUG_TX(p, f, a...) IWL_DEBUG(p, IWL_DL_TX, f, ## a)
|
||||
#define IWL_DEBUG_ISR(p, f, a...) IWL_DEBUG(p, IWL_DL_ISR, f, ## a)
|
||||
#define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a)
|
||||
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
|
||||
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
|
||||
#define IWL_DEBUG_HC_DUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD_DUMP, f, ## a)
|
||||
#define IWL_DEBUG_EEPROM(p, f, a...) IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
|
||||
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
|
||||
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
|
||||
#define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
|
||||
#define IWL_DEBUG_DROP(p, f, a...) IWL_DEBUG(p, IWL_DL_DROP, f, ## a)
|
||||
#define IWL_DEBUG_DROP_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a)
|
||||
#define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a)
|
||||
#define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a)
|
||||
#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a)
|
||||
#define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a)
|
||||
#define IWL_DEBUG_RATE_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a)
|
||||
#define IWL_DEBUG_NOTIF(p, f, a...) IWL_DEBUG(p, IWL_DL_NOTIF, f, ## a)
|
||||
#define IWL_DEBUG_ASSOC(p, f, a...) \
|
||||
IWL_DEBUG(p, IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
|
||||
#define IWL_DEBUG_ASSOC_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
|
||||
#define IWL_DEBUG_HT(p, f, a...) IWL_DEBUG(p, IWL_DL_HT, f, ## a)
|
||||
#define IWL_DEBUG_STATS(p, f, a...) IWL_DEBUG(p, IWL_DL_STATS, f, ## a)
|
||||
#define IWL_DEBUG_STATS_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_STATS, f, ## a)
|
||||
#define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
|
||||
#define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a)
|
||||
#define IWL_DEBUG_QOS(p, f, a...) IWL_DEBUG(p, IWL_DL_QOS, f, ## a)
|
||||
#define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
|
||||
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
|
||||
#define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a)
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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/module.h>
|
||||
|
||||
/* sparse doesn't like tracepoint macros */
|
||||
#ifndef __CHECKER__
|
||||
#include "iwl-dev.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "iwl-devtrace.h"
|
||||
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_iowrite8);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_ioread32);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_iowrite32);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_rx);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_tx);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_ucode_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_ucode_error);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_ucode_cont_event);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_legacy_dev_ucode_wrap_event);
|
||||
#endif
|
|
@ -0,0 +1,270 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#if !defined(__IWLWIFI_LEGACY_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define __IWLWIFI_LEGACY_DEVICE_TRACE
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#if !defined(CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING) || defined(__CHECKER__)
|
||||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#endif
|
||||
|
||||
|
||||
#define PRIV_ENTRY __field(struct iwl_priv *, priv)
|
||||
#define PRIV_ASSIGN (__entry->priv = priv)
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi_legacy_io
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_ioread32,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
||||
TP_ARGS(priv, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(u32, offs)
|
||||
__field(u32, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%p] read io[%#x] = %#x", __entry->priv,
|
||||
__entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_iowrite8,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
|
||||
TP_ARGS(priv, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(u32, offs)
|
||||
__field(u8, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%p] write io[%#x] = %#x)", __entry->priv,
|
||||
__entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_iowrite32,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
||||
TP_ARGS(priv, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(u32, offs)
|
||||
__field(u32, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%p] write io[%#x] = %#x)", __entry->priv,
|
||||
__entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi_legacy_ucode
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_ucode_cont_event,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
|
||||
TP_ARGS(priv, time, data, ev),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(u32, time)
|
||||
__field(u32, data)
|
||||
__field(u32, ev)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->time = time;
|
||||
__entry->data = data;
|
||||
__entry->ev = ev;
|
||||
),
|
||||
TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
|
||||
__entry->priv, __entry->time, __entry->data, __entry->ev)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_ucode_wrap_event,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
|
||||
TP_ARGS(priv, wraps, n_entry, p_entry),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(u32, wraps)
|
||||
__field(u32, n_entry)
|
||||
__field(u32, p_entry)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->wraps = wraps;
|
||||
__entry->n_entry = n_entry;
|
||||
__entry->p_entry = p_entry;
|
||||
),
|
||||
TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
|
||||
__entry->priv, __entry->wraps, __entry->n_entry,
|
||||
__entry->p_entry)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_hcmd,
|
||||
TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
|
||||
TP_ARGS(priv, hcmd, len, flags),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__dynamic_array(u8, hcmd, len)
|
||||
__field(u32, flags)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
memcpy(__get_dynamic_array(hcmd), hcmd, len);
|
||||
__entry->flags = flags;
|
||||
),
|
||||
TP_printk("[%p] hcmd %#.2x (%ssync)",
|
||||
__entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
|
||||
__entry->flags & CMD_ASYNC ? "a" : "")
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_rx,
|
||||
TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
|
||||
TP_ARGS(priv, rxbuf, len),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__dynamic_array(u8, rxbuf, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
memcpy(__get_dynamic_array(rxbuf), rxbuf, len);
|
||||
),
|
||||
TP_printk("[%p] RX cmd %#.2x",
|
||||
__entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4])
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_tx,
|
||||
TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
|
||||
void *buf0, size_t buf0_len,
|
||||
void *buf1, size_t buf1_len),
|
||||
TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(size_t, framelen)
|
||||
__dynamic_array(u8, tfd, tfdlen)
|
||||
|
||||
/*
|
||||
* Do not insert between or below these items,
|
||||
* we want to keep the frame together (except
|
||||
* for the possible padding).
|
||||
*/
|
||||
__dynamic_array(u8, buf0, buf0_len)
|
||||
__dynamic_array(u8, buf1, buf1_len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->framelen = buf0_len + buf1_len;
|
||||
memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
|
||||
memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
|
||||
memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
|
||||
),
|
||||
TP_printk("[%p] TX %.2x (%zu bytes)",
|
||||
__entry->priv,
|
||||
((u8 *)__get_dynamic_array(buf0))[0],
|
||||
__entry->framelen)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_ucode_error,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
|
||||
u32 data1, u32 data2, u32 line, u32 blink1,
|
||||
u32 blink2, u32 ilink1, u32 ilink2),
|
||||
TP_ARGS(priv, desc, time, data1, data2, line,
|
||||
blink1, blink2, ilink1, ilink2),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(u32, desc)
|
||||
__field(u32, time)
|
||||
__field(u32, data1)
|
||||
__field(u32, data2)
|
||||
__field(u32, line)
|
||||
__field(u32, blink1)
|
||||
__field(u32, blink2)
|
||||
__field(u32, ilink1)
|
||||
__field(u32, ilink2)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->desc = desc;
|
||||
__entry->time = time;
|
||||
__entry->data1 = data1;
|
||||
__entry->data2 = data2;
|
||||
__entry->line = line;
|
||||
__entry->blink1 = blink1;
|
||||
__entry->blink2 = blink2;
|
||||
__entry->ilink1 = ilink1;
|
||||
__entry->ilink2 = ilink2;
|
||||
),
|
||||
TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
|
||||
"blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
|
||||
__entry->priv, __entry->desc, __entry->time, __entry->data1,
|
||||
__entry->data2, __entry->line, __entry->blink1,
|
||||
__entry->blink2, __entry->ilink1, __entry->ilink2)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_legacy_dev_ucode_event,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
|
||||
TP_ARGS(priv, time, data, ev),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
|
||||
__field(u32, time)
|
||||
__field(u32, data)
|
||||
__field(u32, ev)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->time = time;
|
||||
__entry->data = data;
|
||||
__entry->ev = ev;
|
||||
),
|
||||
TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
|
||||
__entry->priv, __entry->time, __entry->data, __entry->ev)
|
||||
);
|
||||
#endif /* __IWLWIFI_DEVICE_TRACE */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE iwl-devtrace
|
||||
#include <trace/define_trace.h>
|
|
@ -0,0 +1,561 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-commands.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-io.h"
|
||||
|
||||
/************************** EEPROM BANDS ****************************
|
||||
*
|
||||
* The iwlegacy_eeprom_band definitions below provide the mapping from the
|
||||
* EEPROM contents to the specific channel number supported for each
|
||||
* band.
|
||||
*
|
||||
* For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
|
||||
* definition below maps to physical channel 42 in the 5.2GHz spectrum.
|
||||
* The specific geography and calibration information for that channel
|
||||
* is contained in the eeprom map itself.
|
||||
*
|
||||
* During init, we copy the eeprom information and channel map
|
||||
* information into priv->channel_info_24/52 and priv->channel_map_24/52
|
||||
*
|
||||
* channel_map_24/52 provides the index in the channel_info array for a
|
||||
* given channel. We have to have two separate maps as there is channel
|
||||
* overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
|
||||
* band_2
|
||||
*
|
||||
* A value of 0xff stored in the channel_map indicates that the channel
|
||||
* is not supported by the hardware at all.
|
||||
*
|
||||
* A value of 0xfe in the channel_map indicates that the channel is not
|
||||
* valid for Tx with the current hardware. This means that
|
||||
* while the system can tune and receive on a given channel, it may not
|
||||
* be able to associate or transmit any frames on that
|
||||
* channel. There is no corresponding channel information for that
|
||||
* entry.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* 2.4 GHz */
|
||||
const u8 iwlegacy_eeprom_band_1[14] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
};
|
||||
|
||||
/* 5.2 GHz bands */
|
||||
static const u8 iwlegacy_eeprom_band_2[] = { /* 4915-5080MHz */
|
||||
183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
|
||||
};
|
||||
|
||||
static const u8 iwlegacy_eeprom_band_3[] = { /* 5170-5320MHz */
|
||||
34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
|
||||
};
|
||||
|
||||
static const u8 iwlegacy_eeprom_band_4[] = { /* 5500-5700MHz */
|
||||
100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
|
||||
};
|
||||
|
||||
static const u8 iwlegacy_eeprom_band_5[] = { /* 5725-5825MHz */
|
||||
145, 149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u8 iwlegacy_eeprom_band_6[] = { /* 2.4 ht40 channel */
|
||||
1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
static const u8 iwlegacy_eeprom_band_7[] = { /* 5.2 ht40 channel */
|
||||
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* EEPROM related functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static int iwl_legacy_eeprom_verify_signature(struct iwl_priv *priv)
|
||||
{
|
||||
u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
|
||||
int ret = 0;
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
|
||||
switch (gp) {
|
||||
case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
|
||||
case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(priv, "bad EEPROM signature,"
|
||||
"EEPROM_GP=0x%08x\n", gp);
|
||||
ret = -ENOENT;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const u8
|
||||
*iwl_legacy_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
|
||||
{
|
||||
BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
|
||||
return &priv->eeprom[offset];
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_eeprom_query_addr);
|
||||
|
||||
u16 iwl_legacy_eeprom_query16(const struct iwl_priv *priv, size_t offset)
|
||||
{
|
||||
if (!priv->eeprom)
|
||||
return 0;
|
||||
return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_eeprom_query16);
|
||||
|
||||
/**
|
||||
* iwl_legacy_eeprom_init - read EEPROM contents
|
||||
*
|
||||
* Load the EEPROM contents from adapter into priv->eeprom
|
||||
*
|
||||
* NOTE: This routine uses the non-debug IO access functions.
|
||||
*/
|
||||
int iwl_legacy_eeprom_init(struct iwl_priv *priv)
|
||||
{
|
||||
__le16 *e;
|
||||
u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
|
||||
int sz;
|
||||
int ret;
|
||||
u16 addr;
|
||||
|
||||
/* allocate eeprom */
|
||||
sz = priv->cfg->base_params->eeprom_size;
|
||||
IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
|
||||
priv->eeprom = kzalloc(sz, GFP_KERNEL);
|
||||
if (!priv->eeprom) {
|
||||
ret = -ENOMEM;
|
||||
goto alloc_err;
|
||||
}
|
||||
e = (__le16 *)priv->eeprom;
|
||||
|
||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
||||
|
||||
ret = iwl_legacy_eeprom_verify_signature(priv);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
|
||||
ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* eeprom is an array of 16bit values */
|
||||
for (addr = 0; addr < sz; addr += sizeof(u16)) {
|
||||
u32 r;
|
||||
|
||||
_iwl_legacy_write32(priv, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
|
||||
|
||||
ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
CSR_EEPROM_REG_READ_VALID_MSK,
|
||||
IWL_EEPROM_ACCESS_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(priv, "Time out reading EEPROM[%d]\n",
|
||||
addr);
|
||||
goto done;
|
||||
}
|
||||
r = _iwl_legacy_read_direct32(priv, CSR_EEPROM_REG);
|
||||
e[addr / 2] = cpu_to_le16(r >> 16);
|
||||
}
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
|
||||
"EEPROM",
|
||||
iwl_legacy_eeprom_query16(priv, EEPROM_VERSION));
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
|
||||
|
||||
err:
|
||||
if (ret)
|
||||
iwl_legacy_eeprom_free(priv);
|
||||
/* Reset chip to save power until we load uCode during "up". */
|
||||
iwl_legacy_apm_stop(priv);
|
||||
alloc_err:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_eeprom_init);
|
||||
|
||||
void iwl_legacy_eeprom_free(struct iwl_priv *priv)
|
||||
{
|
||||
kfree(priv->eeprom);
|
||||
priv->eeprom = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_eeprom_free);
|
||||
|
||||
static void iwl_legacy_init_band_reference(const struct iwl_priv *priv,
|
||||
int eep_band, int *eeprom_ch_count,
|
||||
const struct iwl_eeprom_channel **eeprom_ch_info,
|
||||
const u8 **eeprom_ch_index)
|
||||
{
|
||||
u32 offset = priv->cfg->ops->lib->
|
||||
eeprom_ops.regulatory_bands[eep_band - 1];
|
||||
switch (eep_band) {
|
||||
case 1: /* 2.4GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_1);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_1;
|
||||
break;
|
||||
case 2: /* 4.9GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_2);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_2;
|
||||
break;
|
||||
case 3: /* 5.2GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_3);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_3;
|
||||
break;
|
||||
case 4: /* 5.5GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_4);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_4;
|
||||
break;
|
||||
case 5: /* 5.7GHz band */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_5);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_5;
|
||||
break;
|
||||
case 6: /* 2.4GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_6);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_6;
|
||||
break;
|
||||
case 7: /* 5 GHz ht40 channels */
|
||||
*eeprom_ch_count = ARRAY_SIZE(iwlegacy_eeprom_band_7);
|
||||
*eeprom_ch_info = (struct iwl_eeprom_channel *)
|
||||
iwl_legacy_eeprom_query_addr(priv, offset);
|
||||
*eeprom_ch_index = iwlegacy_eeprom_band_7;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
|
||||
? # x " " : "")
|
||||
/**
|
||||
* iwl_legacy_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
|
||||
*
|
||||
* Does not set up a command, or touch hardware.
|
||||
*/
|
||||
static int iwl_legacy_mod_ht40_chan_info(struct iwl_priv *priv,
|
||||
enum ieee80211_band band, u16 channel,
|
||||
const struct iwl_eeprom_channel *eeprom_ch,
|
||||
u8 clear_ht40_extension_channel)
|
||||
{
|
||||
struct iwl_channel_info *ch_info;
|
||||
|
||||
ch_info = (struct iwl_channel_info *)
|
||||
iwl_legacy_get_channel_info(priv, band, channel);
|
||||
|
||||
if (!iwl_legacy_is_channel_valid(ch_info))
|
||||
return -1;
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
|
||||
" Ad-Hoc %ssupported\n",
|
||||
ch_info->channel,
|
||||
iwl_legacy_is_channel_a_band(ch_info) ?
|
||||
"5.2" : "2.4",
|
||||
CHECK_AND_PRINT(IBSS),
|
||||
CHECK_AND_PRINT(ACTIVE),
|
||||
CHECK_AND_PRINT(RADAR),
|
||||
CHECK_AND_PRINT(WIDE),
|
||||
CHECK_AND_PRINT(DFS),
|
||||
eeprom_ch->flags,
|
||||
eeprom_ch->max_power_avg,
|
||||
((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
|
||||
&& !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
|
||||
"" : "not ");
|
||||
|
||||
ch_info->ht40_eeprom = *eeprom_ch;
|
||||
ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_flags = eeprom_ch->flags;
|
||||
if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
|
||||
ch_info->ht40_extension_channel &=
|
||||
~clear_ht40_extension_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
|
||||
? # x " " : "")
|
||||
|
||||
/**
|
||||
* iwl_legacy_init_channel_map - Set up driver's info for all possible channels
|
||||
*/
|
||||
int iwl_legacy_init_channel_map(struct iwl_priv *priv)
|
||||
{
|
||||
int eeprom_ch_count = 0;
|
||||
const u8 *eeprom_ch_index = NULL;
|
||||
const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
|
||||
int band, ch;
|
||||
struct iwl_channel_info *ch_info;
|
||||
|
||||
if (priv->channel_count) {
|
||||
IWL_DEBUG_EEPROM(priv, "Channel map already initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "Initializing regulatory info from EEPROM\n");
|
||||
|
||||
priv->channel_count =
|
||||
ARRAY_SIZE(iwlegacy_eeprom_band_1) +
|
||||
ARRAY_SIZE(iwlegacy_eeprom_band_2) +
|
||||
ARRAY_SIZE(iwlegacy_eeprom_band_3) +
|
||||
ARRAY_SIZE(iwlegacy_eeprom_band_4) +
|
||||
ARRAY_SIZE(iwlegacy_eeprom_band_5);
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
|
||||
priv->channel_count);
|
||||
|
||||
priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
|
||||
priv->channel_count, GFP_KERNEL);
|
||||
if (!priv->channel_info) {
|
||||
IWL_ERR(priv, "Could not allocate channel_info\n");
|
||||
priv->channel_count = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ch_info = priv->channel_info;
|
||||
|
||||
/* Loop through the 5 EEPROM bands adding them in order to the
|
||||
* channel map we maintain (that contains additional information than
|
||||
* what just in the EEPROM) */
|
||||
for (band = 1; band <= 5; band++) {
|
||||
|
||||
iwl_legacy_init_band_reference(priv, band, &eeprom_ch_count,
|
||||
&eeprom_ch_info, &eeprom_ch_index);
|
||||
|
||||
/* Loop through each band adding each of the channels */
|
||||
for (ch = 0; ch < eeprom_ch_count; ch++) {
|
||||
ch_info->channel = eeprom_ch_index[ch];
|
||||
ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ :
|
||||
IEEE80211_BAND_5GHZ;
|
||||
|
||||
/* permanently store EEPROM's channel regulatory flags
|
||||
* and max power in channel info database. */
|
||||
ch_info->eeprom = eeprom_ch_info[ch];
|
||||
|
||||
/* Copy the run-time flags so they are there even on
|
||||
* invalid channels */
|
||||
ch_info->flags = eeprom_ch_info[ch].flags;
|
||||
/* First write that ht40 is not enabled, and then enable
|
||||
* one by one */
|
||||
ch_info->ht40_extension_channel =
|
||||
IEEE80211_CHAN_NO_HT40;
|
||||
|
||||
if (!(iwl_legacy_is_channel_valid(ch_info))) {
|
||||
IWL_DEBUG_EEPROM(priv,
|
||||
"Ch. %d Flags %x [%sGHz] - "
|
||||
"No traffic\n",
|
||||
ch_info->channel,
|
||||
ch_info->flags,
|
||||
iwl_legacy_is_channel_a_band(ch_info) ?
|
||||
"5.2" : "2.4");
|
||||
ch_info++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Initialize regulatory-based run-time data */
|
||||
ch_info->max_power_avg = ch_info->curr_txpow =
|
||||
eeprom_ch_info[ch].max_power_avg;
|
||||
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
|
||||
ch_info->min_power = 0;
|
||||
|
||||
IWL_DEBUG_EEPROM(priv, "Ch. %d [%sGHz] "
|
||||
"%s%s%s%s%s%s(0x%02x %ddBm):"
|
||||
" Ad-Hoc %ssupported\n",
|
||||
ch_info->channel,
|
||||
iwl_legacy_is_channel_a_band(ch_info) ?
|
||||
"5.2" : "2.4",
|
||||
CHECK_AND_PRINT_I(VALID),
|
||||
CHECK_AND_PRINT_I(IBSS),
|
||||
CHECK_AND_PRINT_I(ACTIVE),
|
||||
CHECK_AND_PRINT_I(RADAR),
|
||||
CHECK_AND_PRINT_I(WIDE),
|
||||
CHECK_AND_PRINT_I(DFS),
|
||||
eeprom_ch_info[ch].flags,
|
||||
eeprom_ch_info[ch].max_power_avg,
|
||||
((eeprom_ch_info[ch].
|
||||
flags & EEPROM_CHANNEL_IBSS)
|
||||
&& !(eeprom_ch_info[ch].
|
||||
flags & EEPROM_CHANNEL_RADAR))
|
||||
? "" : "not ");
|
||||
|
||||
/* Set the tx_power_user_lmt to the highest power
|
||||
* supported by any channel */
|
||||
if (eeprom_ch_info[ch].max_power_avg >
|
||||
priv->tx_power_user_lmt)
|
||||
priv->tx_power_user_lmt =
|
||||
eeprom_ch_info[ch].max_power_avg;
|
||||
|
||||
ch_info++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we do have HT40 channels */
|
||||
if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] ==
|
||||
EEPROM_REGULATORY_BAND_NO_HT40 &&
|
||||
priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] ==
|
||||
EEPROM_REGULATORY_BAND_NO_HT40)
|
||||
return 0;
|
||||
|
||||
/* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
|
||||
for (band = 6; band <= 7; band++) {
|
||||
enum ieee80211_band ieeeband;
|
||||
|
||||
iwl_legacy_init_band_reference(priv, band, &eeprom_ch_count,
|
||||
&eeprom_ch_info, &eeprom_ch_index);
|
||||
|
||||
/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
|
||||
ieeeband =
|
||||
(band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
|
||||
/* Loop through each band adding each of the channels */
|
||||
for (ch = 0; ch < eeprom_ch_count; ch++) {
|
||||
/* Set up driver's info for lower half */
|
||||
iwl_legacy_mod_ht40_chan_info(priv, ieeeband,
|
||||
eeprom_ch_index[ch],
|
||||
&eeprom_ch_info[ch],
|
||||
IEEE80211_CHAN_NO_HT40PLUS);
|
||||
|
||||
/* Set up driver's info for upper half */
|
||||
iwl_legacy_mod_ht40_chan_info(priv, ieeeband,
|
||||
eeprom_ch_index[ch] + 4,
|
||||
&eeprom_ch_info[ch],
|
||||
IEEE80211_CHAN_NO_HT40MINUS);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_init_channel_map);
|
||||
|
||||
/*
|
||||
* iwl_legacy_free_channel_map - undo allocations in iwl_legacy_init_channel_map
|
||||
*/
|
||||
void iwl_legacy_free_channel_map(struct iwl_priv *priv)
|
||||
{
|
||||
kfree(priv->channel_info);
|
||||
priv->channel_count = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_free_channel_map);
|
||||
|
||||
/**
|
||||
* iwl_legacy_get_channel_info - Find driver's private channel info
|
||||
*
|
||||
* Based on band and channel number.
|
||||
*/
|
||||
const struct
|
||||
iwl_channel_info *iwl_legacy_get_channel_info(const struct iwl_priv *priv,
|
||||
enum ieee80211_band band, u16 channel)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
for (i = 14; i < priv->channel_count; i++) {
|
||||
if (priv->channel_info[i].channel == channel)
|
||||
return &priv->channel_info[i];
|
||||
}
|
||||
break;
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (channel >= 1 && channel <= 14)
|
||||
return &priv->channel_info[channel - 1];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_get_channel_info);
|
|
@ -0,0 +1,344 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_legacy_eeprom_h__
|
||||
#define __iwl_legacy_eeprom_h__
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
struct iwl_priv;
|
||||
|
||||
/*
|
||||
* EEPROM access time values:
|
||||
*
|
||||
* Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
|
||||
* Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
|
||||
* When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
|
||||
* Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
|
||||
*/
|
||||
#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
|
||||
|
||||
#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */
|
||||
#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
|
||||
|
||||
|
||||
/*
|
||||
* Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
|
||||
*
|
||||
* IBSS and/or AP operation is allowed *only* on those channels with
|
||||
* (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because
|
||||
* RADAR detection is not supported by the 4965 driver, but is a
|
||||
* requirement for establishing a new network for legal operation on channels
|
||||
* requiring RADAR detection or restricting ACTIVE scanning.
|
||||
*
|
||||
* NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
|
||||
* It only indicates that 20 MHz channel use is supported; HT40 channel
|
||||
* usage is indicated by a separate set of regulatory flags for each
|
||||
* HT40 channel pair.
|
||||
*
|
||||
* NOTE: Using a channel inappropriately will result in a uCode error!
|
||||
*/
|
||||
#define IWL_NUM_TX_CALIB_GROUPS 5
|
||||
enum {
|
||||
EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
|
||||
EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
|
||||
/* Bit 2 Reserved */
|
||||
EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
|
||||
EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
|
||||
EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */
|
||||
/* Bit 6 Reserved (was Narrow Channel) */
|
||||
EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
|
||||
};
|
||||
|
||||
/* SKU Capabilities */
|
||||
/* 3945 only */
|
||||
#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
|
||||
#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
|
||||
|
||||
/* *regulatory* channel data format in eeprom, one for each channel.
|
||||
* There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
|
||||
struct iwl_eeprom_channel {
|
||||
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
|
||||
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
|
||||
} __packed;
|
||||
|
||||
/* 3945 Specific */
|
||||
#define EEPROM_3945_EEPROM_VERSION (0x2f)
|
||||
|
||||
/* 4965 has two radio transmitters (and 3 radio receivers) */
|
||||
#define EEPROM_TX_POWER_TX_CHAINS (2)
|
||||
|
||||
/* 4965 has room for up to 8 sets of txpower calibration data */
|
||||
#define EEPROM_TX_POWER_BANDS (8)
|
||||
|
||||
/* 4965 factory calibration measures txpower gain settings for
|
||||
* each of 3 target output levels */
|
||||
#define EEPROM_TX_POWER_MEASUREMENTS (3)
|
||||
|
||||
/* 4965 Specific */
|
||||
/* 4965 driver does not work with txpower calibration version < 5 */
|
||||
#define EEPROM_4965_TX_POWER_VERSION (5)
|
||||
#define EEPROM_4965_EEPROM_VERSION (0x2f)
|
||||
#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
|
||||
#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
|
||||
#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
|
||||
#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
|
||||
|
||||
/* 2.4 GHz */
|
||||
extern const u8 iwlegacy_eeprom_band_1[14];
|
||||
|
||||
/*
|
||||
* factory calibration data for one txpower level, on one channel,
|
||||
* measured on one of the 2 tx chains (radio transmitter and associated
|
||||
* antenna). EEPROM contains:
|
||||
*
|
||||
* 1) Temperature (degrees Celsius) of device when measurement was made.
|
||||
*
|
||||
* 2) Gain table index used to achieve the target measurement power.
|
||||
* This refers to the "well-known" gain tables (see iwl-4965-hw.h).
|
||||
*
|
||||
* 3) Actual measured output power, in half-dBm ("34" = 17 dBm).
|
||||
*
|
||||
* 4) RF power amplifier detector level measurement (not used).
|
||||
*/
|
||||
struct iwl_eeprom_calib_measure {
|
||||
u8 temperature; /* Device temperature (Celsius) */
|
||||
u8 gain_idx; /* Index into gain table */
|
||||
u8 actual_pow; /* Measured RF output power, half-dBm */
|
||||
s8 pa_det; /* Power amp detector level (not used) */
|
||||
} __packed;
|
||||
|
||||
|
||||
/*
|
||||
* measurement set for one channel. EEPROM contains:
|
||||
*
|
||||
* 1) Channel number measured
|
||||
*
|
||||
* 2) Measurements for each of 3 power levels for each of 2 radio transmitters
|
||||
* (a.k.a. "tx chains") (6 measurements altogether)
|
||||
*/
|
||||
struct iwl_eeprom_calib_ch_info {
|
||||
u8 ch_num;
|
||||
struct iwl_eeprom_calib_measure
|
||||
measurements[EEPROM_TX_POWER_TX_CHAINS]
|
||||
[EEPROM_TX_POWER_MEASUREMENTS];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* txpower subband info.
|
||||
*
|
||||
* For each frequency subband, EEPROM contains the following:
|
||||
*
|
||||
* 1) First and last channels within range of the subband. "0" values
|
||||
* indicate that this sample set is not being used.
|
||||
*
|
||||
* 2) Sample measurement sets for 2 channels close to the range endpoints.
|
||||
*/
|
||||
struct iwl_eeprom_calib_subband_info {
|
||||
u8 ch_from; /* channel number of lowest channel in subband */
|
||||
u8 ch_to; /* channel number of highest channel in subband */
|
||||
struct iwl_eeprom_calib_ch_info ch1;
|
||||
struct iwl_eeprom_calib_ch_info ch2;
|
||||
} __packed;
|
||||
|
||||
|
||||
/*
|
||||
* txpower calibration info. EEPROM contains:
|
||||
*
|
||||
* 1) Factory-measured saturation power levels (maximum levels at which
|
||||
* tx power amplifier can output a signal without too much distortion).
|
||||
* There is one level for 2.4 GHz band and one for 5 GHz band. These
|
||||
* values apply to all channels within each of the bands.
|
||||
*
|
||||
* 2) Factory-measured power supply voltage level. This is assumed to be
|
||||
* constant (i.e. same value applies to all channels/bands) while the
|
||||
* factory measurements are being made.
|
||||
*
|
||||
* 3) Up to 8 sets of factory-measured txpower calibration values.
|
||||
* These are for different frequency ranges, since txpower gain
|
||||
* characteristics of the analog radio circuitry vary with frequency.
|
||||
*
|
||||
* Not all sets need to be filled with data;
|
||||
* struct iwl_eeprom_calib_subband_info contains range of channels
|
||||
* (0 if unused) for each set of data.
|
||||
*/
|
||||
struct iwl_eeprom_calib_info {
|
||||
u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */
|
||||
u8 saturation_power52; /* half-dBm */
|
||||
__le16 voltage; /* signed */
|
||||
struct iwl_eeprom_calib_subband_info
|
||||
band_info[EEPROM_TX_POWER_BANDS];
|
||||
} __packed;
|
||||
|
||||
|
||||
/* General */
|
||||
#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
|
||||
#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
|
||||
#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
|
||||
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
|
||||
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
|
||||
#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */
|
||||
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
|
||||
#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
|
||||
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
|
||||
#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */
|
||||
|
||||
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
|
||||
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
|
||||
#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
|
||||
#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
|
||||
#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
|
||||
#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
|
||||
#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
|
||||
|
||||
#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0
|
||||
#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1
|
||||
|
||||
/*
|
||||
* Per-channel regulatory data.
|
||||
*
|
||||
* Each channel that *might* be supported by iwl has a fixed location
|
||||
* in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
|
||||
* txpower (MSB).
|
||||
*
|
||||
* Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
|
||||
* channels (only for 4965, not supported by 3945) appear later in the EEPROM.
|
||||
*
|
||||
* 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
|
||||
*/
|
||||
#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
|
||||
|
||||
/*
|
||||
* 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
|
||||
* 5.0 GHz channels 7, 8, 11, 12, 16
|
||||
* (4915-5080MHz) (none of these is ever supported)
|
||||
*/
|
||||
#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
|
||||
|
||||
/*
|
||||
* 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
|
||||
* (5170-5320MHz)
|
||||
*/
|
||||
#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
|
||||
|
||||
/*
|
||||
* 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
|
||||
* (5500-5700MHz)
|
||||
*/
|
||||
#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
|
||||
|
||||
/*
|
||||
* 5.7 GHz channels 145, 149, 153, 157, 161, 165
|
||||
* (5725-5825MHz)
|
||||
*/
|
||||
#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
|
||||
#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
|
||||
|
||||
/*
|
||||
* 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
|
||||
*
|
||||
* The channel listed is the center of the lower 20 MHz half of the channel.
|
||||
* The overall center frequency is actually 2 channels (10 MHz) above that,
|
||||
* and the upper half of each HT40 channel is centered 4 channels (20 MHz) away
|
||||
* from the lower half; e.g. the upper half of HT40 channel 1 is channel 5,
|
||||
* and the overall HT40 channel width centers on channel 3.
|
||||
*
|
||||
* NOTE: The RXON command uses 20 MHz channel numbers to specify the
|
||||
* control channel to which to tune. RXON also specifies whether the
|
||||
* control channel is the upper or lower half of a HT40 channel.
|
||||
*
|
||||
* NOTE: 4965 does not support HT40 channels on 2.4 GHz.
|
||||
*/
|
||||
#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */
|
||||
|
||||
/*
|
||||
* 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64),
|
||||
* 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
|
||||
*/
|
||||
#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */
|
||||
|
||||
#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
|
||||
|
||||
struct iwl_eeprom_ops {
|
||||
const u32 regulatory_bands[7];
|
||||
int (*acquire_semaphore) (struct iwl_priv *priv);
|
||||
void (*release_semaphore) (struct iwl_priv *priv);
|
||||
};
|
||||
|
||||
|
||||
int iwl_legacy_eeprom_init(struct iwl_priv *priv);
|
||||
void iwl_legacy_eeprom_free(struct iwl_priv *priv);
|
||||
const u8 *iwl_legacy_eeprom_query_addr(const struct iwl_priv *priv,
|
||||
size_t offset);
|
||||
u16 iwl_legacy_eeprom_query16(const struct iwl_priv *priv, size_t offset);
|
||||
int iwl_legacy_init_channel_map(struct iwl_priv *priv);
|
||||
void iwl_legacy_free_channel_map(struct iwl_priv *priv);
|
||||
const struct iwl_channel_info *iwl_legacy_get_channel_info(
|
||||
const struct iwl_priv *priv,
|
||||
enum ieee80211_band band, u16 channel);
|
||||
|
||||
#endif /* __iwl_legacy_eeprom_h__ */
|
|
@ -0,0 +1,513 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_legacy_fh_h__
|
||||
#define __iwl_legacy_fh_h__
|
||||
|
||||
/****************************/
|
||||
/* Flow Handler Definitions */
|
||||
/****************************/
|
||||
|
||||
/**
|
||||
* This I/O area is directly read/writable by driver (e.g. Linux uses writel())
|
||||
* Addresses are offsets from device's PCI hardware base address.
|
||||
*/
|
||||
#define FH_MEM_LOWER_BOUND (0x1000)
|
||||
#define FH_MEM_UPPER_BOUND (0x2000)
|
||||
|
||||
/**
|
||||
* Keep-Warm (KW) buffer base address.
|
||||
*
|
||||
* Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
|
||||
* host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
|
||||
* DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host
|
||||
* from going into a power-savings mode that would cause higher DRAM latency,
|
||||
* and possible data over/under-runs, before all Tx/Rx is complete.
|
||||
*
|
||||
* Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
|
||||
* of the buffer, which must be 4K aligned. Once this is set up, the 4965
|
||||
* automatically invokes keep-warm accesses when normal accesses might not
|
||||
* be sufficient to maintain fast DRAM response.
|
||||
*
|
||||
* Bit fields:
|
||||
* 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned
|
||||
*/
|
||||
#define FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C)
|
||||
|
||||
|
||||
/**
|
||||
* TFD Circular Buffers Base (CBBC) addresses
|
||||
*
|
||||
* 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
|
||||
* circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
|
||||
* (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04
|
||||
* bytes from one another. Each TFD circular buffer in DRAM must be 256-byte
|
||||
* aligned (address bits 0-7 must be 0).
|
||||
*
|
||||
* Bit fields in each pointer register:
|
||||
* 27-0: TFD CB physical base address [35:8], must be 256-byte aligned
|
||||
*/
|
||||
#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
|
||||
#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10)
|
||||
|
||||
/* Find TFD CB base pointer for given queue (range 0-15). */
|
||||
#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
|
||||
|
||||
|
||||
/**
|
||||
* Rx SRAM Control and Status Registers (RSCSR)
|
||||
*
|
||||
* These registers provide handshake between driver and 4965 for the Rx queue
|
||||
* (this queue handles *all* command responses, notifications, Rx data, etc.
|
||||
* sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx
|
||||
* queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can
|
||||
* concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
|
||||
* Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
|
||||
* mapping between RBDs and RBs.
|
||||
*
|
||||
* Driver must allocate host DRAM memory for the following, and set the
|
||||
* physical address of each into 4965 registers:
|
||||
*
|
||||
* 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
|
||||
* entries (although any power of 2, up to 4096, is selectable by driver).
|
||||
* Each entry (1 dword) points to a receive buffer (RB) of consistent size
|
||||
* (typically 4K, although 8K or 16K are also selectable by driver).
|
||||
* Driver sets up RB size and number of RBDs in the CB via Rx config
|
||||
* register FH_MEM_RCSR_CHNL0_CONFIG_REG.
|
||||
*
|
||||
* Bit fields within one RBD:
|
||||
* 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned
|
||||
*
|
||||
* Driver sets physical address [35:8] of base of RBD circular buffer
|
||||
* into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
|
||||
*
|
||||
* 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
|
||||
* (RBs) have been filled, via a "write pointer", actually the index of
|
||||
* the RB's corresponding RBD within the circular buffer. Driver sets
|
||||
* physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
|
||||
*
|
||||
* Bit fields in lower dword of Rx status buffer (upper dword not used
|
||||
* by driver; see struct iwl4965_shared, val0):
|
||||
* 31-12: Not used by driver
|
||||
* 11- 0: Index of last filled Rx buffer descriptor
|
||||
* (4965 writes, driver reads this value)
|
||||
*
|
||||
* As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
|
||||
* enter pointers to these RBs into contiguous RBD circular buffer entries,
|
||||
* and update the 4965's "write" index register,
|
||||
* FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
|
||||
*
|
||||
* This "write" index corresponds to the *next* RBD that the driver will make
|
||||
* available, i.e. one RBD past the tail of the ready-to-fill RBDs within
|
||||
* the circular buffer. This value should initially be 0 (before preparing any
|
||||
* RBs), should be 8 after preparing the first 8 RBs (for example), and must
|
||||
* wrap back to 0 at the end of the circular buffer (but don't wrap before
|
||||
* "read" index has advanced past 1! See below).
|
||||
* NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
|
||||
*
|
||||
* As the 4965 fills RBs (referenced from contiguous RBDs within the circular
|
||||
* buffer), it updates the Rx status buffer in host DRAM, 2) described above,
|
||||
* to tell the driver the index of the latest filled RBD. The driver must
|
||||
* read this "read" index from DRAM after receiving an Rx interrupt from 4965.
|
||||
*
|
||||
* The driver must also internally keep track of a third index, which is the
|
||||
* next RBD to process. When receiving an Rx interrupt, driver should process
|
||||
* all filled but unprocessed RBs up to, but not including, the RB
|
||||
* corresponding to the "read" index. For example, if "read" index becomes "1",
|
||||
* driver may process the RB pointed to by RBD 0. Depending on volume of
|
||||
* traffic, there may be many RBs to process.
|
||||
*
|
||||
* If read index == write index, 4965 thinks there is no room to put new data.
|
||||
* Due to this, the maximum number of filled RBs is 255, instead of 256. To
|
||||
* be safe, make sure that there is a gap of at least 2 RBDs between "write"
|
||||
* and "read" indexes; that is, make sure that there are no more than 254
|
||||
* buffers waiting to be filled.
|
||||
*/
|
||||
#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0)
|
||||
#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
|
||||
#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND)
|
||||
|
||||
/**
|
||||
* Physical base address of 8-byte Rx Status buffer.
|
||||
* Bit fields:
|
||||
* 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned.
|
||||
*/
|
||||
#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0)
|
||||
|
||||
/**
|
||||
* Physical base address of Rx Buffer Descriptor Circular Buffer.
|
||||
* Bit fields:
|
||||
* 27-0: RBD CD physical base address [35:8], must be 256-byte aligned.
|
||||
*/
|
||||
#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004)
|
||||
|
||||
/**
|
||||
* Rx write pointer (index, really!).
|
||||
* Bit fields:
|
||||
* 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1.
|
||||
* NOTE: For 256-entry circular buffer, use only bits [7:0].
|
||||
*/
|
||||
#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008)
|
||||
#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
|
||||
|
||||
|
||||
/**
|
||||
* Rx Config/Status Registers (RCSR)
|
||||
* Rx Config Reg for channel 0 (only channel used)
|
||||
*
|
||||
* Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for
|
||||
* normal operation (see bit fields).
|
||||
*
|
||||
* Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA.
|
||||
* Driver should poll FH_MEM_RSSR_RX_STATUS_REG for
|
||||
* FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing.
|
||||
*
|
||||
* Bit fields:
|
||||
* 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame,
|
||||
* '10' operate normally
|
||||
* 29-24: reserved
|
||||
* 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal),
|
||||
* min "5" for 32 RBDs, max "12" for 4096 RBDs.
|
||||
* 19-18: reserved
|
||||
* 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K,
|
||||
* '10' 12K, '11' 16K.
|
||||
* 15-14: reserved
|
||||
* 13-12: IRQ destination; '00' none, '01' host driver (normal operation)
|
||||
* 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec)
|
||||
* typical value 0x10 (about 1/2 msec)
|
||||
* 3- 0: reserved
|
||||
*/
|
||||
#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
|
||||
#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0)
|
||||
#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND)
|
||||
|
||||
#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0)
|
||||
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK (0x00030000) /* bits 16-17 */
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/
|
||||
|
||||
#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20)
|
||||
#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4)
|
||||
#define RX_RB_TIMEOUT (0x10)
|
||||
|
||||
#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000)
|
||||
#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000)
|
||||
#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000)
|
||||
|
||||
#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000)
|
||||
#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000)
|
||||
#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000)
|
||||
#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000)
|
||||
|
||||
#define FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY (0x00000004)
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000)
|
||||
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000)
|
||||
|
||||
#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
|
||||
|
||||
/**
|
||||
* Rx Shared Status Registers (RSSR)
|
||||
*
|
||||
* After stopping Rx DMA channel (writing 0 to
|
||||
* FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll
|
||||
* FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle.
|
||||
*
|
||||
* Bit fields:
|
||||
* 24: 1 = Channel 0 is idle
|
||||
*
|
||||
* FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV
|
||||
* contain default values that should not be altered by the driver.
|
||||
*/
|
||||
#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40)
|
||||
#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00)
|
||||
|
||||
#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND)
|
||||
#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004)
|
||||
#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\
|
||||
(FH_MEM_RSSR_LOWER_BOUND + 0x008)
|
||||
|
||||
#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000)
|
||||
|
||||
#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28
|
||||
|
||||
/* TFDB Area - TFDs buffer table */
|
||||
#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF)
|
||||
#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900)
|
||||
#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958)
|
||||
#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
|
||||
#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
|
||||
|
||||
/**
|
||||
* Transmit DMA Channel Control/Status Registers (TCSR)
|
||||
*
|
||||
* 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
|
||||
* supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
|
||||
* which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
|
||||
*
|
||||
* To use a Tx DMA channel, driver must initialize its
|
||||
* FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with:
|
||||
*
|
||||
* FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
* FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL
|
||||
*
|
||||
* All other bits should be 0.
|
||||
*
|
||||
* Bit fields:
|
||||
* 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame,
|
||||
* '10' operate normally
|
||||
* 29- 4: Reserved, set to "0"
|
||||
* 3: Enable internal DMA requests (1, normal operation), disable (0)
|
||||
* 2- 0: Reserved, set to "0"
|
||||
*/
|
||||
#define FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00)
|
||||
#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60)
|
||||
|
||||
/* Find Control/Status reg for given Tx DMA/FIFO channel */
|
||||
#define FH49_TCSR_CHNL_NUM (7)
|
||||
#define FH50_TCSR_CHNL_NUM (8)
|
||||
|
||||
/* TCSR: tx_config register values */
|
||||
#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
|
||||
(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
|
||||
#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
|
||||
(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4)
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
|
||||
(FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8)
|
||||
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001)
|
||||
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008)
|
||||
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
|
||||
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000)
|
||||
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000)
|
||||
#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
|
||||
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000)
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000)
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003)
|
||||
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20)
|
||||
#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12)
|
||||
|
||||
/**
|
||||
* Tx Shared Status Registers (TSSR)
|
||||
*
|
||||
* After stopping Tx DMA channel (writing 0 to
|
||||
* FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll
|
||||
* FH_TSSR_TX_STATUS_REG until selected Tx channel is idle
|
||||
* (channel's buffers empty | no pending requests).
|
||||
*
|
||||
* Bit fields:
|
||||
* 31-24: 1 = Channel buffers empty (channel 7:0)
|
||||
* 23-16: 1 = No pending requests (channel 7:0)
|
||||
*/
|
||||
#define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0)
|
||||
#define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0)
|
||||
|
||||
#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010)
|
||||
|
||||
/**
|
||||
* Bit fields for TSSR(Tx Shared Status & Control) error status register:
|
||||
* 31: Indicates an address error when accessed to internal memory
|
||||
* uCode/driver must write "1" in order to clear this flag
|
||||
* 30: Indicates that Host did not send the expected number of dwords to FH
|
||||
* uCode/driver must write "1" in order to clear this flag
|
||||
* 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA
|
||||
* command was received from the scheduler while the TRB was already full
|
||||
* with previous command
|
||||
* uCode/driver must write "1" in order to clear this flag
|
||||
* 7-0: Each status bit indicates a channel's TxCredit error. When an error
|
||||
* bit is set, it indicates that the FH has received a full indication
|
||||
* from the RTC TxFIFO and the current value of the TxCredit counter was
|
||||
* not equal to zero. This mean that the credit mechanism was not
|
||||
* synchronized to the TxFIFO status
|
||||
* uCode/driver must write "1" in order to clear this flag
|
||||
*/
|
||||
#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018)
|
||||
|
||||
#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
|
||||
|
||||
/* Tx service channels */
|
||||
#define FH_SRVC_CHNL (9)
|
||||
#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8)
|
||||
#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
|
||||
#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
|
||||
(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
|
||||
|
||||
#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98)
|
||||
/* Instruct FH to increment the retry count of a packet when
|
||||
* it is brought from the memory to TX-FIFO
|
||||
*/
|
||||
#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002)
|
||||
|
||||
#define RX_QUEUE_SIZE 256
|
||||
#define RX_QUEUE_MASK 255
|
||||
#define RX_QUEUE_SIZE_LOG 8
|
||||
|
||||
/*
|
||||
* RX related structures and functions
|
||||
*/
|
||||
#define RX_FREE_BUFFERS 64
|
||||
#define RX_LOW_WATERMARK 8
|
||||
|
||||
/* Size of one Rx buffer in host DRAM */
|
||||
#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */
|
||||
#define IWL_RX_BUF_SIZE_4K (4 * 1024)
|
||||
#define IWL_RX_BUF_SIZE_8K (8 * 1024)
|
||||
|
||||
/**
|
||||
* struct iwl_rb_status - reseve buffer status
|
||||
* host memory mapped FH registers
|
||||
* @closed_rb_num [0:11] - Indicates the index of the RB which was closed
|
||||
* @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed
|
||||
* @finished_rb_num [0:11] - Indicates the index of the current RB
|
||||
* in which the last frame was written to
|
||||
* @finished_fr_num [0:11] - Indicates the index of the RX Frame
|
||||
* which was transfered
|
||||
*/
|
||||
struct iwl_rb_status {
|
||||
__le16 closed_rb_num;
|
||||
__le16 closed_fr_num;
|
||||
__le16 finished_rb_num;
|
||||
__le16 finished_fr_nam;
|
||||
__le32 __unused; /* 3945 only */
|
||||
} __packed;
|
||||
|
||||
|
||||
#define TFD_QUEUE_SIZE_MAX (256)
|
||||
#define TFD_QUEUE_SIZE_BC_DUP (64)
|
||||
#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
|
||||
#define IWL_TX_DMA_MASK DMA_BIT_MASK(36)
|
||||
#define IWL_NUM_OF_TBS 20
|
||||
|
||||
static inline u8 iwl_legacy_get_dma_hi_addr(dma_addr_t addr)
|
||||
{
|
||||
return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF;
|
||||
}
|
||||
/**
|
||||
* struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor
|
||||
*
|
||||
* This structure contains dma address and length of transmission address
|
||||
*
|
||||
* @lo: low [31:0] portion of the dma address of TX buffer
|
||||
* every even is unaligned on 16 bit boundary
|
||||
* @hi_n_len 0-3 [35:32] portion of dma
|
||||
* 4-15 length of the tx buffer
|
||||
*/
|
||||
struct iwl_tfd_tb {
|
||||
__le32 lo;
|
||||
__le16 hi_n_len;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_tfd
|
||||
*
|
||||
* Transmit Frame Descriptor (TFD)
|
||||
*
|
||||
* @ __reserved1[3] reserved
|
||||
* @ num_tbs 0-4 number of active tbs
|
||||
* 5 reserved
|
||||
* 6-7 padding (not used)
|
||||
* @ tbs[20] transmit frame buffer descriptors
|
||||
* @ __pad padding
|
||||
*
|
||||
* Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
|
||||
* Both driver and device share these circular buffers, each of which must be
|
||||
* contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes
|
||||
*
|
||||
* Driver must indicate the physical address of the base of each
|
||||
* circular buffer via the FH_MEM_CBBC_QUEUE registers.
|
||||
*
|
||||
* Each TFD contains pointer/size information for up to 20 data buffers
|
||||
* in host DRAM. These buffers collectively contain the (one) frame described
|
||||
* by the TFD. Each buffer must be a single contiguous block of memory within
|
||||
* itself, but buffers may be scattered in host DRAM. Each buffer has max size
|
||||
* of (4K - 4). The concatenates all of a TFD's buffers into a single
|
||||
* Tx frame, up to 8 KBytes in size.
|
||||
*
|
||||
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
|
||||
*/
|
||||
struct iwl_tfd {
|
||||
u8 __reserved1[3];
|
||||
u8 num_tbs;
|
||||
struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
|
||||
__le32 __pad;
|
||||
} __packed;
|
||||
|
||||
/* Keep Warm Size */
|
||||
#define IWL_KW_SIZE 0x1000 /* 4k */
|
||||
|
||||
#endif /* !__iwl_legacy_fh_h__ */
|
|
@ -0,0 +1,271 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* 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/sched.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-core.h"
|
||||
|
||||
|
||||
const char *iwl_legacy_get_cmd_string(u8 cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(REPLY_ALIVE);
|
||||
IWL_CMD(REPLY_ERROR);
|
||||
IWL_CMD(REPLY_RXON);
|
||||
IWL_CMD(REPLY_RXON_ASSOC);
|
||||
IWL_CMD(REPLY_QOS_PARAM);
|
||||
IWL_CMD(REPLY_RXON_TIMING);
|
||||
IWL_CMD(REPLY_ADD_STA);
|
||||
IWL_CMD(REPLY_REMOVE_STA);
|
||||
IWL_CMD(REPLY_WEPKEY);
|
||||
IWL_CMD(REPLY_3945_RX);
|
||||
IWL_CMD(REPLY_TX);
|
||||
IWL_CMD(REPLY_RATE_SCALE);
|
||||
IWL_CMD(REPLY_LEDS_CMD);
|
||||
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
|
||||
IWL_CMD(REPLY_CHANNEL_SWITCH);
|
||||
IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
|
||||
IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
|
||||
IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
|
||||
IWL_CMD(POWER_TABLE_CMD);
|
||||
IWL_CMD(PM_SLEEP_NOTIFICATION);
|
||||
IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
|
||||
IWL_CMD(REPLY_SCAN_CMD);
|
||||
IWL_CMD(REPLY_SCAN_ABORT_CMD);
|
||||
IWL_CMD(SCAN_START_NOTIFICATION);
|
||||
IWL_CMD(SCAN_RESULTS_NOTIFICATION);
|
||||
IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
|
||||
IWL_CMD(BEACON_NOTIFICATION);
|
||||
IWL_CMD(REPLY_TX_BEACON);
|
||||
IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
|
||||
IWL_CMD(REPLY_BT_CONFIG);
|
||||
IWL_CMD(REPLY_STATISTICS_CMD);
|
||||
IWL_CMD(STATISTICS_NOTIFICATION);
|
||||
IWL_CMD(CARD_STATE_NOTIFICATION);
|
||||
IWL_CMD(MISSED_BEACONS_NOTIFICATION);
|
||||
IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
|
||||
IWL_CMD(SENSITIVITY_CMD);
|
||||
IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
|
||||
IWL_CMD(REPLY_RX_PHY_CMD);
|
||||
IWL_CMD(REPLY_RX_MPDU_CMD);
|
||||
IWL_CMD(REPLY_RX);
|
||||
IWL_CMD(REPLY_COMPRESSED_BA);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_get_cmd_string);
|
||||
|
||||
#define HOST_COMPLETE_TIMEOUT (HZ / 2)
|
||||
|
||||
static void iwl_legacy_generic_cmd_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
|
||||
iwl_legacy_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
switch (cmd->hdr.cmd) {
|
||||
case REPLY_TX_LINK_QUALITY_CMD:
|
||||
case SENSITIVITY_CMD:
|
||||
IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n",
|
||||
iwl_legacy_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n",
|
||||
iwl_legacy_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_legacy_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!(cmd->flags & CMD_ASYNC));
|
||||
|
||||
/* An asynchronous command can not expect an SKB to be set. */
|
||||
BUG_ON(cmd->flags & CMD_WANT_SKB);
|
||||
|
||||
/* Assign a generic callback if one is not provided */
|
||||
if (!cmd->callback)
|
||||
cmd->callback = iwl_legacy_generic_cmd_callback;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EBUSY;
|
||||
|
||||
ret = iwl_legacy_enqueue_hcmd(priv, cmd);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id), ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
int cmd_idx;
|
||||
int ret;
|
||||
|
||||
BUG_ON(cmd->flags & CMD_ASYNC);
|
||||
|
||||
/* A synchronous command can not have a callback set. */
|
||||
BUG_ON(cmd->callback);
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
mutex_lock(&priv->sync_cmd_mutex);
|
||||
|
||||
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
|
||||
cmd_idx = iwl_legacy_enqueue_hcmd(priv, cmd);
|
||||
if (cmd_idx < 0) {
|
||||
ret = cmd_idx;
|
||||
IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id), ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
|
||||
!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
|
||||
HOST_COMPLETE_TIMEOUT);
|
||||
if (!ret) {
|
||||
if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
|
||||
IWL_ERR(priv,
|
||||
"Error sending %s: time out after %dms.\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id),
|
||||
jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
|
||||
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Clearing HCMD_ACTIVE for command %s\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
ret = -ETIMEDOUT;
|
||||
goto cancel;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
|
||||
IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
ret = -ECANCELED;
|
||||
goto fail;
|
||||
}
|
||||
if (test_bit(STATUS_FW_ERROR, &priv->status)) {
|
||||
IWL_ERR(priv, "Command %s failed: FW Error\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
|
||||
IWL_ERR(priv, "Error: Response NULL in '%s'\n",
|
||||
iwl_legacy_get_cmd_string(cmd->id));
|
||||
ret = -EIO;
|
||||
goto cancel;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
cancel:
|
||||
if (cmd->flags & CMD_WANT_SKB) {
|
||||
/*
|
||||
* Cancel the CMD_WANT_SKB flag for the cmd in the
|
||||
* TX cmd queue. Otherwise in case the cmd comes
|
||||
* in later, it will possibly set an invalid
|
||||
* address (cmd->meta.source).
|
||||
*/
|
||||
priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
|
||||
~CMD_WANT_SKB;
|
||||
}
|
||||
fail:
|
||||
if (cmd->reply_page) {
|
||||
iwl_legacy_free_pages(priv, cmd->reply_page);
|
||||
cmd->reply_page = 0;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&priv->sync_cmd_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_cmd_sync);
|
||||
|
||||
int iwl_legacy_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
if (cmd->flags & CMD_ASYNC)
|
||||
return iwl_legacy_send_cmd_async(priv, cmd);
|
||||
|
||||
return iwl_legacy_send_cmd_sync(priv, cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_cmd);
|
||||
|
||||
int
|
||||
iwl_legacy_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = id,
|
||||
.len = len,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
return iwl_legacy_send_cmd_sync(priv, &cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_cmd_pdu);
|
||||
|
||||
int iwl_legacy_send_cmd_pdu_async(struct iwl_priv *priv,
|
||||
u8 id, u16 len, const void *data,
|
||||
void (*callback)(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct iwl_rx_packet *pkt))
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = id,
|
||||
.len = len,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
cmd.flags |= CMD_ASYNC;
|
||||
cmd.callback = callback;
|
||||
|
||||
return iwl_legacy_send_cmd_async(priv, &cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_cmd_pdu_async);
|
|
@ -0,0 +1,181 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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_legacy_helpers_h__
|
||||
#define __iwl_legacy_helpers_h__
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-io.h"
|
||||
|
||||
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
|
||||
|
||||
|
||||
static inline struct ieee80211_conf *iwl_legacy_ieee80211_get_hw_conf(
|
||||
struct ieee80211_hw *hw)
|
||||
{
|
||||
return &hw->conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_queue_inc_wrap - increment queue index, wrap back to beginning
|
||||
* @index -- current index
|
||||
* @n_bd -- total number of entries in queue (must be power of 2)
|
||||
*/
|
||||
static inline int iwl_legacy_queue_inc_wrap(int index, int n_bd)
|
||||
{
|
||||
return ++index & (n_bd - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_queue_dec_wrap - decrement queue index, wrap back to end
|
||||
* @index -- current index
|
||||
* @n_bd -- total number of entries in queue (must be power of 2)
|
||||
*/
|
||||
static inline int iwl_legacy_queue_dec_wrap(int index, int n_bd)
|
||||
{
|
||||
return --index & (n_bd - 1);
|
||||
}
|
||||
|
||||
/* TODO: Move fw_desc functions to iwl-pci.ko */
|
||||
static inline void iwl_legacy_free_fw_desc(struct pci_dev *pci_dev,
|
||||
struct fw_desc *desc)
|
||||
{
|
||||
if (desc->v_addr)
|
||||
dma_free_coherent(&pci_dev->dev, desc->len,
|
||||
desc->v_addr, desc->p_addr);
|
||||
desc->v_addr = NULL;
|
||||
desc->len = 0;
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_alloc_fw_desc(struct pci_dev *pci_dev,
|
||||
struct fw_desc *desc)
|
||||
{
|
||||
if (!desc->len) {
|
||||
desc->v_addr = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
|
||||
&desc->p_addr, GFP_KERNEL);
|
||||
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have 8 bits used like this:
|
||||
*
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* | | | | | | | |
|
||||
* | | | | | | +-+-------- AC queue (0-3)
|
||||
* | | | | | |
|
||||
* | +-+-+-+-+------------ HW queue ID
|
||||
* |
|
||||
* +---------------------- unused
|
||||
*/
|
||||
static inline void
|
||||
iwl_legacy_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
|
||||
{
|
||||
BUG_ON(ac > 3); /* only have 2 bits */
|
||||
BUG_ON(hwq > 31); /* only use 5 bits */
|
||||
|
||||
txq->swq_id = (hwq << 2) | ac;
|
||||
}
|
||||
|
||||
static inline void iwl_legacy_wake_queue(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq)
|
||||
{
|
||||
u8 queue = txq->swq_id;
|
||||
u8 ac = queue & 3;
|
||||
u8 hwq = (queue >> 2) & 0x1f;
|
||||
|
||||
if (test_and_clear_bit(hwq, priv->queue_stopped))
|
||||
if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0)
|
||||
ieee80211_wake_queue(priv->hw, ac);
|
||||
}
|
||||
|
||||
static inline void iwl_legacy_stop_queue(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq)
|
||||
{
|
||||
u8 queue = txq->swq_id;
|
||||
u8 ac = queue & 3;
|
||||
u8 hwq = (queue >> 2) & 0x1f;
|
||||
|
||||
if (!test_and_set_bit(hwq, priv->queue_stopped))
|
||||
if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0)
|
||||
ieee80211_stop_queue(priv->hw, ac);
|
||||
}
|
||||
|
||||
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
|
||||
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
|
||||
|
||||
static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv)
|
||||
{
|
||||
clear_bit(STATUS_INT_ENABLED, &priv->status);
|
||||
|
||||
/* disable interrupts from uCode/NIC to host */
|
||||
iwl_write32(priv, CSR_INT_MASK, 0x00000000);
|
||||
|
||||
/* acknowledge/clear/reset any interrupts still pending
|
||||
* from uCode or flow handler (Rx/Tx DMA) */
|
||||
iwl_write32(priv, CSR_INT, 0xffffffff);
|
||||
iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
|
||||
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
|
||||
}
|
||||
|
||||
static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
|
||||
set_bit(STATUS_INT_ENABLED, &priv->status);
|
||||
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_beacon_time_mask_low - mask of lower 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_legacy_beacon_time_mask_low(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return (1 << tsf_bits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_beacon_time_mask_high - mask of higher 32 bit of beacon time
|
||||
* @priv -- pointer to iwl_priv data structure
|
||||
* @tsf_bits -- number of bits need to shift for masking)
|
||||
*/
|
||||
static inline u32 iwl_legacy_beacon_time_mask_high(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
{
|
||||
return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
|
||||
}
|
||||
|
||||
#endif /* __iwl_legacy_helpers_h__ */
|
|
@ -0,0 +1,545 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project.
|
||||
*
|
||||
* 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_legacy_io_h__
|
||||
#define __iwl_legacy_io_h__
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-devtrace.h"
|
||||
|
||||
/*
|
||||
* IO, register, and NIC memory access functions
|
||||
*
|
||||
* NOTE on naming convention and macro usage for these
|
||||
*
|
||||
* A single _ prefix before a an access function means that no state
|
||||
* check or debug information is printed when that function is called.
|
||||
*
|
||||
* A double __ prefix before an access function means that state is checked
|
||||
* and the current line number and caller function name are printed in addition
|
||||
* to any other debug output.
|
||||
*
|
||||
* The non-prefixed name is the #define that maps the caller into a
|
||||
* #define that provides the caller's name and __LINE__ to the double
|
||||
* prefix version.
|
||||
*
|
||||
* If you wish to call the function without any debug or state checking,
|
||||
* you should use the single _ prefix version (as is used by dependent IO
|
||||
* routines, for example _iwl_legacy_read_direct32 calls the non-check version of
|
||||
* _iwl_legacy_read32.)
|
||||
*
|
||||
* These declarations are *extremely* useful in quickly isolating code deltas
|
||||
* which result in misconfiguration of the hardware I/O. In combination with
|
||||
* git-bisect and the IO debug level you can quickly determine the specific
|
||||
* commit which breaks the IO sequence to the hardware.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline void _iwl_legacy_write8(struct iwl_priv *priv, u32 ofs, u8 val)
|
||||
{
|
||||
trace_iwlwifi_legacy_dev_iowrite8(priv, ofs, val);
|
||||
iowrite8(val, priv->hw_base + ofs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline void
|
||||
__iwl_legacy_write8(const char *f, u32 l, struct iwl_priv *priv,
|
||||
u32 ofs, u8 val)
|
||||
{
|
||||
IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l);
|
||||
_iwl_legacy_write8(priv, ofs, val);
|
||||
}
|
||||
#define iwl_write8(priv, ofs, val) \
|
||||
__iwl_legacy_write8(__FILE__, __LINE__, priv, ofs, val)
|
||||
#else
|
||||
#define iwl_write8(priv, ofs, val) _iwl_legacy_write8(priv, ofs, val)
|
||||
#endif
|
||||
|
||||
|
||||
static inline void _iwl_legacy_write32(struct iwl_priv *priv, u32 ofs, u32 val)
|
||||
{
|
||||
trace_iwlwifi_legacy_dev_iowrite32(priv, ofs, val);
|
||||
iowrite32(val, priv->hw_base + ofs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline void
|
||||
__iwl_legacy_write32(const char *f, u32 l, struct iwl_priv *priv,
|
||||
u32 ofs, u32 val)
|
||||
{
|
||||
IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
|
||||
_iwl_legacy_write32(priv, ofs, val);
|
||||
}
|
||||
#define iwl_write32(priv, ofs, val) \
|
||||
__iwl_legacy_write32(__FILE__, __LINE__, priv, ofs, val)
|
||||
#else
|
||||
#define iwl_write32(priv, ofs, val) _iwl_legacy_write32(priv, ofs, val)
|
||||
#endif
|
||||
|
||||
static inline u32 _iwl_legacy_read32(struct iwl_priv *priv, u32 ofs)
|
||||
{
|
||||
u32 val = ioread32(priv->hw_base + ofs);
|
||||
trace_iwlwifi_legacy_dev_ioread32(priv, ofs, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline u32
|
||||
__iwl_legacy_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
|
||||
{
|
||||
IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l);
|
||||
return _iwl_legacy_read32(priv, ofs);
|
||||
}
|
||||
#define iwl_read32(priv, ofs) __iwl_legacy_read32(__FILE__, __LINE__, priv, ofs)
|
||||
#else
|
||||
#define iwl_read32(p, o) _iwl_legacy_read32(p, o)
|
||||
#endif
|
||||
|
||||
#define IWL_POLL_INTERVAL 10 /* microseconds */
|
||||
static inline int
|
||||
_iwl_legacy_poll_bit(struct iwl_priv *priv, u32 addr,
|
||||
u32 bits, u32 mask, int timeout)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((_iwl_legacy_read32(priv, addr) & mask) == (bits & mask))
|
||||
return t;
|
||||
udelay(IWL_POLL_INTERVAL);
|
||||
t += IWL_POLL_INTERVAL;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline int __iwl_legacy_poll_bit(const char *f, u32 l,
|
||||
struct iwl_priv *priv, u32 addr,
|
||||
u32 bits, u32 mask, int timeout)
|
||||
{
|
||||
int ret = _iwl_legacy_poll_bit(priv, addr, bits, mask, timeout);
|
||||
IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
|
||||
addr, bits, mask,
|
||||
unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
|
||||
return ret;
|
||||
}
|
||||
#define iwl_poll_bit(priv, addr, bits, mask, timeout) \
|
||||
__iwl_legacy_poll_bit(__FILE__, __LINE__, priv, addr, \
|
||||
bits, mask, timeout)
|
||||
#else
|
||||
#define iwl_poll_bit(p, a, b, m, t) _iwl_legacy_poll_bit(p, a, b, m, t)
|
||||
#endif
|
||||
|
||||
static inline void _iwl_legacy_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
_iwl_legacy_write32(priv, reg, _iwl_legacy_read32(priv, reg) | mask);
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline void __iwl_legacy_set_bit(const char *f, u32 l,
|
||||
struct iwl_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
u32 val = _iwl_legacy_read32(priv, reg) | mask;
|
||||
IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg,
|
||||
mask, val);
|
||||
_iwl_legacy_write32(priv, reg, val);
|
||||
}
|
||||
static inline void iwl_legacy_set_bit(struct iwl_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
__iwl_legacy_set_bit(__FILE__, __LINE__, p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
#else
|
||||
static inline void iwl_legacy_set_bit(struct iwl_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_iwl_legacy_set_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
_iwl_legacy_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
_iwl_legacy_write32(priv, reg, _iwl_legacy_read32(priv, reg) & ~mask);
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline void
|
||||
__iwl_legacy_clear_bit(const char *f, u32 l,
|
||||
struct iwl_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
u32 val = _iwl_legacy_read32(priv, reg) & ~mask;
|
||||
IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
|
||||
_iwl_legacy_write32(priv, reg, val);
|
||||
}
|
||||
static inline void iwl_legacy_clear_bit(struct iwl_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
__iwl_legacy_clear_bit(__FILE__, __LINE__, p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
#else
|
||||
static inline void iwl_legacy_clear_bit(struct iwl_priv *p, u32 r, u32 m)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&p->reg_lock, reg_flags);
|
||||
_iwl_legacy_clear_bit(p, r, m);
|
||||
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int _iwl_legacy_grab_nic_access(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
_iwl_legacy_set_bit(priv, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
|
||||
/*
|
||||
* These bits say the device is running, and should keep running for
|
||||
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
|
||||
* but they do not indicate that embedded SRAM is restored yet;
|
||||
* 3945 and 4965 have volatile SRAM, and must save/restore contents
|
||||
* to/from host DRAM when sleeping/waking for power-saving.
|
||||
* Each direction takes approximately 1/4 millisecond; with this
|
||||
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
|
||||
* series of register accesses are expected (e.g. reading Event Log),
|
||||
* to keep device from sleeping.
|
||||
*
|
||||
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
|
||||
* SRAM is okay/restored. We don't check that here because this call
|
||||
* is just for hardware register access; but GP1 MAC_SLEEP check is a
|
||||
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
|
||||
*
|
||||
*/
|
||||
ret = _iwl_legacy_poll_bit(priv, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
|
||||
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
|
||||
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
|
||||
if (ret < 0) {
|
||||
val = _iwl_legacy_read32(priv, CSR_GP_CNTRL);
|
||||
IWL_ERR(priv,
|
||||
"MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
|
||||
_iwl_legacy_write32(priv, CSR_RESET,
|
||||
CSR_RESET_REG_FLAG_FORCE_NMI);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline int __iwl_legacy_grab_nic_access(const char *f, u32 l,
|
||||
struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l);
|
||||
return _iwl_legacy_grab_nic_access(priv);
|
||||
}
|
||||
#define iwl_grab_nic_access(priv) \
|
||||
__iwl_legacy_grab_nic_access(__FILE__, __LINE__, priv)
|
||||
#else
|
||||
#define iwl_grab_nic_access(priv) \
|
||||
_iwl_legacy_grab_nic_access(priv)
|
||||
#endif
|
||||
|
||||
static inline void _iwl_legacy_release_nic_access(struct iwl_priv *priv)
|
||||
{
|
||||
_iwl_legacy_clear_bit(priv, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline void __iwl_legacy_release_nic_access(const char *f, u32 l,
|
||||
struct iwl_priv *priv)
|
||||
{
|
||||
|
||||
IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l);
|
||||
_iwl_legacy_release_nic_access(priv);
|
||||
}
|
||||
#define iwl_release_nic_access(priv) \
|
||||
__iwl_legacy_release_nic_access(__FILE__, __LINE__, priv)
|
||||
#else
|
||||
#define iwl_release_nic_access(priv) \
|
||||
_iwl_legacy_release_nic_access(priv)
|
||||
#endif
|
||||
|
||||
static inline u32 _iwl_legacy_read_direct32(struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
return _iwl_legacy_read32(priv, reg);
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline u32 __iwl_legacy_read_direct32(const char *f, u32 l,
|
||||
struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
u32 value = _iwl_legacy_read_direct32(priv, reg);
|
||||
IWL_DEBUG_IO(priv,
|
||||
"read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value,
|
||||
f, l);
|
||||
return value;
|
||||
}
|
||||
static inline u32 iwl_legacy_read_direct32(struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
value = __iwl_legacy_read_direct32(__FILE__, __LINE__, priv, reg);
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return value;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline u32 iwl_legacy_read_direct32(struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
value = _iwl_legacy_read_direct32(priv, reg);
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return value;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void _iwl_legacy_write_direct32(struct iwl_priv *priv,
|
||||
u32 reg, u32 value)
|
||||
{
|
||||
_iwl_legacy_write32(priv, reg, value);
|
||||
}
|
||||
static inline void
|
||||
iwl_legacy_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
if (!iwl_grab_nic_access(priv)) {
|
||||
_iwl_legacy_write_direct32(priv, reg, value);
|
||||
iwl_release_nic_access(priv);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void iwl_legacy_write_reg_buf(struct iwl_priv *priv,
|
||||
u32 reg, u32 len, u32 *values)
|
||||
{
|
||||
u32 count = sizeof(u32);
|
||||
|
||||
if ((priv != NULL) && (values != NULL)) {
|
||||
for (; 0 < len; len -= count, reg += count, values++)
|
||||
iwl_legacy_write_direct32(priv, reg, *values);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int _iwl_legacy_poll_direct_bit(struct iwl_priv *priv, u32 addr,
|
||||
u32 mask, int timeout)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((iwl_legacy_read_direct32(priv, addr) & mask) == mask)
|
||||
return t;
|
||||
udelay(IWL_POLL_INTERVAL);
|
||||
t += IWL_POLL_INTERVAL;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static inline int __iwl_legacy_poll_direct_bit(const char *f, u32 l,
|
||||
struct iwl_priv *priv,
|
||||
u32 addr, u32 mask, int timeout)
|
||||
{
|
||||
int ret = _iwl_legacy_poll_direct_bit(priv, addr, mask, timeout);
|
||||
|
||||
if (unlikely(ret == -ETIMEDOUT))
|
||||
IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - "
|
||||
"timedout - %s %d\n", addr, mask, f, l);
|
||||
else
|
||||
IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
|
||||
"- %s %d\n", addr, mask, ret, f, l);
|
||||
return ret;
|
||||
}
|
||||
#define iwl_poll_direct_bit(priv, addr, mask, timeout) \
|
||||
__iwl_legacy_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout)
|
||||
#else
|
||||
#define iwl_poll_direct_bit _iwl_legacy_poll_direct_bit
|
||||
#endif
|
||||
|
||||
static inline u32 _iwl_legacy_read_prph(struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
|
||||
rmb();
|
||||
return _iwl_legacy_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
|
||||
}
|
||||
static inline u32 iwl_legacy_read_prph(struct iwl_priv *priv, u32 reg)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
val = _iwl_legacy_read_prph(priv, reg);
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void _iwl_legacy_write_prph(struct iwl_priv *priv,
|
||||
u32 addr, u32 val)
|
||||
{
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
|
||||
((addr & 0x0000FFFF) | (3 << 24)));
|
||||
wmb();
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
iwl_legacy_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
if (!iwl_grab_nic_access(priv)) {
|
||||
_iwl_legacy_write_prph(priv, addr, val);
|
||||
iwl_release_nic_access(priv);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
#define _iwl_legacy_set_bits_prph(priv, reg, mask) \
|
||||
_iwl_legacy_write_prph(priv, reg, (_iwl_legacy_read_prph(priv, reg) | mask))
|
||||
|
||||
static inline void
|
||||
iwl_legacy_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
_iwl_legacy_set_bits_prph(priv, reg, mask);
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
#define _iwl_legacy_set_bits_mask_prph(priv, reg, bits, mask) \
|
||||
_iwl_legacy_write_prph(priv, reg, \
|
||||
((_iwl_legacy_read_prph(priv, reg) & mask) | bits))
|
||||
|
||||
static inline void iwl_legacy_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
|
||||
u32 bits, u32 mask)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
_iwl_legacy_set_bits_mask_prph(priv, reg, bits, mask);
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void iwl_legacy_clear_bits_prph(struct iwl_priv
|
||||
*priv, u32 reg, u32 mask)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
val = _iwl_legacy_read_prph(priv, reg);
|
||||
_iwl_legacy_write_prph(priv, reg, (val & ~mask));
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline u32 iwl_legacy_read_targ_mem(struct iwl_priv *priv, u32 addr)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
u32 value;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
iwl_grab_nic_access(priv);
|
||||
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
|
||||
rmb();
|
||||
value = _iwl_legacy_read_direct32(priv, HBUS_TARG_MEM_RDAT);
|
||||
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
iwl_legacy_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
if (!iwl_grab_nic_access(priv)) {
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
|
||||
wmb();
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
|
||||
iwl_release_nic_access(priv);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
iwl_legacy_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
|
||||
u32 len, u32 *values)
|
||||
{
|
||||
unsigned long reg_flags;
|
||||
|
||||
spin_lock_irqsave(&priv->reg_lock, reg_flags);
|
||||
if (!iwl_grab_nic_access(priv)) {
|
||||
_iwl_legacy_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
|
||||
wmb();
|
||||
for (; 0 < len; len -= sizeof(u32), values++)
|
||||
_iwl_legacy_write_direct32(priv,
|
||||
HBUS_TARG_MEM_WDAT, *values);
|
||||
|
||||
iwl_release_nic_access(priv);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,188 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
|
||||
/* default: IWL_LED_BLINK(0) using blinking index table */
|
||||
static int led_mode;
|
||||
module_param(led_mode, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(led_mode, "0=system default, "
|
||||
"1=On(RF On)/Off(RF Off), 2=blinking");
|
||||
|
||||
static const struct ieee80211_tpt_blink iwl_blink[] = {
|
||||
{ .throughput = 0 * 1024 - 1, .blink_time = 334 },
|
||||
{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
|
||||
{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
|
||||
{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
|
||||
{ .throughput = 20 * 1024 - 1, .blink_time = 170 },
|
||||
{ .throughput = 50 * 1024 - 1, .blink_time = 150 },
|
||||
{ .throughput = 70 * 1024 - 1, .blink_time = 130 },
|
||||
{ .throughput = 100 * 1024 - 1, .blink_time = 110 },
|
||||
{ .throughput = 200 * 1024 - 1, .blink_time = 80 },
|
||||
{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Adjust led blink rate to compensate on a MAC Clock difference on every HW
|
||||
* Led blink rate analysis showed an average deviation of 0% on 3945,
|
||||
* 5% on 4965 HW.
|
||||
* Need to compensate on the led on/off time per HW according to the deviation
|
||||
* to achieve the desired led frequency
|
||||
* The calculation is: (100-averageDeviation)/100 * blinkTime
|
||||
* For code efficiency the calculation will be:
|
||||
* compensation = (100 - averageDeviation) * 64 / 100
|
||||
* NewBlinkTime = (compensation * BlinkTime) / 64
|
||||
*/
|
||||
static inline u8 iwl_legacy_blink_compensation(struct iwl_priv *priv,
|
||||
u8 time, u16 compensation)
|
||||
{
|
||||
if (!compensation) {
|
||||
IWL_ERR(priv, "undefined blink compensation: "
|
||||
"use pre-defined blinking time\n");
|
||||
return time;
|
||||
}
|
||||
|
||||
return (u8)((time * compensation) >> 6);
|
||||
}
|
||||
|
||||
/* Set led pattern command */
|
||||
static int iwl_legacy_led_cmd(struct iwl_priv *priv,
|
||||
unsigned long on,
|
||||
unsigned long off)
|
||||
{
|
||||
struct iwl_led_cmd led_cmd = {
|
||||
.id = IWL_LED_LINK,
|
||||
.interval = IWL_DEF_LED_INTRVL
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!test_bit(STATUS_READY, &priv->status))
|
||||
return -EBUSY;
|
||||
|
||||
if (priv->blink_on == on && priv->blink_off == off)
|
||||
return 0;
|
||||
|
||||
IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
|
||||
priv->cfg->base_params->led_compensation);
|
||||
led_cmd.on = iwl_legacy_blink_compensation(priv, on,
|
||||
priv->cfg->base_params->led_compensation);
|
||||
led_cmd.off = iwl_legacy_blink_compensation(priv, off,
|
||||
priv->cfg->base_params->led_compensation);
|
||||
|
||||
ret = priv->cfg->ops->led->cmd(priv, &led_cmd);
|
||||
if (!ret) {
|
||||
priv->blink_on = on;
|
||||
priv->blink_off = off;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_legacy_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
|
||||
unsigned long on = 0;
|
||||
|
||||
if (brightness > 0)
|
||||
on = IWL_LED_SOLID;
|
||||
|
||||
iwl_legacy_led_cmd(priv, on, 0);
|
||||
}
|
||||
|
||||
static int iwl_legacy_led_blink_set(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
|
||||
|
||||
return iwl_legacy_led_cmd(priv, *delay_on, *delay_off);
|
||||
}
|
||||
|
||||
void iwl_legacy_leds_init(struct iwl_priv *priv)
|
||||
{
|
||||
int mode = led_mode;
|
||||
int ret;
|
||||
|
||||
if (mode == IWL_LED_DEFAULT)
|
||||
mode = priv->cfg->led_mode;
|
||||
|
||||
priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
priv->led.brightness_set = iwl_legacy_led_brightness_set;
|
||||
priv->led.blink_set = iwl_legacy_led_blink_set;
|
||||
priv->led.max_brightness = 1;
|
||||
|
||||
switch (mode) {
|
||||
case IWL_LED_DEFAULT:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
case IWL_LED_BLINK:
|
||||
priv->led.default_trigger =
|
||||
ieee80211_create_tpt_led_trigger(priv->hw,
|
||||
IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
|
||||
iwl_blink, ARRAY_SIZE(iwl_blink));
|
||||
break;
|
||||
case IWL_LED_RF_STATE:
|
||||
priv->led.default_trigger =
|
||||
ieee80211_get_radio_led_name(priv->hw);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = led_classdev_register(&priv->pci_dev->dev, &priv->led);
|
||||
if (ret) {
|
||||
kfree(priv->led.name);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->led_registered = true;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_leds_init);
|
||||
|
||||
void iwl_legacy_leds_exit(struct iwl_priv *priv)
|
||||
{
|
||||
if (!priv->led_registered)
|
||||
return;
|
||||
|
||||
led_classdev_unregister(&priv->led);
|
||||
kfree(priv->led.name);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_leds_exit);
|
|
@ -0,0 +1,56 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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_legacy_leds_h__
|
||||
#define __iwl_legacy_leds_h__
|
||||
|
||||
|
||||
struct iwl_priv;
|
||||
|
||||
#define IWL_LED_SOLID 11
|
||||
#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
|
||||
|
||||
#define IWL_LED_ACTIVITY (0<<1)
|
||||
#define IWL_LED_LINK (1<<1)
|
||||
|
||||
/*
|
||||
* LED mode
|
||||
* IWL_LED_DEFAULT: use device default
|
||||
* IWL_LED_RF_STATE: turn LED on/off based on RF state
|
||||
* LED ON = RF ON
|
||||
* LED OFF = RF OFF
|
||||
* IWL_LED_BLINK: adjust led blink rate based on blink table
|
||||
*/
|
||||
enum iwl_led_mode {
|
||||
IWL_LED_DEFAULT,
|
||||
IWL_LED_RF_STATE,
|
||||
IWL_LED_BLINK,
|
||||
};
|
||||
|
||||
void iwl_legacy_leds_init(struct iwl_priv *priv);
|
||||
void iwl_legacy_leds_exit(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_legacy_leds_h__ */
|
|
@ -0,0 +1,456 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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_legacy_rs_h__
|
||||
#define __iwl_legacy_rs_h__
|
||||
|
||||
struct iwl_rate_info {
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
||||
u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
|
||||
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
|
||||
u8 prev_ieee; /* previous rate in IEEE speeds */
|
||||
u8 next_ieee; /* next rate in IEEE speeds */
|
||||
u8 prev_rs; /* previous rate used in rs algo */
|
||||
u8 next_rs; /* next rate used in rs algo */
|
||||
u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
|
||||
u8 next_rs_tgg; /* next rate used in TGG rs algo */
|
||||
};
|
||||
|
||||
struct iwl3945_rate_info {
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
|
||||
u8 prev_ieee; /* previous rate in IEEE speeds */
|
||||
u8 next_ieee; /* next rate in IEEE speeds */
|
||||
u8 prev_rs; /* previous rate used in rs algo */
|
||||
u8 next_rs; /* next rate used in rs algo */
|
||||
u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
|
||||
u8 next_rs_tgg; /* next rate used in TGG rs algo */
|
||||
u8 table_rs_index; /* index in rate scale table cmd */
|
||||
u8 prev_table_rs; /* prev in rate table cmd */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* These serve as indexes into
|
||||
* struct iwl_rate_info iwlegacy_rates[IWL_RATE_COUNT];
|
||||
*/
|
||||
enum {
|
||||
IWL_RATE_1M_INDEX = 0,
|
||||
IWL_RATE_2M_INDEX,
|
||||
IWL_RATE_5M_INDEX,
|
||||
IWL_RATE_11M_INDEX,
|
||||
IWL_RATE_6M_INDEX,
|
||||
IWL_RATE_9M_INDEX,
|
||||
IWL_RATE_12M_INDEX,
|
||||
IWL_RATE_18M_INDEX,
|
||||
IWL_RATE_24M_INDEX,
|
||||
IWL_RATE_36M_INDEX,
|
||||
IWL_RATE_48M_INDEX,
|
||||
IWL_RATE_54M_INDEX,
|
||||
IWL_RATE_60M_INDEX,
|
||||
IWL_RATE_COUNT,
|
||||
IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */
|
||||
IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1,
|
||||
IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
|
||||
IWL_RATE_INVALID = IWL_RATE_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
IWL_RATE_6M_INDEX_TABLE = 0,
|
||||
IWL_RATE_9M_INDEX_TABLE,
|
||||
IWL_RATE_12M_INDEX_TABLE,
|
||||
IWL_RATE_18M_INDEX_TABLE,
|
||||
IWL_RATE_24M_INDEX_TABLE,
|
||||
IWL_RATE_36M_INDEX_TABLE,
|
||||
IWL_RATE_48M_INDEX_TABLE,
|
||||
IWL_RATE_54M_INDEX_TABLE,
|
||||
IWL_RATE_1M_INDEX_TABLE,
|
||||
IWL_RATE_2M_INDEX_TABLE,
|
||||
IWL_RATE_5M_INDEX_TABLE,
|
||||
IWL_RATE_11M_INDEX_TABLE,
|
||||
IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
|
||||
IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
|
||||
IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
|
||||
IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
|
||||
IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
|
||||
};
|
||||
|
||||
/* #define vs. enum to keep from defaulting to 'large integer' */
|
||||
#define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX)
|
||||
#define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX)
|
||||
#define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX)
|
||||
#define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX)
|
||||
#define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX)
|
||||
#define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX)
|
||||
#define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX)
|
||||
#define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX)
|
||||
#define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX)
|
||||
#define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX)
|
||||
#define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX)
|
||||
#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX)
|
||||
#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
|
||||
|
||||
/* uCode API values for legacy bit rates, both OFDM and CCK */
|
||||
enum {
|
||||
IWL_RATE_6M_PLCP = 13,
|
||||
IWL_RATE_9M_PLCP = 15,
|
||||
IWL_RATE_12M_PLCP = 5,
|
||||
IWL_RATE_18M_PLCP = 7,
|
||||
IWL_RATE_24M_PLCP = 9,
|
||||
IWL_RATE_36M_PLCP = 11,
|
||||
IWL_RATE_48M_PLCP = 1,
|
||||
IWL_RATE_54M_PLCP = 3,
|
||||
IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
|
||||
IWL_RATE_1M_PLCP = 10,
|
||||
IWL_RATE_2M_PLCP = 20,
|
||||
IWL_RATE_5M_PLCP = 55,
|
||||
IWL_RATE_11M_PLCP = 110,
|
||||
/*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
|
||||
};
|
||||
|
||||
/* uCode API values for OFDM high-throughput (HT) bit rates */
|
||||
enum {
|
||||
IWL_RATE_SISO_6M_PLCP = 0,
|
||||
IWL_RATE_SISO_12M_PLCP = 1,
|
||||
IWL_RATE_SISO_18M_PLCP = 2,
|
||||
IWL_RATE_SISO_24M_PLCP = 3,
|
||||
IWL_RATE_SISO_36M_PLCP = 4,
|
||||
IWL_RATE_SISO_48M_PLCP = 5,
|
||||
IWL_RATE_SISO_54M_PLCP = 6,
|
||||
IWL_RATE_SISO_60M_PLCP = 7,
|
||||
IWL_RATE_MIMO2_6M_PLCP = 0x8,
|
||||
IWL_RATE_MIMO2_12M_PLCP = 0x9,
|
||||
IWL_RATE_MIMO2_18M_PLCP = 0xa,
|
||||
IWL_RATE_MIMO2_24M_PLCP = 0xb,
|
||||
IWL_RATE_MIMO2_36M_PLCP = 0xc,
|
||||
IWL_RATE_MIMO2_48M_PLCP = 0xd,
|
||||
IWL_RATE_MIMO2_54M_PLCP = 0xe,
|
||||
IWL_RATE_MIMO2_60M_PLCP = 0xf,
|
||||
IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
|
||||
};
|
||||
|
||||
/* MAC header values for bit rates */
|
||||
enum {
|
||||
IWL_RATE_6M_IEEE = 12,
|
||||
IWL_RATE_9M_IEEE = 18,
|
||||
IWL_RATE_12M_IEEE = 24,
|
||||
IWL_RATE_18M_IEEE = 36,
|
||||
IWL_RATE_24M_IEEE = 48,
|
||||
IWL_RATE_36M_IEEE = 72,
|
||||
IWL_RATE_48M_IEEE = 96,
|
||||
IWL_RATE_54M_IEEE = 108,
|
||||
IWL_RATE_60M_IEEE = 120,
|
||||
IWL_RATE_1M_IEEE = 2,
|
||||
IWL_RATE_2M_IEEE = 4,
|
||||
IWL_RATE_5M_IEEE = 11,
|
||||
IWL_RATE_11M_IEEE = 22,
|
||||
};
|
||||
|
||||
#define IWL_CCK_BASIC_RATES_MASK \
|
||||
(IWL_RATE_1M_MASK | \
|
||||
IWL_RATE_2M_MASK)
|
||||
|
||||
#define IWL_CCK_RATES_MASK \
|
||||
(IWL_CCK_BASIC_RATES_MASK | \
|
||||
IWL_RATE_5M_MASK | \
|
||||
IWL_RATE_11M_MASK)
|
||||
|
||||
#define IWL_OFDM_BASIC_RATES_MASK \
|
||||
(IWL_RATE_6M_MASK | \
|
||||
IWL_RATE_12M_MASK | \
|
||||
IWL_RATE_24M_MASK)
|
||||
|
||||
#define IWL_OFDM_RATES_MASK \
|
||||
(IWL_OFDM_BASIC_RATES_MASK | \
|
||||
IWL_RATE_9M_MASK | \
|
||||
IWL_RATE_18M_MASK | \
|
||||
IWL_RATE_36M_MASK | \
|
||||
IWL_RATE_48M_MASK | \
|
||||
IWL_RATE_54M_MASK)
|
||||
|
||||
#define IWL_BASIC_RATES_MASK \
|
||||
(IWL_OFDM_BASIC_RATES_MASK | \
|
||||
IWL_CCK_BASIC_RATES_MASK)
|
||||
|
||||
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
|
||||
#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1)
|
||||
|
||||
#define IWL_INVALID_VALUE -1
|
||||
|
||||
#define IWL_MIN_RSSI_VAL -100
|
||||
#define IWL_MAX_RSSI_VAL 0
|
||||
|
||||
/* These values specify how many Tx frame attempts before
|
||||
* searching for a new modulation mode */
|
||||
#define IWL_LEGACY_FAILURE_LIMIT 160
|
||||
#define IWL_LEGACY_SUCCESS_LIMIT 480
|
||||
#define IWL_LEGACY_TABLE_COUNT 160
|
||||
|
||||
#define IWL_NONE_LEGACY_FAILURE_LIMIT 400
|
||||
#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500
|
||||
#define IWL_NONE_LEGACY_TABLE_COUNT 1500
|
||||
|
||||
/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
|
||||
#define IWL_RS_GOOD_RATIO 12800 /* 100% */
|
||||
#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */
|
||||
#define IWL_RATE_HIGH_TH 10880 /* 85% */
|
||||
#define IWL_RATE_INCREASE_TH 6400 /* 50% */
|
||||
#define IWL_RATE_DECREASE_TH 1920 /* 15% */
|
||||
|
||||
/* possible actions when in legacy mode */
|
||||
#define IWL_LEGACY_SWITCH_ANTENNA1 0
|
||||
#define IWL_LEGACY_SWITCH_ANTENNA2 1
|
||||
#define IWL_LEGACY_SWITCH_SISO 2
|
||||
#define IWL_LEGACY_SWITCH_MIMO2_AB 3
|
||||
#define IWL_LEGACY_SWITCH_MIMO2_AC 4
|
||||
#define IWL_LEGACY_SWITCH_MIMO2_BC 5
|
||||
|
||||
/* possible actions when in siso mode */
|
||||
#define IWL_SISO_SWITCH_ANTENNA1 0
|
||||
#define IWL_SISO_SWITCH_ANTENNA2 1
|
||||
#define IWL_SISO_SWITCH_MIMO2_AB 2
|
||||
#define IWL_SISO_SWITCH_MIMO2_AC 3
|
||||
#define IWL_SISO_SWITCH_MIMO2_BC 4
|
||||
#define IWL_SISO_SWITCH_GI 5
|
||||
|
||||
/* possible actions when in mimo mode */
|
||||
#define IWL_MIMO2_SWITCH_ANTENNA1 0
|
||||
#define IWL_MIMO2_SWITCH_ANTENNA2 1
|
||||
#define IWL_MIMO2_SWITCH_SISO_A 2
|
||||
#define IWL_MIMO2_SWITCH_SISO_B 3
|
||||
#define IWL_MIMO2_SWITCH_SISO_C 4
|
||||
#define IWL_MIMO2_SWITCH_GI 5
|
||||
|
||||
#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_GI
|
||||
|
||||
#define IWL_ACTION_LIMIT 3 /* # possible actions */
|
||||
|
||||
#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */
|
||||
|
||||
/* load per tid defines for A-MPDU activation */
|
||||
#define IWL_AGG_TPT_THREHOLD 0
|
||||
#define IWL_AGG_LOAD_THRESHOLD 10
|
||||
#define IWL_AGG_ALL_TID 0xff
|
||||
#define TID_QUEUE_CELL_SPACING 50 /*mS */
|
||||
#define TID_QUEUE_MAX_SIZE 20
|
||||
#define TID_ROUND_VALUE 5 /* mS */
|
||||
#define TID_MAX_LOAD_COUNT 8
|
||||
|
||||
#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
|
||||
#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
|
||||
|
||||
extern const struct iwl_rate_info iwlegacy_rates[IWL_RATE_COUNT];
|
||||
|
||||
enum iwl_table_type {
|
||||
LQ_NONE,
|
||||
LQ_G, /* legacy types */
|
||||
LQ_A,
|
||||
LQ_SISO, /* high-throughput types */
|
||||
LQ_MIMO2,
|
||||
LQ_MAX,
|
||||
};
|
||||
|
||||
#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
|
||||
#define is_siso(tbl) ((tbl) == LQ_SISO)
|
||||
#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
|
||||
#define is_mimo(tbl) (is_mimo2(tbl))
|
||||
#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
|
||||
#define is_a_band(tbl) ((tbl) == LQ_A)
|
||||
#define is_g_and(tbl) ((tbl) == LQ_G)
|
||||
|
||||
#define ANT_NONE 0x0
|
||||
#define ANT_A BIT(0)
|
||||
#define ANT_B BIT(1)
|
||||
#define ANT_AB (ANT_A | ANT_B)
|
||||
#define ANT_C BIT(2)
|
||||
#define ANT_AC (ANT_A | ANT_C)
|
||||
#define ANT_BC (ANT_B | ANT_C)
|
||||
#define ANT_ABC (ANT_AB | ANT_C)
|
||||
|
||||
#define IWL_MAX_MCS_DISPLAY_SIZE 12
|
||||
|
||||
struct iwl_rate_mcs_info {
|
||||
char mbps[IWL_MAX_MCS_DISPLAY_SIZE];
|
||||
char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_rate_scale_data -- tx success history for one rate
|
||||
*/
|
||||
struct iwl_rate_scale_data {
|
||||
u64 data; /* bitmap of successful frames */
|
||||
s32 success_counter; /* number of frames successful */
|
||||
s32 success_ratio; /* per-cent * 128 */
|
||||
s32 counter; /* number of frames attempted */
|
||||
s32 average_tpt; /* success ratio * expected throughput */
|
||||
unsigned long stamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_scale_tbl_info -- tx params and success history for all rates
|
||||
*
|
||||
* There are two of these in struct iwl_lq_sta,
|
||||
* one for "active", and one for "search".
|
||||
*/
|
||||
struct iwl_scale_tbl_info {
|
||||
enum iwl_table_type lq_type;
|
||||
u8 ant_type;
|
||||
u8 is_SGI; /* 1 = short guard interval */
|
||||
u8 is_ht40; /* 1 = 40 MHz channel width */
|
||||
u8 is_dup; /* 1 = duplicated data streams */
|
||||
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
|
||||
u8 max_search; /* maximun number of tables we can search */
|
||||
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
|
||||
u32 current_rate; /* rate_n_flags, uCode API format */
|
||||
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
|
||||
};
|
||||
|
||||
struct iwl_traffic_load {
|
||||
unsigned long time_stamp; /* age of the oldest statistics */
|
||||
u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
|
||||
* slice */
|
||||
u32 total; /* total num of packets during the
|
||||
* last TID_MAX_TIME_DIFF */
|
||||
u8 queue_count; /* number of queues that has
|
||||
* been used since the last cleanup */
|
||||
u8 head; /* start of the circular buffer */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_lq_sta -- driver's rate scaling private structure
|
||||
*
|
||||
* Pointer to this gets passed back and forth between driver and mac80211.
|
||||
*/
|
||||
struct iwl_lq_sta {
|
||||
u8 active_tbl; /* index of active table, range 0-1 */
|
||||
u8 enable_counter; /* indicates HT mode */
|
||||
u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
|
||||
u8 search_better_tbl; /* 1: currently trying alternate mode */
|
||||
s32 last_tpt;
|
||||
|
||||
/* The following determine when to search for a new mode */
|
||||
u32 table_count_limit;
|
||||
u32 max_failure_limit; /* # failed frames before new search */
|
||||
u32 max_success_limit; /* # successful frames before new search */
|
||||
u32 table_count;
|
||||
u32 total_failed; /* total failed frames, any/all rates */
|
||||
u32 total_success; /* total successful frames, any/all rates */
|
||||
u64 flush_timer; /* time staying in mode before new search */
|
||||
|
||||
u8 action_counter; /* # mode-switch actions tried */
|
||||
u8 is_green;
|
||||
u8 is_dup;
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
|
||||
u32 supp_rates;
|
||||
u16 active_legacy_rate;
|
||||
u16 active_siso_rate;
|
||||
u16 active_mimo2_rate;
|
||||
s8 max_rate_idx; /* Max rate set by user */
|
||||
u8 missed_rate_counter;
|
||||
|
||||
struct iwl_link_quality_cmd lq;
|
||||
struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
|
||||
struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
|
||||
u8 tx_agg_tid_en;
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
struct dentry *rs_sta_dbgfs_scale_table_file;
|
||||
struct dentry *rs_sta_dbgfs_stats_table_file;
|
||||
struct dentry *rs_sta_dbgfs_rate_scale_data_file;
|
||||
struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
|
||||
u32 dbg_fixed_rate;
|
||||
#endif
|
||||
struct iwl_priv *drv;
|
||||
|
||||
/* used to be in sta_info */
|
||||
int last_txrate_idx;
|
||||
/* last tx rate_n_flags */
|
||||
u32 last_rate_n_flags;
|
||||
/* packets destined for this STA are aggregated */
|
||||
u8 is_agg;
|
||||
};
|
||||
|
||||
static inline u8 iwl4965_num_of_ant(u8 mask)
|
||||
{
|
||||
return !!((mask) & ANT_A) +
|
||||
!!((mask) & ANT_B) +
|
||||
!!((mask) & ANT_C);
|
||||
}
|
||||
|
||||
static inline u8 iwl4965_first_antenna(u8 mask)
|
||||
{
|
||||
if (mask & ANT_A)
|
||||
return ANT_A;
|
||||
if (mask & ANT_B)
|
||||
return ANT_B;
|
||||
return ANT_C;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
|
||||
*
|
||||
* The specific throughput table used is based on the type of network
|
||||
* the associated with, including A, B, G, and G w/ TGG protection
|
||||
*/
|
||||
extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
|
||||
|
||||
/* Initialize station's rate scaling information after adding station */
|
||||
extern void iwl4965_rs_rate_init(struct iwl_priv *priv,
|
||||
struct ieee80211_sta *sta, u8 sta_id);
|
||||
extern void iwl3945_rs_rate_init(struct iwl_priv *priv,
|
||||
struct ieee80211_sta *sta, u8 sta_id);
|
||||
|
||||
/**
|
||||
* iwl_rate_control_register - Register the rate control algorithm callbacks
|
||||
*
|
||||
* Since the rate control algorithm is hardware specific, there is no need
|
||||
* or reason to place it as a stand alone module. The driver can call
|
||||
* iwl_rate_control_register in order to register the rate control callbacks
|
||||
* with the mac80211 subsystem. This should be performed prior to calling
|
||||
* ieee80211_register_hw
|
||||
*
|
||||
*/
|
||||
extern int iwl4965_rate_control_register(void);
|
||||
extern int iwl3945_rate_control_register(void);
|
||||
|
||||
/**
|
||||
* iwl_rate_control_unregister - Unregister the rate control callbacks
|
||||
*
|
||||
* This should be called after calling ieee80211_unregister_hw, but before
|
||||
* the driver is unloaded.
|
||||
*/
|
||||
extern void iwl4965_rate_control_unregister(void);
|
||||
extern void iwl3945_rate_control_unregister(void);
|
||||
|
||||
#endif /* __iwl_legacy_rs__ */
|
|
@ -0,0 +1,165 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2007 - 2011 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-power.h"
|
||||
|
||||
/*
|
||||
* Setting power level allows the card to go to sleep when not busy.
|
||||
*
|
||||
* We calculate a sleep command based on the required latency, which
|
||||
* we get from mac80211. In order to handle thermal throttling, we can
|
||||
* also use pre-defined power levels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This defines the old power levels. They are still used by default
|
||||
* (level 1) and for thermal throttle (levels 3 through 5)
|
||||
*/
|
||||
|
||||
struct iwl_power_vec_entry {
|
||||
struct iwl_powertable_cmd cmd;
|
||||
u8 no_dtim; /* number of skip dtim */
|
||||
};
|
||||
|
||||
static void iwl_legacy_power_sleep_cam_cmd(struct iwl_priv *priv,
|
||||
struct iwl_powertable_cmd *cmd)
|
||||
{
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (priv->power_data.pci_pm)
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
|
||||
IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_legacy_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
|
||||
{
|
||||
IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
|
||||
IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
|
||||
IWL_DEBUG_POWER(priv, "Tx timeout = %u\n",
|
||||
le32_to_cpu(cmd->tx_data_timeout));
|
||||
IWL_DEBUG_POWER(priv, "Rx timeout = %u\n",
|
||||
le32_to_cpu(cmd->rx_data_timeout));
|
||||
IWL_DEBUG_POWER(priv,
|
||||
"Sleep interval vector = { %d , %d , %d , %d , %d }\n",
|
||||
le32_to_cpu(cmd->sleep_interval[0]),
|
||||
le32_to_cpu(cmd->sleep_interval[1]),
|
||||
le32_to_cpu(cmd->sleep_interval[2]),
|
||||
le32_to_cpu(cmd->sleep_interval[3]),
|
||||
le32_to_cpu(cmd->sleep_interval[4]));
|
||||
|
||||
return iwl_legacy_send_cmd_pdu(priv, POWER_TABLE_CMD,
|
||||
sizeof(struct iwl_powertable_cmd), cmd);
|
||||
}
|
||||
|
||||
int
|
||||
iwl_legacy_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
|
||||
bool force)
|
||||
{
|
||||
int ret;
|
||||
bool update_chains;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
/* Don't update the RX chain when chain noise calibration is running */
|
||||
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
|
||||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
|
||||
|
||||
if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
|
||||
return 0;
|
||||
|
||||
if (!iwl_legacy_is_ready_rf(priv))
|
||||
return -EIO;
|
||||
|
||||
/* scan complete use sleep_power_next, need to be updated */
|
||||
memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
|
||||
if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
|
||||
IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
|
||||
set_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
ret = iwl_legacy_set_power(priv, cmd);
|
||||
if (!ret) {
|
||||
if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
|
||||
clear_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
if (priv->cfg->ops->lib->update_chain_flags && update_chains)
|
||||
priv->cfg->ops->lib->update_chain_flags(priv);
|
||||
else if (priv->cfg->ops->lib->update_chain_flags)
|
||||
IWL_DEBUG_POWER(priv,
|
||||
"Cannot update the power, chain noise "
|
||||
"calibration running: %d\n",
|
||||
priv->chain_noise_data.state);
|
||||
|
||||
memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
|
||||
} else
|
||||
IWL_ERR(priv, "set power fail, ret = %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_legacy_power_update_mode(struct iwl_priv *priv, bool force)
|
||||
{
|
||||
struct iwl_powertable_cmd cmd;
|
||||
|
||||
iwl_legacy_power_sleep_cam_cmd(priv, &cmd);
|
||||
return iwl_legacy_power_set_mode(priv, &cmd, force);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_power_update_mode);
|
||||
|
||||
/* initialize to default */
|
||||
void iwl_legacy_power_initialize(struct iwl_priv *priv)
|
||||
{
|
||||
u16 lctl = iwl_legacy_pcie_link_ctl(priv);
|
||||
|
||||
priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
|
||||
|
||||
priv->power_data.debug_sleep_level_override = -1;
|
||||
|
||||
memset(&priv->power_data.sleep_cmd, 0,
|
||||
sizeof(priv->power_data.sleep_cmd));
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_power_initialize);
|
|
@ -0,0 +1,55 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2007 - 2011 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_legacy_power_setting_h__
|
||||
#define __iwl_legacy_power_setting_h__
|
||||
|
||||
#include "iwl-commands.h"
|
||||
|
||||
enum iwl_power_level {
|
||||
IWL_POWER_INDEX_1,
|
||||
IWL_POWER_INDEX_2,
|
||||
IWL_POWER_INDEX_3,
|
||||
IWL_POWER_INDEX_4,
|
||||
IWL_POWER_INDEX_5,
|
||||
IWL_POWER_NUM
|
||||
};
|
||||
|
||||
struct iwl_power_mgr {
|
||||
struct iwl_powertable_cmd sleep_cmd;
|
||||
struct iwl_powertable_cmd sleep_cmd_next;
|
||||
int debug_sleep_level_override;
|
||||
bool pci_pm;
|
||||
};
|
||||
|
||||
int
|
||||
iwl_legacy_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
|
||||
bool force);
|
||||
int iwl_legacy_power_update_mode(struct iwl_priv *priv, bool force);
|
||||
void iwl_legacy_power_initialize(struct iwl_priv *priv);
|
||||
|
||||
#endif /* __iwl_legacy_power_setting_h__ */
|
|
@ -0,0 +1,523 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __iwl_legacy_prph_h__
|
||||
#define __iwl_legacy_prph_h__
|
||||
|
||||
/*
|
||||
* Registers in this file are internal, not PCI bus memory mapped.
|
||||
* Driver accesses these via HBUS_TARG_PRPH_* registers.
|
||||
*/
|
||||
#define PRPH_BASE (0x00000)
|
||||
#define PRPH_END (0xFFFFF)
|
||||
|
||||
/* APMG (power management) constants */
|
||||
#define APMG_BASE (PRPH_BASE + 0x3000)
|
||||
#define APMG_CLK_CTRL_REG (APMG_BASE + 0x0000)
|
||||
#define APMG_CLK_EN_REG (APMG_BASE + 0x0004)
|
||||
#define APMG_CLK_DIS_REG (APMG_BASE + 0x0008)
|
||||
#define APMG_PS_CTRL_REG (APMG_BASE + 0x000c)
|
||||
#define APMG_PCIDEV_STT_REG (APMG_BASE + 0x0010)
|
||||
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
|
||||
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
|
||||
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
|
||||
#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
|
||||
#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
|
||||
|
||||
#define APMS_CLK_VAL_MRB_FUNC_MODE (0x00000001)
|
||||
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
|
||||
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
|
||||
|
||||
#define APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000)
|
||||
#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
|
||||
#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
|
||||
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
|
||||
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
|
||||
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
|
||||
#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
|
||||
#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
|
||||
|
||||
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
|
||||
|
||||
/**
|
||||
* BSM (Bootstrap State Machine)
|
||||
*
|
||||
* The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
|
||||
* in special SRAM that does not power down when the embedded control
|
||||
* processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
|
||||
*
|
||||
* When powering back up after sleeps (or during initial uCode load), the BSM
|
||||
* internally loads the short bootstrap program from the special SRAM into the
|
||||
* embedded processor's instruction SRAM, and starts the processor so it runs
|
||||
* the bootstrap program.
|
||||
*
|
||||
* This bootstrap program loads (via PCI busmaster DMA) instructions and data
|
||||
* images for a uCode program from host DRAM locations. The host driver
|
||||
* indicates DRAM locations and sizes for instruction and data images via the
|
||||
* four BSM_DRAM_* registers. Once the bootstrap program loads the new program,
|
||||
* the new program starts automatically.
|
||||
*
|
||||
* The uCode used for open-source drivers includes two programs:
|
||||
*
|
||||
* 1) Initialization -- performs hardware calibration and sets up some
|
||||
* internal data, then notifies host via "initialize alive" notification
|
||||
* (struct iwl_init_alive_resp) that it has completed all of its work.
|
||||
* After signal from host, it then loads and starts the runtime program.
|
||||
* The initialization program must be used when initially setting up the
|
||||
* NIC after loading the driver.
|
||||
*
|
||||
* 2) Runtime/Protocol -- performs all normal runtime operations. This
|
||||
* notifies host via "alive" notification (struct iwl_alive_resp) that it
|
||||
* is ready to be used.
|
||||
*
|
||||
* When initializing the NIC, the host driver does the following procedure:
|
||||
*
|
||||
* 1) Load bootstrap program (instructions only, no data image for bootstrap)
|
||||
* into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND
|
||||
*
|
||||
* 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
|
||||
* images in host DRAM.
|
||||
*
|
||||
* 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
|
||||
* BSM_WR_MEM_SRC_REG = 0
|
||||
* BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
|
||||
* BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
|
||||
*
|
||||
* 4) Load bootstrap into instruction SRAM:
|
||||
* BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
|
||||
*
|
||||
* 5) Wait for load completion:
|
||||
* Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
|
||||
*
|
||||
* 6) Enable future boot loads whenever NIC's power management triggers it:
|
||||
* BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
|
||||
*
|
||||
* 7) Start the NIC by removing all reset bits:
|
||||
* CSR_RESET = 0
|
||||
*
|
||||
* The bootstrap uCode (already in instruction SRAM) loads initialization
|
||||
* uCode. Initialization uCode performs data initialization, sends
|
||||
* "initialize alive" notification to host, and waits for a signal from
|
||||
* host to load runtime code.
|
||||
*
|
||||
* 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
|
||||
* images in host DRAM. The last register loaded must be the instruction
|
||||
* byte count register ("1" in MSbit tells initialization uCode to load
|
||||
* the runtime uCode):
|
||||
* BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD
|
||||
*
|
||||
* 5) Wait for "alive" notification, then issue normal runtime commands.
|
||||
*
|
||||
* Data caching during power-downs:
|
||||
*
|
||||
* Just before the embedded controller powers down (e.g for automatic
|
||||
* power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
|
||||
* a current snapshot of the embedded processor's data SRAM into host DRAM.
|
||||
* This caches the data while the embedded processor's memory is powered down.
|
||||
* Location and size are controlled by BSM_DRAM_DATA_* registers.
|
||||
*
|
||||
* NOTE: Instruction SRAM does not need to be saved, since that doesn't
|
||||
* change during operation; the original image (from uCode distribution
|
||||
* file) can be used for reload.
|
||||
*
|
||||
* When powering back up, the BSM loads the bootstrap program. Bootstrap looks
|
||||
* at the BSM_DRAM_* registers, which now point to the runtime instruction
|
||||
* image and the cached (modified) runtime data (*not* the initialization
|
||||
* uCode). Bootstrap reloads these runtime images into SRAM, and restarts the
|
||||
* uCode from where it left off before the power-down.
|
||||
*
|
||||
* NOTE: Initialization uCode does *not* run as part of the save/restore
|
||||
* procedure.
|
||||
*
|
||||
* This save/restore method is mostly for autonomous power management during
|
||||
* normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and
|
||||
* RFKILL should use complete restarts (with total re-initialization) of uCode,
|
||||
* allowing total shutdown (including BSM memory).
|
||||
*
|
||||
* Note that, during normal operation, the host DRAM that held the initial
|
||||
* startup data for the runtime code is now being used as a backup data cache
|
||||
* for modified data! If you need to completely re-initialize the NIC, make
|
||||
* sure that you use the runtime data image from the uCode distribution file,
|
||||
* not the modified/saved runtime data. You may want to store a separate
|
||||
* "clean" runtime data image in DRAM to avoid disk reads of distribution file.
|
||||
*/
|
||||
|
||||
/* BSM bit fields */
|
||||
#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */
|
||||
#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/
|
||||
#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */
|
||||
|
||||
/* BSM addresses */
|
||||
#define BSM_BASE (PRPH_BASE + 0x3400)
|
||||
#define BSM_END (PRPH_BASE + 0x3800)
|
||||
|
||||
#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */
|
||||
#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */
|
||||
#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */
|
||||
#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */
|
||||
#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */
|
||||
|
||||
/*
|
||||
* Pointers and size regs for bootstrap load and data SRAM save/restore.
|
||||
* NOTE: 3945 pointers use bits 31:0 of DRAM address.
|
||||
* 4965 pointers use bits 35:4 of DRAM address.
|
||||
*/
|
||||
#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090)
|
||||
#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094)
|
||||
#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098)
|
||||
#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C)
|
||||
|
||||
/*
|
||||
* BSM special memory, stays powered on during power-save sleeps.
|
||||
* Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
|
||||
*/
|
||||
#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800)
|
||||
#define BSM_SRAM_SIZE (1024) /* bytes */
|
||||
|
||||
|
||||
/* 3945 Tx scheduler registers */
|
||||
#define ALM_SCD_BASE (PRPH_BASE + 0x2E00)
|
||||
#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000)
|
||||
#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004)
|
||||
#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010)
|
||||
#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014)
|
||||
#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020)
|
||||
#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C)
|
||||
#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030)
|
||||
|
||||
/**
|
||||
* Tx Scheduler
|
||||
*
|
||||
* The Tx Scheduler selects the next frame to be transmitted, choosing TFDs
|
||||
* (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
|
||||
* host DRAM. It steers each frame's Tx command (which contains the frame
|
||||
* data) into one of up to 7 prioritized Tx DMA FIFO channels within the
|
||||
* device. A queue maps to only one (selectable by driver) Tx DMA channel,
|
||||
* but one DMA channel may take input from several queues.
|
||||
*
|
||||
* Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows
|
||||
* (cf. default_queue_to_tx_fifo in iwl-4965.c):
|
||||
*
|
||||
* 0 -- EDCA BK (background) frames, lowest priority
|
||||
* 1 -- EDCA BE (best effort) frames, normal priority
|
||||
* 2 -- EDCA VI (video) frames, higher priority
|
||||
* 3 -- EDCA VO (voice) and management frames, highest priority
|
||||
* 4 -- Commands (e.g. RXON, etc.)
|
||||
* 5 -- unused (HCCA)
|
||||
* 6 -- unused (HCCA)
|
||||
* 7 -- not used by driver (device-internal only)
|
||||
*
|
||||
*
|
||||
* Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
|
||||
* In addition, driver can map the remaining queues to Tx DMA/FIFO
|
||||
* channels 0-3 to support 11n aggregation via EDCA DMA channels.
|
||||
*
|
||||
* The driver sets up each queue to work in one of two modes:
|
||||
*
|
||||
* 1) Scheduler-Ack, in which the scheduler automatically supports a
|
||||
* block-ack (BA) window of up to 64 TFDs. In this mode, each queue
|
||||
* contains TFDs for a unique combination of Recipient Address (RA)
|
||||
* and Traffic Identifier (TID), that is, traffic of a given
|
||||
* Quality-Of-Service (QOS) priority, destined for a single station.
|
||||
*
|
||||
* In scheduler-ack mode, the scheduler keeps track of the Tx status of
|
||||
* each frame within the BA window, including whether it's been transmitted,
|
||||
* and whether it's been acknowledged by the receiving station. The device
|
||||
* automatically processes block-acks received from the receiving STA,
|
||||
* and reschedules un-acked frames to be retransmitted (successful
|
||||
* Tx completion may end up being out-of-order).
|
||||
*
|
||||
* The driver must maintain the queue's Byte Count table in host DRAM
|
||||
* (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
|
||||
* This mode does not support fragmentation.
|
||||
*
|
||||
* 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
|
||||
* The device may automatically retry Tx, but will retry only one frame
|
||||
* at a time, until receiving ACK from receiving station, or reaching
|
||||
* retry limit and giving up.
|
||||
*
|
||||
* The command queue (#4/#9) must use this mode!
|
||||
* This mode does not require use of the Byte Count table in host DRAM.
|
||||
*
|
||||
* Driver controls scheduler operation via 3 means:
|
||||
* 1) Scheduler registers
|
||||
* 2) Shared scheduler data base in internal 4956 SRAM
|
||||
* 3) Shared data in host DRAM
|
||||
*
|
||||
* Initialization:
|
||||
*
|
||||
* When loading, driver should allocate memory for:
|
||||
* 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs.
|
||||
* 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory
|
||||
* (1024 bytes for each queue).
|
||||
*
|
||||
* After receiving "Alive" response from uCode, driver must initialize
|
||||
* the scheduler (especially for queue #4/#9, the command queue, otherwise
|
||||
* the driver can't issue commands!):
|
||||
*/
|
||||
|
||||
/**
|
||||
* Max Tx window size is the max number of contiguous TFDs that the scheduler
|
||||
* can keep track of at one time when creating block-ack chains of frames.
|
||||
* Note that "64" matches the number of ack bits in a block-ack packet.
|
||||
* Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
|
||||
* IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values.
|
||||
*/
|
||||
#define SCD_WIN_SIZE 64
|
||||
#define SCD_FRAME_LIMIT 64
|
||||
|
||||
/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
|
||||
#define IWL49_SCD_START_OFFSET 0xa02c00
|
||||
|
||||
/*
|
||||
* 4965 tells driver SRAM address for internal scheduler structs via this reg.
|
||||
* Value is valid only after "Alive" response from uCode.
|
||||
*/
|
||||
#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0)
|
||||
|
||||
/*
|
||||
* Driver may need to update queue-empty bits after changing queue's
|
||||
* write and read pointers (indexes) during (re-)initialization (i.e. when
|
||||
* scheduler is not tracking what's happening).
|
||||
* Bit fields:
|
||||
* 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit
|
||||
* 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty
|
||||
* NOTE: This register is not used by Linux driver.
|
||||
*/
|
||||
#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4)
|
||||
|
||||
/*
|
||||
* Physical base address of array of byte count (BC) circular buffers (CBs).
|
||||
* Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
|
||||
* This register points to BC CB for queue 0, must be on 1024-byte boundary.
|
||||
* Others are spaced by 1024 bytes.
|
||||
* Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
|
||||
* (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
|
||||
* Bit fields:
|
||||
* 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned.
|
||||
*/
|
||||
#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10)
|
||||
|
||||
/*
|
||||
* Enables any/all Tx DMA/FIFO channels.
|
||||
* Scheduler generates requests for only the active channels.
|
||||
* Set this to 0xff to enable all 8 channels (normal usage).
|
||||
* Bit fields:
|
||||
* 7- 0: Enable (1), disable (0), one bit for each channel 0-7
|
||||
*/
|
||||
#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c)
|
||||
/*
|
||||
* Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
|
||||
* Initialized and updated by driver as new TFDs are added to queue.
|
||||
* NOTE: If using Block Ack, index must correspond to frame's
|
||||
* Start Sequence Number; index = (SSN & 0xff)
|
||||
* NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
|
||||
*/
|
||||
#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4)
|
||||
|
||||
/*
|
||||
* Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
|
||||
* For FIFO mode, index indicates next frame to transmit.
|
||||
* For Scheduler-ACK mode, index indicates first frame in Tx window.
|
||||
* Initialized by driver, updated by scheduler.
|
||||
*/
|
||||
#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4)
|
||||
|
||||
/*
|
||||
* Select which queues work in chain mode (1) vs. not (0).
|
||||
* Use chain mode to build chains of aggregated frames.
|
||||
* Bit fields:
|
||||
* 31-16: Reserved
|
||||
* 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
|
||||
* NOTE: If driver sets up queue for chain mode, it should be also set up
|
||||
* Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
|
||||
*/
|
||||
#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0)
|
||||
|
||||
/*
|
||||
* Select which queues interrupt driver when scheduler increments
|
||||
* a queue's read pointer (index).
|
||||
* Bit fields:
|
||||
* 31-16: Reserved
|
||||
* 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
|
||||
* NOTE: This functionality is apparently a no-op; driver relies on interrupts
|
||||
* from Rx queue to read Tx command responses and update Tx queues.
|
||||
*/
|
||||
#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4)
|
||||
|
||||
/*
|
||||
* Queue search status registers. One for each queue.
|
||||
* Sets up queue mode and assigns queue to Tx DMA channel.
|
||||
* Bit fields:
|
||||
* 19-10: Write mask/enable bits for bits 0-9
|
||||
* 9: Driver should init to "0"
|
||||
* 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
|
||||
* Driver should init to "1" for aggregation mode, or "0" otherwise.
|
||||
* 7-6: Driver should init to "0"
|
||||
* 5: Window Size Left; indicates whether scheduler can request
|
||||
* another TFD, based on window size, etc. Driver should init
|
||||
* this bit to "1" for aggregation mode, or "0" for non-agg.
|
||||
* 4-1: Tx FIFO to use (range 0-7).
|
||||
* 0: Queue is active (1), not active (0).
|
||||
* Other bits should be written as "0"
|
||||
*
|
||||
* NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled
|
||||
* via SCD_QUEUECHAIN_SEL.
|
||||
*/
|
||||
#define IWL49_SCD_QUEUE_STATUS_BITS(x)\
|
||||
(IWL49_SCD_START_OFFSET + 0x104 + (x) * 4)
|
||||
|
||||
/* Bit field positions */
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0)
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1)
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5)
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8)
|
||||
|
||||
/* Write masks */
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10)
|
||||
#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00)
|
||||
|
||||
/**
|
||||
* 4965 internal SRAM structures for scheduler, shared with driver ...
|
||||
*
|
||||
* Driver should clear and initialize the following areas after receiving
|
||||
* "Alive" response from 4965 uCode, i.e. after initial
|
||||
* uCode load, or after a uCode load done for error recovery:
|
||||
*
|
||||
* SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
|
||||
* SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
|
||||
* SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
|
||||
*
|
||||
* Driver accesses SRAM via HBUS_TARG_MEM_* registers.
|
||||
* Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
|
||||
* All OFFSET values must be added to this base address.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Queue context. One 8-byte entry for each of 16 queues.
|
||||
*
|
||||
* Driver should clear this entire area (size 0x80) to 0 after receiving
|
||||
* "Alive" notification from uCode. Additionally, driver should init
|
||||
* each queue's entry as follows:
|
||||
*
|
||||
* LS Dword bit fields:
|
||||
* 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64.
|
||||
*
|
||||
* MS Dword bit fields:
|
||||
* 16-22: Frame limit. Driver should init to 10 (0xa).
|
||||
*
|
||||
* Driver should init all other bits to 0.
|
||||
*
|
||||
* Init must be done after driver receives "Alive" response from 4965 uCode,
|
||||
* and when setting up queue for aggregation.
|
||||
*/
|
||||
#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380
|
||||
#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \
|
||||
(IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
|
||||
|
||||
#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0)
|
||||
#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F)
|
||||
#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
|
||||
#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
|
||||
|
||||
/*
|
||||
* Tx Status Bitmap
|
||||
*
|
||||
* Driver should clear this entire area (size 0x100) to 0 after receiving
|
||||
* "Alive" notification from uCode. Area is used only by device itself;
|
||||
* no other support (besides clearing) is required from driver.
|
||||
*/
|
||||
#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400
|
||||
|
||||
/*
|
||||
* RAxTID to queue translation mapping.
|
||||
*
|
||||
* When queue is in Scheduler-ACK mode, frames placed in a that queue must be
|
||||
* for only one combination of receiver address (RA) and traffic ID (TID), i.e.
|
||||
* one QOS priority level destined for one station (for this wireless link,
|
||||
* not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit
|
||||
* mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK
|
||||
* mode, the device ignores the mapping value.
|
||||
*
|
||||
* Bit fields, for each 16-bit map:
|
||||
* 15-9: Reserved, set to 0
|
||||
* 8-4: Index into device's station table for recipient station
|
||||
* 3-0: Traffic ID (tid), range 0-15
|
||||
*
|
||||
* Driver should clear this entire area (size 32 bytes) to 0 after receiving
|
||||
* "Alive" notification from uCode. To update a 16-bit map value, driver
|
||||
* must read a dword-aligned value from device SRAM, replace the 16-bit map
|
||||
* value of interest, and write the dword value back into device SRAM.
|
||||
*/
|
||||
#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500
|
||||
|
||||
/* Find translation table dword to read/write for given queue */
|
||||
#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
|
||||
((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
|
||||
|
||||
#define IWL_SCD_TXFIFO_POS_TID (0)
|
||||
#define IWL_SCD_TXFIFO_POS_RA (4)
|
||||
#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
|
||||
|
||||
/*********************** END TX SCHEDULER *************************************/
|
||||
|
||||
#endif /* __iwl_legacy_prph_h__ */
|
|
@ -0,0 +1,302 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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/etherdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
/************************** RX-FUNCTIONS ****************************/
|
||||
/*
|
||||
* Rx theory of operation
|
||||
*
|
||||
* Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
|
||||
* each of which point to Receive Buffers to be filled by the NIC. These get
|
||||
* used not only for Rx frames, but for any command response or notification
|
||||
* from the NIC. The driver and NIC manage the Rx buffers by means
|
||||
* of indexes into the circular buffer.
|
||||
*
|
||||
* Rx Queue Indexes
|
||||
* The host/firmware share two index registers for managing the Rx buffers.
|
||||
*
|
||||
* The READ index maps to the first position that the firmware may be writing
|
||||
* to -- the driver can read up to (but not including) this position and get
|
||||
* good data.
|
||||
* The READ index is managed by the firmware once the card is enabled.
|
||||
*
|
||||
* The WRITE index maps to the last position the driver has read from -- the
|
||||
* position preceding WRITE is the last slot the firmware can place a packet.
|
||||
*
|
||||
* The queue is empty (no good data) if WRITE = READ - 1, and is full if
|
||||
* WRITE = READ.
|
||||
*
|
||||
* During initialization, the host sets up the READ queue position to the first
|
||||
* INDEX position, and WRITE to the last (READ - 1 wrapped)
|
||||
*
|
||||
* When the firmware places a packet in a buffer, it will advance the READ index
|
||||
* and fire the RX interrupt. The driver can then query the READ index and
|
||||
* process as many packets as possible, moving the WRITE index forward as it
|
||||
* resets the Rx queue buffers with new memory.
|
||||
*
|
||||
* The management in the driver is as follows:
|
||||
* + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
|
||||
* iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
|
||||
* to replenish the iwl->rxq->rx_free.
|
||||
* + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
|
||||
* iwl->rxq is replenished and the READ INDEX is updated (updating the
|
||||
* 'processed' and 'read' driver indexes as well)
|
||||
* + A received packet is processed and handed to the kernel network stack,
|
||||
* detached from the iwl->rxq. The driver 'processed' index is updated.
|
||||
* + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
|
||||
* list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
|
||||
* INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
|
||||
* were enough free buffers and RX_STALLED is set it is cleared.
|
||||
*
|
||||
*
|
||||
* Driver sequence:
|
||||
*
|
||||
* iwl_legacy_rx_queue_alloc() Allocates rx_free
|
||||
* iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
|
||||
* iwl_rx_queue_restock
|
||||
* iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
|
||||
* queue, updates firmware pointers, and updates
|
||||
* the WRITE index. If insufficient rx_free buffers
|
||||
* are available, schedules iwl_rx_replenish
|
||||
*
|
||||
* -- enable interrupts --
|
||||
* ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
|
||||
* READ INDEX, detaching the SKB from the pool.
|
||||
* Moves the packet buffer from queue to rx_used.
|
||||
* Calls iwl_rx_queue_restock to refill any empty
|
||||
* slots.
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* iwl_legacy_rx_queue_space - Return number of free slots available in queue.
|
||||
*/
|
||||
int iwl_legacy_rx_queue_space(const struct iwl_rx_queue *q)
|
||||
{
|
||||
int s = q->read - q->write;
|
||||
if (s <= 0)
|
||||
s += RX_QUEUE_SIZE;
|
||||
/* keep some buffer to not confuse full and empty queue */
|
||||
s -= 2;
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
return s;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_rx_queue_space);
|
||||
|
||||
/**
|
||||
* iwl_legacy_rx_queue_update_write_ptr - Update the write pointer for the RX queue
|
||||
*/
|
||||
void
|
||||
iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv,
|
||||
struct iwl_rx_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
|
||||
if (q->need_update == 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/* If power-saving is in use, make sure device is awake */
|
||||
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
|
||||
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
||||
|
||||
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Rx queue requesting wakeup,"
|
||||
" GP1 = 0x%x\n", reg);
|
||||
iwl_legacy_set_bit(priv, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
q->write_actual = (q->write & ~0x7);
|
||||
iwl_legacy_write_direct32(priv, rx_wrt_ptr_reg,
|
||||
q->write_actual);
|
||||
|
||||
/* Else device is assumed to be awake */
|
||||
} else {
|
||||
/* Device expects a multiple of 8 */
|
||||
q->write_actual = (q->write & ~0x7);
|
||||
iwl_legacy_write_direct32(priv, rx_wrt_ptr_reg,
|
||||
q->write_actual);
|
||||
}
|
||||
|
||||
q->need_update = 0;
|
||||
|
||||
exit_unlock:
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_rx_queue_update_write_ptr);
|
||||
|
||||
int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rx_queue *rxq = &priv->rxq;
|
||||
struct device *dev = &priv->pci_dev->dev;
|
||||
int i;
|
||||
|
||||
spin_lock_init(&rxq->lock);
|
||||
INIT_LIST_HEAD(&rxq->rx_free);
|
||||
INIT_LIST_HEAD(&rxq->rx_used);
|
||||
|
||||
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
|
||||
rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
|
||||
GFP_KERNEL);
|
||||
if (!rxq->bd)
|
||||
goto err_bd;
|
||||
|
||||
rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
|
||||
&rxq->rb_stts_dma, GFP_KERNEL);
|
||||
if (!rxq->rb_stts)
|
||||
goto err_rb;
|
||||
|
||||
/* Fill the rx_used queue with _all_ of the Rx buffers */
|
||||
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
|
||||
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
|
||||
|
||||
/* Set us so that we have processed and used all buffers, but have
|
||||
* not restocked the Rx queue with fresh buffers */
|
||||
rxq->read = rxq->write = 0;
|
||||
rxq->write_actual = 0;
|
||||
rxq->free_count = 0;
|
||||
rxq->need_update = 0;
|
||||
return 0;
|
||||
|
||||
err_rb:
|
||||
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
|
||||
rxq->bd_dma);
|
||||
err_bd:
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_rx_queue_alloc);
|
||||
|
||||
|
||||
void iwl_legacy_rx_spectrum_measure_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
|
||||
|
||||
if (!report->state) {
|
||||
IWL_DEBUG_11H(priv,
|
||||
"Spectrum Measure Notification: Start\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&priv->measure_report, report, sizeof(*report));
|
||||
priv->measurement_status |= MEASUREMENT_READY;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_rx_spectrum_measure_notif);
|
||||
|
||||
void iwl_legacy_recover_from_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
if (iwl_legacy_is_any_associated(priv)) {
|
||||
if (priv->cfg->ops->lib->check_plcp_health) {
|
||||
if (!priv->cfg->ops->lib->check_plcp_health(
|
||||
priv, pkt)) {
|
||||
/*
|
||||
* high plcp error detected
|
||||
* reset Radio
|
||||
*/
|
||||
iwl_legacy_force_reset(priv,
|
||||
IWL_RF_RESET, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_recover_from_statistics);
|
||||
|
||||
/*
|
||||
* returns non-zero if packet should be dropped
|
||||
*/
|
||||
int iwl_legacy_set_decrypted_flag(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,
|
||||
u32 decrypt_res,
|
||||
struct ieee80211_rx_status *stats)
|
||||
{
|
||||
u16 fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
/*
|
||||
* All contexts have the same setting here due to it being
|
||||
* a module parameter, so OK to check any context.
|
||||
*/
|
||||
if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
|
||||
RXON_FILTER_DIS_DECRYPT_MSK)
|
||||
return 0;
|
||||
|
||||
if (!(fc & IEEE80211_FCTL_PROTECTED))
|
||||
return 0;
|
||||
|
||||
IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res);
|
||||
switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
|
||||
case RX_RES_STATUS_SEC_TYPE_TKIP:
|
||||
/* The uCode has got a bad phase 1 Key, pushes the packet.
|
||||
* Decryption will be done in SW. */
|
||||
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
|
||||
RX_RES_STATUS_BAD_KEY_TTAK)
|
||||
break;
|
||||
|
||||
case RX_RES_STATUS_SEC_TYPE_WEP:
|
||||
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
|
||||
RX_RES_STATUS_BAD_ICV_MIC) {
|
||||
/* bad ICV, the packet is destroyed since the
|
||||
* decryption is inplace, drop it */
|
||||
IWL_DEBUG_RX(priv, "Packet destroyed\n");
|
||||
return -1;
|
||||
}
|
||||
case RX_RES_STATUS_SEC_TYPE_CCMP:
|
||||
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
|
||||
RX_RES_STATUS_DECRYPT_OK) {
|
||||
IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
|
||||
stats->flag |= RX_FLAG_DECRYPTED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_set_decrypted_flag);
|
|
@ -0,0 +1,625 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*****************************************************************************/
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
|
||||
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
|
||||
* sending probe req. This should be set long enough to hear probe responses
|
||||
* from more than one AP. */
|
||||
#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
|
||||
#define IWL_ACTIVE_DWELL_TIME_52 (20)
|
||||
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
|
||||
|
||||
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
|
||||
* Must be set longer than active dwell time.
|
||||
* For the most reliable scan, set > AP beacon interval (typically 100msec). */
|
||||
#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
|
||||
#define IWL_PASSIVE_DWELL_TIME_52 (10)
|
||||
#define IWL_PASSIVE_DWELL_BASE (100)
|
||||
#define IWL_CHANNEL_TUNE_TIME 5
|
||||
|
||||
static int iwl_legacy_send_scan_abort(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
struct iwl_rx_packet *pkt;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_SCAN_ABORT_CMD,
|
||||
.flags = CMD_WANT_SKB,
|
||||
};
|
||||
|
||||
/* Exit instantly with error when device is not ready
|
||||
* to receive scan abort command or it does not perform
|
||||
* hardware scan currently */
|
||||
if (!test_bit(STATUS_READY, &priv->status) ||
|
||||
!test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
|
||||
!test_bit(STATUS_SCAN_HW, &priv->status) ||
|
||||
test_bit(STATUS_FW_ERROR, &priv->status) ||
|
||||
test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return -EIO;
|
||||
|
||||
ret = iwl_legacy_send_cmd_sync(priv, &cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pkt = (struct iwl_rx_packet *)cmd.reply_page;
|
||||
if (pkt->u.status != CAN_ABORT_STATUS) {
|
||||
/* The scan abort will return 1 for success or
|
||||
* 2 for "failure". A failure condition can be
|
||||
* due to simply not being in an active scan which
|
||||
* can occur if we send the scan abort before we
|
||||
* the microcode has notified us that a scan is
|
||||
* completed. */
|
||||
IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
iwl_legacy_free_pages(priv, cmd.reply_page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_legacy_complete_scan(struct iwl_priv *priv, bool aborted)
|
||||
{
|
||||
/* check if scan was requested from mac80211 */
|
||||
if (priv->scan_request) {
|
||||
IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
|
||||
ieee80211_scan_completed(priv->hw, aborted);
|
||||
}
|
||||
|
||||
priv->is_internal_short_scan = false;
|
||||
priv->scan_vif = NULL;
|
||||
priv->scan_request = NULL;
|
||||
}
|
||||
|
||||
void iwl_legacy_force_scan_end(struct iwl_priv *priv)
|
||||
{
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
|
||||
return;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
iwl_legacy_complete_scan(priv, true);
|
||||
}
|
||||
|
||||
static void iwl_legacy_do_scan_abort(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (!test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = iwl_legacy_send_scan_abort(priv);
|
||||
if (ret) {
|
||||
IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
|
||||
iwl_legacy_force_scan_end(priv);
|
||||
} else
|
||||
IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_scan_cancel - Cancel any currently executing HW scan
|
||||
*/
|
||||
int iwl_legacy_scan_cancel(struct iwl_priv *priv)
|
||||
{
|
||||
IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
|
||||
queue_work(priv->workqueue, &priv->abort_scan);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_scan_cancel);
|
||||
|
||||
/**
|
||||
* iwl_legacy_scan_cancel_timeout - Cancel any currently executing HW scan
|
||||
* @ms: amount of time to wait (in milliseconds) for scan to abort
|
||||
*
|
||||
*/
|
||||
int iwl_legacy_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(ms);
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
|
||||
|
||||
iwl_legacy_do_scan_abort(priv);
|
||||
|
||||
while (time_before_eq(jiffies, timeout)) {
|
||||
if (!test_bit(STATUS_SCAN_HW, &priv->status))
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
return test_bit(STATUS_SCAN_HW, &priv->status);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_scan_cancel_timeout);
|
||||
|
||||
/* Service response to REPLY_SCAN_CMD (0x80) */
|
||||
static void iwl_legacy_rx_reply_scan(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_scanreq_notification *notif =
|
||||
(struct iwl_scanreq_notification *)pkt->u.raw;
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Service SCAN_START_NOTIFICATION (0x82) */
|
||||
static void iwl_legacy_rx_scan_start_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_scanstart_notification *notif =
|
||||
(struct iwl_scanstart_notification *)pkt->u.raw;
|
||||
priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
|
||||
IWL_DEBUG_SCAN(priv, "Scan start: "
|
||||
"%d [802.11%s] "
|
||||
"(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
|
||||
notif->channel,
|
||||
notif->band ? "bg" : "a",
|
||||
le32_to_cpu(notif->tsf_high),
|
||||
le32_to_cpu(notif->tsf_low),
|
||||
notif->status, notif->beacon_timer);
|
||||
}
|
||||
|
||||
/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
|
||||
static void iwl_legacy_rx_scan_results_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_scanresults_notification *notif =
|
||||
(struct iwl_scanresults_notification *)pkt->u.raw;
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan ch.res: "
|
||||
"%d [802.11%s] "
|
||||
"(TSF: 0x%08X:%08X) - %d "
|
||||
"elapsed=%lu usec\n",
|
||||
notif->channel,
|
||||
notif->band ? "bg" : "a",
|
||||
le32_to_cpu(notif->tsf_high),
|
||||
le32_to_cpu(notif->tsf_low),
|
||||
le32_to_cpu(notif->statistics[0]),
|
||||
le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
|
||||
static void iwl_legacy_rx_scan_complete_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
|
||||
#endif
|
||||
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
|
||||
scan_notif->scanned_channels,
|
||||
scan_notif->tsf_low,
|
||||
scan_notif->tsf_high, scan_notif->status);
|
||||
|
||||
/* The HW is no longer scanning */
|
||||
clear_bit(STATUS_SCAN_HW, &priv->status);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
|
||||
(priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
|
||||
jiffies_to_msecs(jiffies - priv->scan_start));
|
||||
|
||||
queue_work(priv->workqueue, &priv->scan_completed);
|
||||
}
|
||||
|
||||
void iwl_legacy_setup_rx_scan_handlers(struct iwl_priv *priv)
|
||||
{
|
||||
/* scan handlers */
|
||||
priv->rx_handlers[REPLY_SCAN_CMD] = iwl_legacy_rx_reply_scan;
|
||||
priv->rx_handlers[SCAN_START_NOTIFICATION] =
|
||||
iwl_legacy_rx_scan_start_notif;
|
||||
priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
|
||||
iwl_legacy_rx_scan_results_notif;
|
||||
priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
|
||||
iwl_legacy_rx_scan_complete_notif;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_setup_rx_scan_handlers);
|
||||
|
||||
inline u16 iwl_legacy_get_active_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u8 n_probes)
|
||||
{
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
return IWL_ACTIVE_DWELL_TIME_52 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
|
||||
else
|
||||
return IWL_ACTIVE_DWELL_TIME_24 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_get_active_dwell_time);
|
||||
|
||||
u16 iwl_legacy_get_passive_dwell_time(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
u16 passive = (band == IEEE80211_BAND_2GHZ) ?
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
|
||||
|
||||
if (iwl_legacy_is_any_associated(priv)) {
|
||||
/*
|
||||
* If we're associated, we clamp the maximum passive
|
||||
* dwell time to be 98% of the smallest beacon interval
|
||||
* (minus 2 * channel tune time)
|
||||
*/
|
||||
for_each_context(priv, ctx) {
|
||||
u16 value;
|
||||
|
||||
if (!iwl_legacy_is_associated_ctx(ctx))
|
||||
continue;
|
||||
value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
|
||||
if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
|
||||
value = IWL_PASSIVE_DWELL_BASE;
|
||||
value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
|
||||
passive = min(value, passive);
|
||||
}
|
||||
}
|
||||
|
||||
return passive;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_get_passive_dwell_time);
|
||||
|
||||
void iwl_legacy_init_scan_params(struct iwl_priv *priv)
|
||||
{
|
||||
u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
|
||||
if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
|
||||
priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
|
||||
if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
|
||||
priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_init_scan_params);
|
||||
|
||||
static int __must_check iwl_legacy_scan_initiate(struct iwl_priv *priv,
|
||||
struct ieee80211_vif *vif,
|
||||
bool internal,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
||||
if (WARN_ON(!priv->cfg->ops->utils->request_scan))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
if (!iwl_legacy_is_ready_rf(priv)) {
|
||||
IWL_WARN(priv, "Request scan called when driver not ready.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_HW, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"Multiple concurrent scan requests in parallel.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
|
||||
internal ? "internal short " : "");
|
||||
|
||||
set_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = internal;
|
||||
priv->scan_start = jiffies;
|
||||
priv->scan_band = band;
|
||||
|
||||
ret = priv->cfg->ops->utils->request_scan(priv, vif);
|
||||
if (ret) {
|
||||
clear_bit(STATUS_SCANNING, &priv->status);
|
||||
priv->is_internal_short_scan = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
queue_delayed_work(priv->workqueue, &priv->scan_check,
|
||||
IWL_SCAN_CHECK_WATCHDOG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_legacy_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
|
||||
if (req->n_channels == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status) &&
|
||||
!priv->is_internal_short_scan) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* mac80211 will only ask for one band at a time */
|
||||
priv->scan_request = req;
|
||||
priv->scan_vif = vif;
|
||||
|
||||
/*
|
||||
* If an internal scan is in progress, just set
|
||||
* up the scan_request as per above.
|
||||
*/
|
||||
if (priv->is_internal_short_scan) {
|
||||
IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
|
||||
ret = 0;
|
||||
} else
|
||||
ret = iwl_legacy_scan_initiate(priv, vif, false,
|
||||
req->channels[0]->band);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_mac_hw_scan);
|
||||
|
||||
/*
|
||||
* internal short scan, this function should only been called while associated.
|
||||
* It will reset and tune the radio to prevent possible RF related problem
|
||||
*/
|
||||
void iwl_legacy_internal_short_hw_scan(struct iwl_priv *priv)
|
||||
{
|
||||
queue_work(priv->workqueue, &priv->start_internal_scan);
|
||||
}
|
||||
|
||||
static void iwl_legacy_bg_start_internal_scan(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv =
|
||||
container_of(work, struct iwl_priv, start_internal_scan);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Start internal scan\n");
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (priv->is_internal_short_scan == true) {
|
||||
IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (test_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (iwl_legacy_scan_initiate(priv, NULL, true, priv->band))
|
||||
IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
|
||||
unlock:
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
static void iwl_legacy_bg_scan_check(struct work_struct *data)
|
||||
{
|
||||
struct iwl_priv *priv =
|
||||
container_of(data, struct iwl_priv, scan_check.work);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Scan check work\n");
|
||||
|
||||
/* Since we are here firmware does not finish scan and
|
||||
* most likely is in bad shape, so we don't bother to
|
||||
* send abort command, just force scan complete to mac80211 */
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_legacy_force_scan_end(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_fill_probe_req - fill in all required fields and IE for probe request
|
||||
*/
|
||||
|
||||
u16
|
||||
iwl_legacy_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
|
||||
const u8 *ta, const u8 *ies, int ie_len, int left)
|
||||
{
|
||||
int len = 0;
|
||||
u8 *pos = NULL;
|
||||
|
||||
/* Make sure there is enough space for the probe request,
|
||||
* two mandatory IEs and the data */
|
||||
left -= 24;
|
||||
if (left < 0)
|
||||
return 0;
|
||||
|
||||
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
|
||||
memcpy(frame->da, iwlegacy_bcast_addr, ETH_ALEN);
|
||||
memcpy(frame->sa, ta, ETH_ALEN);
|
||||
memcpy(frame->bssid, iwlegacy_bcast_addr, ETH_ALEN);
|
||||
frame->seq_ctrl = 0;
|
||||
|
||||
len += 24;
|
||||
|
||||
/* ...next IE... */
|
||||
pos = &frame->u.probe_req.variable[0];
|
||||
|
||||
/* fill in our indirect SSID IE */
|
||||
left -= 2;
|
||||
if (left < 0)
|
||||
return 0;
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = 0;
|
||||
|
||||
len += 2;
|
||||
|
||||
if (WARN_ON(left < ie_len))
|
||||
return len;
|
||||
|
||||
if (ies && ie_len) {
|
||||
memcpy(pos, ies, ie_len);
|
||||
len += ie_len;
|
||||
}
|
||||
|
||||
return (u16)len;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_fill_probe_req);
|
||||
|
||||
static void iwl_legacy_bg_abort_scan(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Abort scan work\n");
|
||||
|
||||
/* We keep scan_check work queued in case when firmware will not
|
||||
* report back scan completed notification */
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_legacy_scan_cancel_timeout(priv, 200);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
static void iwl_legacy_bg_scan_completed(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv =
|
||||
container_of(work, struct iwl_priv, scan_completed);
|
||||
bool aborted;
|
||||
|
||||
IWL_DEBUG_SCAN(priv, "Completed %sscan.\n",
|
||||
priv->is_internal_short_scan ? "internal short " : "");
|
||||
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
|
||||
if (aborted)
|
||||
IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
|
||||
|
||||
if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
|
||||
IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
|
||||
goto out_settings;
|
||||
}
|
||||
|
||||
if (priv->is_internal_short_scan && !aborted) {
|
||||
int err;
|
||||
|
||||
/* Check if mac80211 requested scan during our internal scan */
|
||||
if (priv->scan_request == NULL)
|
||||
goto out_complete;
|
||||
|
||||
/* If so request a new scan */
|
||||
err = iwl_legacy_scan_initiate(priv, priv->scan_vif, false,
|
||||
priv->scan_request->channels[0]->band);
|
||||
if (err) {
|
||||
IWL_DEBUG_SCAN(priv,
|
||||
"failed to initiate pending scan: %d\n", err);
|
||||
aborted = true;
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_complete:
|
||||
iwl_legacy_complete_scan(priv, aborted);
|
||||
|
||||
out_settings:
|
||||
/* Can we still talk to firmware ? */
|
||||
if (!iwl_legacy_is_ready_rf(priv))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We do not commit power settings while scan is pending,
|
||||
* do it now if the settings changed.
|
||||
*/
|
||||
iwl_legacy_power_set_mode(priv, &priv->power_data.sleep_cmd_next,
|
||||
false);
|
||||
iwl_legacy_set_tx_power(priv, priv->tx_power_next, false);
|
||||
|
||||
priv->cfg->ops->utils->post_scan(priv);
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
void iwl_legacy_setup_scan_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
INIT_WORK(&priv->scan_completed, iwl_legacy_bg_scan_completed);
|
||||
INIT_WORK(&priv->abort_scan, iwl_legacy_bg_abort_scan);
|
||||
INIT_WORK(&priv->start_internal_scan,
|
||||
iwl_legacy_bg_start_internal_scan);
|
||||
INIT_DELAYED_WORK(&priv->scan_check, iwl_legacy_bg_scan_check);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_setup_scan_deferred_work);
|
||||
|
||||
void iwl_legacy_cancel_scan_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
cancel_work_sync(&priv->start_internal_scan);
|
||||
cancel_work_sync(&priv->abort_scan);
|
||||
cancel_work_sync(&priv->scan_completed);
|
||||
|
||||
if (cancel_delayed_work_sync(&priv->scan_check)) {
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_legacy_force_scan_end(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_cancel_scan_deferred_work);
|
|
@ -0,0 +1,92 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from 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_legacy_spectrum_h__
|
||||
#define __iwl_legacy_spectrum_h__
|
||||
enum { /* ieee80211_basic_report.map */
|
||||
IEEE80211_BASIC_MAP_BSS = (1 << 0),
|
||||
IEEE80211_BASIC_MAP_OFDM = (1 << 1),
|
||||
IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
|
||||
IEEE80211_BASIC_MAP_RADAR = (1 << 3),
|
||||
IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
|
||||
/* Bits 5-7 are reserved */
|
||||
|
||||
};
|
||||
struct ieee80211_basic_report {
|
||||
u8 channel;
|
||||
__le64 start_time;
|
||||
__le16 duration;
|
||||
u8 map;
|
||||
} __packed;
|
||||
|
||||
enum { /* ieee80211_measurement_request.mode */
|
||||
/* Bit 0 is reserved */
|
||||
IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
|
||||
IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
|
||||
IEEE80211_MEASUREMENT_REPORT = (1 << 3),
|
||||
/* Bits 4-7 are reserved */
|
||||
};
|
||||
|
||||
enum {
|
||||
IEEE80211_REPORT_BASIC = 0, /* required */
|
||||
IEEE80211_REPORT_CCA = 1, /* optional */
|
||||
IEEE80211_REPORT_RPI = 2, /* optional */
|
||||
/* 3-255 reserved */
|
||||
};
|
||||
|
||||
struct ieee80211_measurement_params {
|
||||
u8 channel;
|
||||
__le64 start_time;
|
||||
__le16 duration;
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_info_element {
|
||||
u8 id;
|
||||
u8 len;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_measurement_request {
|
||||
struct ieee80211_info_element ie;
|
||||
u8 token;
|
||||
u8 mode;
|
||||
u8 type;
|
||||
struct ieee80211_measurement_params params[0];
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_measurement_report {
|
||||
struct ieee80211_info_element ie;
|
||||
u8 token;
|
||||
u8 mode;
|
||||
u8 type;
|
||||
union {
|
||||
struct ieee80211_basic_report basic[0];
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,816 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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 <net/mac80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/lockdep.h>
|
||||
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
|
||||
/* priv->sta_lock must be held */
|
||||
static void iwl_legacy_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
|
||||
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
|
||||
IWL_ERR(priv,
|
||||
"ACTIVATE a non DRIVER active station id %u addr %pM\n",
|
||||
sta_id, priv->stations[sta_id].sta.sta.addr);
|
||||
|
||||
if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
|
||||
IWL_DEBUG_ASSOC(priv,
|
||||
"STA id %u addr %pM already present"
|
||||
" in uCode (according to driver)\n",
|
||||
sta_id, priv->stations[sta_id].sta.sta.addr);
|
||||
} else {
|
||||
priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
|
||||
IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
|
||||
sta_id, priv->stations[sta_id].sta.sta.addr);
|
||||
}
|
||||
}
|
||||
|
||||
static int iwl_legacy_process_add_sta_resp(struct iwl_priv *priv,
|
||||
struct iwl_legacy_addsta_cmd *addsta,
|
||||
struct iwl_rx_packet *pkt,
|
||||
bool sync)
|
||||
{
|
||||
u8 sta_id = addsta->sta.sta_id;
|
||||
unsigned long flags;
|
||||
int ret = -EIO;
|
||||
|
||||
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
|
||||
pkt->hdr.flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
|
||||
sta_id);
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
switch (pkt->u.add_sta.status) {
|
||||
case ADD_STA_SUCCESS_MSK:
|
||||
IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
|
||||
iwl_legacy_sta_ucode_activate(priv, sta_id);
|
||||
ret = 0;
|
||||
break;
|
||||
case ADD_STA_NO_ROOM_IN_TABLE:
|
||||
IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
|
||||
sta_id);
|
||||
break;
|
||||
case ADD_STA_NO_BLOCK_ACK_RESOURCE:
|
||||
IWL_ERR(priv,
|
||||
"Adding station %d failed, no block ack resource.\n",
|
||||
sta_id);
|
||||
break;
|
||||
case ADD_STA_MODIFY_NON_EXIST_STA:
|
||||
IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
|
||||
sta_id);
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
|
||||
pkt->u.add_sta.status);
|
||||
break;
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
|
||||
priv->stations[sta_id].sta.mode ==
|
||||
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
|
||||
sta_id, priv->stations[sta_id].sta.sta.addr);
|
||||
|
||||
/*
|
||||
* XXX: The MAC address in the command buffer is often changed from
|
||||
* the original sent to the device. That is, the MAC address
|
||||
* written to the command buffer often is not the same MAC adress
|
||||
* read from the command buffer when the command returns. This
|
||||
* issue has not yet been resolved and this debugging is left to
|
||||
* observe the problem.
|
||||
*/
|
||||
IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
|
||||
priv->stations[sta_id].sta.mode ==
|
||||
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
|
||||
addsta->sta.addr);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_legacy_add_sta_callback(struct iwl_priv *priv,
|
||||
struct iwl_device_cmd *cmd,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_legacy_addsta_cmd *addsta =
|
||||
(struct iwl_legacy_addsta_cmd *)cmd->cmd.payload;
|
||||
|
||||
iwl_legacy_process_add_sta_resp(priv, addsta, pkt, false);
|
||||
|
||||
}
|
||||
|
||||
int iwl_legacy_send_add_sta(struct iwl_priv *priv,
|
||||
struct iwl_legacy_addsta_cmd *sta, u8 flags)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = NULL;
|
||||
int ret = 0;
|
||||
u8 data[sizeof(*sta)];
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_ADD_STA,
|
||||
.flags = flags,
|
||||
.data = data,
|
||||
};
|
||||
u8 sta_id __maybe_unused = sta->sta.sta_id;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
|
||||
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
cmd.callback = iwl_legacy_add_sta_callback;
|
||||
else {
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
might_sleep();
|
||||
}
|
||||
|
||||
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
|
||||
ret = iwl_legacy_send_cmd(priv, &cmd);
|
||||
|
||||
if (ret || (flags & CMD_ASYNC))
|
||||
return ret;
|
||||
|
||||
if (ret == 0) {
|
||||
pkt = (struct iwl_rx_packet *)cmd.reply_page;
|
||||
ret = iwl_legacy_process_add_sta_resp(priv, sta, pkt, true);
|
||||
}
|
||||
iwl_legacy_free_pages(priv, cmd.reply_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_add_sta);
|
||||
|
||||
static void iwl_legacy_set_ht_add_station(struct iwl_priv *priv, u8 index,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
|
||||
__le32 sta_flags;
|
||||
u8 mimo_ps_mode;
|
||||
|
||||
if (!sta || !sta_ht_inf->ht_supported)
|
||||
goto done;
|
||||
|
||||
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
|
||||
IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n",
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
|
||||
"static" :
|
||||
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
|
||||
"dynamic" : "disabled");
|
||||
|
||||
sta_flags = priv->stations[index].sta.station_flags;
|
||||
|
||||
sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
|
||||
|
||||
switch (mimo_ps_mode) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
sta_flags |= STA_FLG_MIMO_DIS_MSK;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||
break;
|
||||
default:
|
||||
IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
sta_flags |= cpu_to_le32(
|
||||
(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
|
||||
|
||||
sta_flags |= cpu_to_le32(
|
||||
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
|
||||
|
||||
if (iwl_legacy_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
|
||||
sta_flags |= STA_FLG_HT40_EN_MSK;
|
||||
else
|
||||
sta_flags &= ~STA_FLG_HT40_EN_MSK;
|
||||
|
||||
priv->stations[index].sta.station_flags = sta_flags;
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_prep_station - Prepare station information for addition
|
||||
*
|
||||
* should be called with sta_lock held
|
||||
*/
|
||||
u8 iwl_legacy_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_station_entry *station;
|
||||
int i;
|
||||
u8 sta_id = IWL_INVALID_STATION;
|
||||
u16 rate;
|
||||
|
||||
if (is_ap)
|
||||
sta_id = ctx->ap_sta_id;
|
||||
else if (is_broadcast_ether_addr(addr))
|
||||
sta_id = ctx->bcast_sta_id;
|
||||
else
|
||||
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
|
||||
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
||||
addr)) {
|
||||
sta_id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!priv->stations[i].used &&
|
||||
sta_id == IWL_INVALID_STATION)
|
||||
sta_id = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* These two conditions have the same outcome, but keep them
|
||||
* separate
|
||||
*/
|
||||
if (unlikely(sta_id == IWL_INVALID_STATION))
|
||||
return sta_id;
|
||||
|
||||
/*
|
||||
* uCode is not able to deal with multiple requests to add a
|
||||
* station. Keep track if one is in progress so that we do not send
|
||||
* another.
|
||||
*/
|
||||
if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"STA %d already in process of being added.\n",
|
||||
sta_id);
|
||||
return sta_id;
|
||||
}
|
||||
|
||||
if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
|
||||
(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
|
||||
!compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
|
||||
IWL_DEBUG_ASSOC(priv,
|
||||
"STA %d (%pM) already added, not adding again.\n",
|
||||
sta_id, addr);
|
||||
return sta_id;
|
||||
}
|
||||
|
||||
station = &priv->stations[sta_id];
|
||||
station->used = IWL_STA_DRIVER_ACTIVE;
|
||||
IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
|
||||
sta_id, addr);
|
||||
priv->num_stations++;
|
||||
|
||||
/* Set up the REPLY_ADD_STA command to send to device */
|
||||
memset(&station->sta, 0, sizeof(struct iwl_legacy_addsta_cmd));
|
||||
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
|
||||
station->sta.mode = 0;
|
||||
station->sta.sta.sta_id = sta_id;
|
||||
station->sta.station_flags = ctx->station_flags;
|
||||
station->ctxid = ctx->ctxid;
|
||||
|
||||
if (sta) {
|
||||
struct iwl_station_priv_common *sta_priv;
|
||||
|
||||
sta_priv = (void *)sta->drv_priv;
|
||||
sta_priv->ctx = ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK to call unconditionally, since local stations (IBSS BSSID
|
||||
* STA and broadcast STA) pass in a NULL sta, and mac80211
|
||||
* doesn't allow HT IBSS.
|
||||
*/
|
||||
iwl_legacy_set_ht_add_station(priv, sta_id, sta, ctx);
|
||||
|
||||
/* 3945 only */
|
||||
rate = (priv->band == IEEE80211_BAND_5GHZ) ?
|
||||
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
|
||||
/* Turn on both antennas for the station... */
|
||||
station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
|
||||
|
||||
return sta_id;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_legacy_prep_station);
|
||||
|
||||
#define STA_WAIT_TIMEOUT (HZ/2)
|
||||
|
||||
/**
|
||||
* iwl_legacy_add_station_common -
|
||||
*/
|
||||
int
|
||||
iwl_legacy_add_station_common(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap,
|
||||
struct ieee80211_sta *sta, u8 *sta_id_r)
|
||||
{
|
||||
unsigned long flags_spin;
|
||||
int ret = 0;
|
||||
u8 sta_id;
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
|
||||
*sta_id_r = 0;
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
sta_id = iwl_legacy_prep_station(priv, ctx, addr, is_ap, sta);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
|
||||
addr);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* uCode is not able to deal with multiple requests to add a
|
||||
* station. Keep track if one is in progress so that we do not send
|
||||
* another.
|
||||
*/
|
||||
if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"STA %d already in process of being added.\n",
|
||||
sta_id);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
|
||||
(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
|
||||
IWL_DEBUG_ASSOC(priv,
|
||||
"STA %d (%pM) already added, not adding again.\n",
|
||||
sta_id, addr);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
|
||||
memcpy(&sta_cmd, &priv->stations[sta_id].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
|
||||
/* Add station to device's station table */
|
||||
ret = iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
if (ret) {
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
IWL_ERR(priv, "Adding station %pM failed.\n",
|
||||
priv->stations[sta_id].sta.sta.addr);
|
||||
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
|
||||
priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
}
|
||||
*sta_id_r = sta_id;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_add_station_common);
|
||||
|
||||
/**
|
||||
* iwl_legacy_sta_ucode_deactivate - deactivate ucode status for a station
|
||||
*
|
||||
* priv->sta_lock must be held
|
||||
*/
|
||||
static void iwl_legacy_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
/* Ucode must be active and driver must be non active */
|
||||
if ((priv->stations[sta_id].used &
|
||||
(IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
|
||||
IWL_STA_UCODE_ACTIVE)
|
||||
IWL_ERR(priv, "removed non active STA %u\n", sta_id);
|
||||
|
||||
priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
|
||||
|
||||
memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
|
||||
IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
|
||||
}
|
||||
|
||||
static int iwl_legacy_send_remove_station(struct iwl_priv *priv,
|
||||
const u8 *addr, int sta_id,
|
||||
bool temporary)
|
||||
{
|
||||
struct iwl_rx_packet *pkt;
|
||||
int ret;
|
||||
|
||||
unsigned long flags_spin;
|
||||
struct iwl_rem_sta_cmd rm_sta_cmd;
|
||||
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_REMOVE_STA,
|
||||
.len = sizeof(struct iwl_rem_sta_cmd),
|
||||
.flags = CMD_SYNC,
|
||||
.data = &rm_sta_cmd,
|
||||
};
|
||||
|
||||
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
|
||||
rm_sta_cmd.num_sta = 1;
|
||||
memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
|
||||
|
||||
cmd.flags |= CMD_WANT_SKB;
|
||||
|
||||
ret = iwl_legacy_send_cmd(priv, &cmd);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pkt = (struct iwl_rx_packet *)cmd.reply_page;
|
||||
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
|
||||
pkt->hdr.flags);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
switch (pkt->u.rem_sta.status) {
|
||||
case REM_STA_SUCCESS_MSK:
|
||||
if (!temporary) {
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
iwl_legacy_sta_ucode_deactivate(priv, sta_id);
|
||||
spin_unlock_irqrestore(&priv->sta_lock,
|
||||
flags_spin);
|
||||
}
|
||||
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
|
||||
break;
|
||||
default:
|
||||
ret = -EIO;
|
||||
IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
iwl_legacy_free_pages(priv, cmd.reply_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_remove_station - Remove driver's knowledge of station.
|
||||
*/
|
||||
int iwl_legacy_remove_station(struct iwl_priv *priv, const u8 sta_id,
|
||||
const u8 *addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!iwl_legacy_is_ready(priv)) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Unable to remove station %pM, device not ready.\n",
|
||||
addr);
|
||||
/*
|
||||
* It is typical for stations to be removed when we are
|
||||
* going down. Return success since device will be down
|
||||
* soon anyway
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n",
|
||||
sta_id, addr);
|
||||
|
||||
if (WARN_ON(sta_id == IWL_INVALID_STATION))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
|
||||
IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
|
||||
addr);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
|
||||
IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
|
||||
addr);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
|
||||
kfree(priv->stations[sta_id].lq);
|
||||
priv->stations[sta_id].lq = NULL;
|
||||
}
|
||||
|
||||
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
|
||||
|
||||
priv->num_stations--;
|
||||
|
||||
BUG_ON(priv->num_stations < 0);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return iwl_legacy_send_remove_station(priv, addr, sta_id, false);
|
||||
out_err:
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_legacy_remove_station);
|
||||
|
||||
/**
|
||||
* iwl_legacy_clear_ucode_stations - clear ucode station table bits
|
||||
*
|
||||
* This function clears all the bits in the driver indicating
|
||||
* which stations are active in the ucode. Call when something
|
||||
* other than explicit station management would cause this in
|
||||
* the ucode, e.g. unassociated RXON.
|
||||
*/
|
||||
void iwl_legacy_clear_ucode_stations(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags_spin;
|
||||
bool cleared = false;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
for (i = 0; i < priv->hw_params.max_stations; i++) {
|
||||
if (ctx && ctx->ctxid != priv->stations[i].ctxid)
|
||||
continue;
|
||||
|
||||
if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Clearing ucode active for station %d\n", i);
|
||||
priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
|
||||
if (!cleared)
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"No active stations found to be cleared\n");
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_clear_ucode_stations);
|
||||
|
||||
/**
|
||||
* iwl_legacy_restore_stations() - Restore driver known stations to device
|
||||
*
|
||||
* All stations considered active by driver, but not present in ucode, is
|
||||
* restored.
|
||||
*
|
||||
* Function sleeps.
|
||||
*/
|
||||
void
|
||||
iwl_legacy_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
|
||||
{
|
||||
struct iwl_legacy_addsta_cmd sta_cmd;
|
||||
struct iwl_link_quality_cmd lq;
|
||||
unsigned long flags_spin;
|
||||
int i;
|
||||
bool found = false;
|
||||
int ret;
|
||||
bool send_lq;
|
||||
|
||||
if (!iwl_legacy_is_ready(priv)) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Not ready yet, not restoring any stations.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
for (i = 0; i < priv->hw_params.max_stations; i++) {
|
||||
if (ctx->ctxid != priv->stations[i].ctxid)
|
||||
continue;
|
||||
if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
|
||||
!(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
|
||||
IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
|
||||
priv->stations[i].sta.sta.addr);
|
||||
priv->stations[i].sta.mode = 0;
|
||||
priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->hw_params.max_stations; i++) {
|
||||
if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
|
||||
memcpy(&sta_cmd, &priv->stations[i].sta,
|
||||
sizeof(struct iwl_legacy_addsta_cmd));
|
||||
send_lq = false;
|
||||
if (priv->stations[i].lq) {
|
||||
memcpy(&lq, priv->stations[i].lq,
|
||||
sizeof(struct iwl_link_quality_cmd));
|
||||
send_lq = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
ret = iwl_legacy_send_add_sta(priv, &sta_cmd, CMD_SYNC);
|
||||
if (ret) {
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
IWL_ERR(priv, "Adding station %pM failed.\n",
|
||||
priv->stations[i].sta.sta.addr);
|
||||
priv->stations[i].used &=
|
||||
~IWL_STA_DRIVER_ACTIVE;
|
||||
priv->stations[i].used &=
|
||||
~IWL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&priv->sta_lock,
|
||||
flags_spin);
|
||||
}
|
||||
/*
|
||||
* Rate scaling has already been initialized, send
|
||||
* current LQ command
|
||||
*/
|
||||
if (send_lq)
|
||||
iwl_legacy_send_lq_cmd(priv, ctx, &lq,
|
||||
CMD_SYNC, true);
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
if (!found)
|
||||
IWL_DEBUG_INFO(priv, "Restoring all known stations"
|
||||
" .... no stations to be restored.\n");
|
||||
else
|
||||
IWL_DEBUG_INFO(priv, "Restoring all known stations"
|
||||
" .... complete.\n");
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_restore_stations);
|
||||
|
||||
int iwl_legacy_get_free_ucode_key_index(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->sta_key_max_num; i++)
|
||||
if (!test_and_set_bit(i, &priv->ucode_key_table))
|
||||
return i;
|
||||
|
||||
return WEP_INVALID_OFFSET;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_get_free_ucode_key_index);
|
||||
|
||||
void iwl_legacy_dealloc_bcast_stations(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
for (i = 0; i < priv->hw_params.max_stations; i++) {
|
||||
if (!(priv->stations[i].used & IWL_STA_BCAST))
|
||||
continue;
|
||||
|
||||
priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
|
||||
priv->num_stations--;
|
||||
BUG_ON(priv->num_stations < 0);
|
||||
kfree(priv->stations[i].lq);
|
||||
priv->stations[i].lq = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iwl_legacy_dealloc_bcast_stations);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
static void iwl_legacy_dump_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq)
|
||||
{
|
||||
int i;
|
||||
IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
|
||||
IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
|
||||
lq->general_params.single_stream_ant_msk,
|
||||
lq->general_params.dual_stream_ant_msk);
|
||||
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
|
||||
i, lq->rs_table[i].rate_n_flags);
|
||||
}
|
||||
#else
|
||||
static inline void iwl_legacy_dump_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* iwl_legacy_is_lq_table_valid() - Test one aspect of LQ cmd for validity
|
||||
*
|
||||
* It sometimes happens when a HT rate has been in use and we
|
||||
* loose connectivity with AP then mac80211 will first tell us that the
|
||||
* current channel is not HT anymore before removing the station. In such a
|
||||
* scenario the RXON flags will be updated to indicate we are not
|
||||
* communicating HT anymore, but the LQ command may still contain HT rates.
|
||||
* Test for this to prevent driver from sending LQ command between the time
|
||||
* RXON flags are updated and when LQ command is updated.
|
||||
*/
|
||||
static bool iwl_legacy_is_lq_table_valid(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct iwl_link_quality_cmd *lq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ctx->ht.enabled)
|
||||
return true;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
|
||||
ctx->active.channel);
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
|
||||
if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
|
||||
RATE_MCS_HT_MSK) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"index %d of LQ expects HT channel\n",
|
||||
i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_send_lq_cmd() - Send link quality command
|
||||
* @init: This command is sent as part of station initialization right
|
||||
* after station has been added.
|
||||
*
|
||||
* The link quality command is sent as the last step of station creation.
|
||||
* This is the special case in which init is set and we call a callback in
|
||||
* this case to clear the state indicating that station creation is in
|
||||
* progress.
|
||||
*/
|
||||
int iwl_legacy_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
|
||||
struct iwl_link_quality_cmd *lq, u8 flags, bool init)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags_spin;
|
||||
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_TX_LINK_QUALITY_CMD,
|
||||
.len = sizeof(struct iwl_link_quality_cmd),
|
||||
.flags = flags,
|
||||
.data = lq,
|
||||
};
|
||||
|
||||
if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
|
||||
iwl_legacy_dump_lq_cmd(priv, lq);
|
||||
BUG_ON(init && (cmd.flags & CMD_ASYNC));
|
||||
|
||||
if (iwl_legacy_is_lq_table_valid(priv, ctx, lq))
|
||||
ret = iwl_legacy_send_cmd(priv, &cmd);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
if (cmd.flags & CMD_ASYNC)
|
||||
return ret;
|
||||
|
||||
if (init) {
|
||||
IWL_DEBUG_INFO(priv, "init LQ command complete,"
|
||||
" clearing sta addition status for sta %d\n",
|
||||
lq->sta_id);
|
||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||
priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_send_lq_cmd);
|
||||
|
||||
int iwl_legacy_mac_sta_remove(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv;
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
|
||||
sta->addr);
|
||||
mutex_lock(&priv->mutex);
|
||||
IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
|
||||
sta->addr);
|
||||
ret = iwl_legacy_remove_station(priv, sta_common->sta_id, sta->addr);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "Error removing station %pM\n",
|
||||
sta->addr);
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_mac_sta_remove);
|
|
@ -0,0 +1,148 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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_legacy_sta_h__
|
||||
#define __iwl_legacy_sta_h__
|
||||
|
||||
#include "iwl-dev.h"
|
||||
|
||||
#define HW_KEY_DYNAMIC 0
|
||||
#define HW_KEY_DEFAULT 1
|
||||
|
||||
#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
|
||||
#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
|
||||
#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of
|
||||
being activated */
|
||||
#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
|
||||
(this is for the IBSS BSSID stations) */
|
||||
#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
|
||||
|
||||
|
||||
void iwl_legacy_restore_stations(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_legacy_clear_ucode_stations(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx);
|
||||
void iwl_legacy_dealloc_bcast_stations(struct iwl_priv *priv);
|
||||
int iwl_legacy_get_free_ucode_key_index(struct iwl_priv *priv);
|
||||
int iwl_legacy_send_add_sta(struct iwl_priv *priv,
|
||||
struct iwl_legacy_addsta_cmd *sta, u8 flags);
|
||||
int iwl_legacy_add_station_common(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap,
|
||||
struct ieee80211_sta *sta, u8 *sta_id_r);
|
||||
int iwl_legacy_remove_station(struct iwl_priv *priv,
|
||||
const u8 sta_id,
|
||||
const u8 *addr);
|
||||
int iwl_legacy_mac_sta_remove(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
|
||||
u8 iwl_legacy_prep_station(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
const u8 *addr, bool is_ap,
|
||||
struct ieee80211_sta *sta);
|
||||
|
||||
int iwl_legacy_send_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *ctx,
|
||||
struct iwl_link_quality_cmd *lq,
|
||||
u8 flags, bool init);
|
||||
|
||||
/**
|
||||
* iwl_legacy_clear_driver_stations - clear knowledge of all stations from driver
|
||||
* @priv: iwl priv struct
|
||||
*
|
||||
* This is called during iwl_down() to make sure that in the case
|
||||
* we're coming there from a hardware restart mac80211 will be
|
||||
* able to reconfigure stations -- if we're getting there in the
|
||||
* normal down flow then the stations will already be cleared.
|
||||
*/
|
||||
static inline void iwl_legacy_clear_driver_stations(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_rxon_context *ctx;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
memset(priv->stations, 0, sizeof(priv->stations));
|
||||
priv->num_stations = 0;
|
||||
|
||||
priv->ucode_key_table = 0;
|
||||
|
||||
for_each_context(priv, ctx) {
|
||||
/*
|
||||
* Remove all key information that is not stored as part
|
||||
* of station information since mac80211 may not have had
|
||||
* a chance to remove all the keys. When device is
|
||||
* reconfigured by mac80211 after an error all keys will
|
||||
* be reconfigured.
|
||||
*/
|
||||
memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
|
||||
ctx->key_mapping_keys = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
}
|
||||
|
||||
static inline int iwl_legacy_sta_id(struct ieee80211_sta *sta)
|
||||
{
|
||||
if (WARN_ON(!sta))
|
||||
return IWL_INVALID_STATION;
|
||||
|
||||
return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_sta_id_or_broadcast - return sta_id or broadcast sta
|
||||
* @priv: iwl priv
|
||||
* @context: the current context
|
||||
* @sta: mac80211 station
|
||||
*
|
||||
* In certain circumstances mac80211 passes a station pointer
|
||||
* that may be %NULL, for example during TX or key setup. In
|
||||
* that case, we need to use the broadcast station, so this
|
||||
* inline wraps that pattern.
|
||||
*/
|
||||
static inline int iwl_legacy_sta_id_or_broadcast(struct iwl_priv *priv,
|
||||
struct iwl_rxon_context *context,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
int sta_id;
|
||||
|
||||
if (!sta)
|
||||
return context->bcast_sta_id;
|
||||
|
||||
sta_id = iwl_legacy_sta_id(sta);
|
||||
|
||||
/*
|
||||
* mac80211 should not be passing a partially
|
||||
* initialised station!
|
||||
*/
|
||||
WARN_ON(sta_id == IWL_INVALID_STATION);
|
||||
|
||||
return sta_id;
|
||||
}
|
||||
#endif /* __iwl_legacy_sta_h__ */
|
|
@ -0,0 +1,660 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2011 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/etherdevice.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-dev.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
|
||||
/**
|
||||
* iwl_legacy_txq_update_write_ptr - Send new write index to hardware
|
||||
*/
|
||||
void
|
||||
iwl_legacy_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
||||
{
|
||||
u32 reg = 0;
|
||||
int txq_id = txq->q.id;
|
||||
|
||||
if (txq->need_update == 0)
|
||||
return;
|
||||
|
||||
/* if we're trying to save power */
|
||||
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
|
||||
/* wake up nic if it's powered down ...
|
||||
* uCode will wake up, and interrupt us again, so next
|
||||
* time we'll skip this part. */
|
||||
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
|
||||
|
||||
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Tx queue %d requesting wakeup,"
|
||||
" GP1 = 0x%x\n", txq_id, reg);
|
||||
iwl_legacy_set_bit(priv, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
return;
|
||||
}
|
||||
|
||||
iwl_legacy_write_direct32(priv, HBUS_TARG_WRPTR,
|
||||
txq->q.write_ptr | (txq_id << 8));
|
||||
|
||||
/*
|
||||
* else not in power-save mode,
|
||||
* uCode will never sleep when we're
|
||||
* trying to tx (during RFKILL, we're not trying to tx).
|
||||
*/
|
||||
} else
|
||||
iwl_write32(priv, HBUS_TARG_WRPTR,
|
||||
txq->q.write_ptr | (txq_id << 8));
|
||||
txq->need_update = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr);
|
||||
|
||||
/**
|
||||
* iwl_legacy_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
|
||||
*/
|
||||
void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[txq_id];
|
||||
struct iwl_queue *q = &txq->q;
|
||||
|
||||
if (q->n_bd == 0)
|
||||
return;
|
||||
|
||||
while (q->write_ptr != q->read_ptr) {
|
||||
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
|
||||
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_tx_queue_unmap);
|
||||
|
||||
/**
|
||||
* iwl_legacy_tx_queue_free - Deallocate DMA queue.
|
||||
* @txq: Transmit queue to deallocate.
|
||||
*
|
||||
* Empty queue by removing and destroying all BD's.
|
||||
* Free all buffers.
|
||||
* 0-fill, but do not free "txq" descriptor structure.
|
||||
*/
|
||||
void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[txq_id];
|
||||
struct device *dev = &priv->pci_dev->dev;
|
||||
int i;
|
||||
|
||||
iwl_legacy_tx_queue_unmap(priv, txq_id);
|
||||
|
||||
/* De-alloc array of command/tx buffers */
|
||||
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
|
||||
/* De-alloc circular buffer of TFDs */
|
||||
if (txq->q.n_bd)
|
||||
dma_free_coherent(dev, priv->hw_params.tfd_size *
|
||||
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
|
||||
|
||||
/* De-alloc array of per-TFD driver data */
|
||||
kfree(txq->txb);
|
||||
txq->txb = NULL;
|
||||
|
||||
/* deallocate arrays */
|
||||
kfree(txq->cmd);
|
||||
kfree(txq->meta);
|
||||
txq->cmd = NULL;
|
||||
txq->meta = NULL;
|
||||
|
||||
/* 0-fill queue descriptor structure */
|
||||
memset(txq, 0, sizeof(*txq));
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_tx_queue_free);
|
||||
|
||||
/**
|
||||
* iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
|
||||
*/
|
||||
void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
|
||||
struct iwl_queue *q = &txq->q;
|
||||
bool huge = false;
|
||||
int i;
|
||||
|
||||
if (q->n_bd == 0)
|
||||
return;
|
||||
|
||||
while (q->read_ptr != q->write_ptr) {
|
||||
/* we have no way to tell if it is a huge cmd ATM */
|
||||
i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0);
|
||||
|
||||
if (txq->meta[i].flags & CMD_SIZE_HUGE)
|
||||
huge = true;
|
||||
else
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
dma_unmap_addr(&txq->meta[i], mapping),
|
||||
dma_unmap_len(&txq->meta[i], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
|
||||
}
|
||||
|
||||
if (huge) {
|
||||
i = q->n_window;
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
dma_unmap_addr(&txq->meta[i], mapping),
|
||||
dma_unmap_len(&txq->meta[i], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap);
|
||||
|
||||
/**
|
||||
* iwl_legacy_cmd_queue_free - Deallocate DMA queue.
|
||||
* @txq: Transmit queue to deallocate.
|
||||
*
|
||||
* Empty queue by removing and destroying all BD's.
|
||||
* Free all buffers.
|
||||
* 0-fill, but do not free "txq" descriptor structure.
|
||||
*/
|
||||
void iwl_legacy_cmd_queue_free(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
|
||||
struct device *dev = &priv->pci_dev->dev;
|
||||
int i;
|
||||
|
||||
iwl_legacy_cmd_queue_unmap(priv);
|
||||
|
||||
/* De-alloc array of command/tx buffers */
|
||||
for (i = 0; i <= TFD_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
|
||||
/* De-alloc circular buffer of TFDs */
|
||||
if (txq->q.n_bd)
|
||||
dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
|
||||
txq->tfds, txq->q.dma_addr);
|
||||
|
||||
/* deallocate arrays */
|
||||
kfree(txq->cmd);
|
||||
kfree(txq->meta);
|
||||
txq->cmd = NULL;
|
||||
txq->meta = NULL;
|
||||
|
||||
/* 0-fill queue descriptor structure */
|
||||
memset(txq, 0, sizeof(*txq));
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_cmd_queue_free);
|
||||
|
||||
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
|
||||
* DMA services
|
||||
*
|
||||
* Theory of operation
|
||||
*
|
||||
* A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
|
||||
* of buffer descriptors, each of which points to one or more data buffers for
|
||||
* the device to read from or fill. Driver and device exchange status of each
|
||||
* queue via "read" and "write" pointers. Driver keeps minimum of 2 empty
|
||||
* entries in each circular buffer, to protect against confusing empty and full
|
||||
* queue states.
|
||||
*
|
||||
* The device reads or writes the data in the queues via the device's several
|
||||
* DMA/FIFO channels. Each queue is mapped to a single DMA channel.
|
||||
*
|
||||
* For Tx queue, there are low mark and high mark limits. If, after queuing
|
||||
* the packet for Tx, free space become < low mark, Tx queue stopped. When
|
||||
* reclaiming packets (on 'tx done IRQ), if free space become > high mark,
|
||||
* Tx queue resumed.
|
||||
*
|
||||
* See more detailed info in iwl-4965-hw.h.
|
||||
***************************************************/
|
||||
|
||||
int iwl_legacy_queue_space(const struct iwl_queue *q)
|
||||
{
|
||||
int s = q->read_ptr - q->write_ptr;
|
||||
|
||||
if (q->read_ptr > q->write_ptr)
|
||||
s -= q->n_bd;
|
||||
|
||||
if (s <= 0)
|
||||
s += q->n_window;
|
||||
/* keep some reserve to not confuse empty and full situations */
|
||||
s -= 2;
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
return s;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_queue_space);
|
||||
|
||||
|
||||
/**
|
||||
* iwl_legacy_queue_init - Initialize queue's high/low-water and read/write indexes
|
||||
*/
|
||||
static int iwl_legacy_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
|
||||
int count, int slots_num, u32 id)
|
||||
{
|
||||
q->n_bd = count;
|
||||
q->n_window = slots_num;
|
||||
q->id = id;
|
||||
|
||||
/* count must be power-of-two size, otherwise iwl_legacy_queue_inc_wrap
|
||||
* and iwl_legacy_queue_dec_wrap are broken. */
|
||||
BUG_ON(!is_power_of_2(count));
|
||||
|
||||
/* slots_num must be power-of-two size, otherwise
|
||||
* iwl_legacy_get_cmd_index is broken. */
|
||||
BUG_ON(!is_power_of_2(slots_num));
|
||||
|
||||
q->low_mark = q->n_window / 4;
|
||||
if (q->low_mark < 4)
|
||||
q->low_mark = 4;
|
||||
|
||||
q->high_mark = q->n_window / 8;
|
||||
if (q->high_mark < 2)
|
||||
q->high_mark = 2;
|
||||
|
||||
q->write_ptr = q->read_ptr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
|
||||
*/
|
||||
static int iwl_legacy_tx_queue_alloc(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq, u32 id)
|
||||
{
|
||||
struct device *dev = &priv->pci_dev->dev;
|
||||
size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
|
||||
|
||||
/* Driver private data, only for Tx (not command) queues,
|
||||
* not shared with device. */
|
||||
if (id != priv->cmd_queue) {
|
||||
txq->txb = kzalloc(sizeof(txq->txb[0]) *
|
||||
TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
|
||||
if (!txq->txb) {
|
||||
IWL_ERR(priv, "kmalloc for auxiliary BD "
|
||||
"structures failed\n");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
txq->txb = NULL;
|
||||
}
|
||||
|
||||
/* Circular buffer of transmit frame descriptors (TFDs),
|
||||
* shared with device */
|
||||
txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
|
||||
GFP_KERNEL);
|
||||
if (!txq->tfds) {
|
||||
IWL_ERR(priv, "pci_alloc_consistent(%zd) failed\n", tfd_sz);
|
||||
goto error;
|
||||
}
|
||||
txq->q.id = id;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(txq->txb);
|
||||
txq->txb = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_tx_queue_init - Allocate and initialize one tx/cmd queue
|
||||
*/
|
||||
int iwl_legacy_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id)
|
||||
{
|
||||
int i, len;
|
||||
int ret;
|
||||
int actual_slots = slots_num;
|
||||
|
||||
/*
|
||||
* Alloc buffer array for commands (Tx or other types of commands).
|
||||
* For the command queue (#4/#9), allocate command space + one big
|
||||
* command for scan, since scan command is very huge; the system will
|
||||
* not have two scans at the same time, so only one is needed.
|
||||
* For normal Tx queues (all other queues), no super-size command
|
||||
* space is needed.
|
||||
*/
|
||||
if (txq_id == priv->cmd_queue)
|
||||
actual_slots++;
|
||||
|
||||
txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
|
||||
GFP_KERNEL);
|
||||
txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!txq->meta || !txq->cmd)
|
||||
goto out_free_arrays;
|
||||
|
||||
len = sizeof(struct iwl_device_cmd);
|
||||
for (i = 0; i < actual_slots; i++) {
|
||||
/* only happens for cmd queue */
|
||||
if (i == slots_num)
|
||||
len = IWL_MAX_CMD_SIZE;
|
||||
|
||||
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
|
||||
if (!txq->cmd[i])
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Alloc driver data array and TFD circular buffer */
|
||||
ret = iwl_legacy_tx_queue_alloc(priv, txq, txq_id);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
txq->need_update = 0;
|
||||
|
||||
/*
|
||||
* For the default queues 0-3, set up the swq_id
|
||||
* already -- all others need to get one later
|
||||
* (if they need one at all).
|
||||
*/
|
||||
if (txq_id < 4)
|
||||
iwl_legacy_set_swq_id(txq, txq_id, txq_id);
|
||||
|
||||
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
|
||||
* iwl_legacy_queue_inc_wrap and iwl_legacy_queue_dec_wrap are broken. */
|
||||
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
|
||||
|
||||
/* Initialize queue's high/low-water marks, and head/tail indexes */
|
||||
iwl_legacy_queue_init(priv, &txq->q,
|
||||
TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
|
||||
|
||||
/* Tell device where to find queue */
|
||||
priv->cfg->ops->lib->txq_init(priv, txq);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < actual_slots; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
out_free_arrays:
|
||||
kfree(txq->meta);
|
||||
kfree(txq->cmd);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_tx_queue_init);
|
||||
|
||||
void iwl_legacy_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id)
|
||||
{
|
||||
int actual_slots = slots_num;
|
||||
|
||||
if (txq_id == priv->cmd_queue)
|
||||
actual_slots++;
|
||||
|
||||
memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
|
||||
|
||||
txq->need_update = 0;
|
||||
|
||||
/* Initialize queue's high/low-water marks, and head/tail indexes */
|
||||
iwl_legacy_queue_init(priv, &txq->q,
|
||||
TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
|
||||
|
||||
/* Tell device where to find queue */
|
||||
priv->cfg->ops->lib->txq_init(priv, txq);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_tx_queue_reset);
|
||||
|
||||
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
|
||||
|
||||
/**
|
||||
* iwl_legacy_enqueue_hcmd - enqueue a uCode command
|
||||
* @priv: device private data point
|
||||
* @cmd: a point to the ucode command structure
|
||||
*
|
||||
* The function returns < 0 values to indicate the operation is
|
||||
* failed. On success, it turns the index (> 0) of command in the
|
||||
* command queue.
|
||||
*/
|
||||
int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
|
||||
struct iwl_queue *q = &txq->q;
|
||||
struct iwl_device_cmd *out_cmd;
|
||||
struct iwl_cmd_meta *out_meta;
|
||||
dma_addr_t phys_addr;
|
||||
unsigned long flags;
|
||||
int len;
|
||||
u32 idx;
|
||||
u16 fix_size;
|
||||
|
||||
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
|
||||
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
|
||||
|
||||
/* If any of the command structures end up being larger than
|
||||
* the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
|
||||
* we will need to increase the size of the TFD entries
|
||||
* Also, check to see if command buffer should not exceed the size
|
||||
* of device_cmd and max_cmd_size. */
|
||||
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
|
||||
!(cmd->flags & CMD_SIZE_HUGE));
|
||||
BUG_ON(fix_size > IWL_MAX_CMD_SIZE);
|
||||
|
||||
if (iwl_legacy_is_rfkill(priv) || iwl_legacy_is_ctkill(priv)) {
|
||||
IWL_WARN(priv, "Not sending command - %s KILL\n",
|
||||
iwl_legacy_is_rfkill(priv) ? "RF" : "CT");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
|
||||
IWL_ERR(priv, "No space in command queue\n");
|
||||
IWL_ERR(priv, "Restarting adapter due to queue full\n");
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->hcmd_lock, flags);
|
||||
|
||||
/* If this is a huge cmd, mark the huge flag also on the meta.flags
|
||||
* of the _original_ cmd. This is used for DMA mapping clean up.
|
||||
*/
|
||||
if (cmd->flags & CMD_SIZE_HUGE) {
|
||||
idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0);
|
||||
txq->meta[idx].flags = CMD_SIZE_HUGE;
|
||||
}
|
||||
|
||||
idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
|
||||
out_cmd = txq->cmd[idx];
|
||||
out_meta = &txq->meta[idx];
|
||||
|
||||
memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
|
||||
out_meta->flags = cmd->flags;
|
||||
if (cmd->flags & CMD_WANT_SKB)
|
||||
out_meta->source = cmd;
|
||||
if (cmd->flags & CMD_ASYNC)
|
||||
out_meta->callback = cmd->callback;
|
||||
|
||||
out_cmd->hdr.cmd = cmd->id;
|
||||
memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
|
||||
|
||||
/* At this point, the out_cmd now has all of the incoming cmd
|
||||
* information */
|
||||
|
||||
out_cmd->hdr.flags = 0;
|
||||
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
|
||||
INDEX_TO_SEQ(q->write_ptr));
|
||||
if (cmd->flags & CMD_SIZE_HUGE)
|
||||
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
|
||||
len = sizeof(struct iwl_device_cmd);
|
||||
if (idx == TFD_CMD_SLOTS)
|
||||
len = IWL_MAX_CMD_SIZE;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
|
||||
switch (out_cmd->hdr.cmd) {
|
||||
case REPLY_TX_LINK_QUALITY_CMD:
|
||||
case SENSITIVITY_CMD:
|
||||
IWL_DEBUG_HC_DUMP(priv,
|
||||
"Sending command %s (#%x), seq: 0x%04X, "
|
||||
"%d bytes at %d[%d]:%d\n",
|
||||
iwl_legacy_get_cmd_string(out_cmd->hdr.cmd),
|
||||
out_cmd->hdr.cmd,
|
||||
le16_to_cpu(out_cmd->hdr.sequence), fix_size,
|
||||
q->write_ptr, idx, priv->cmd_queue);
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
|
||||
"%d bytes at %d[%d]:%d\n",
|
||||
iwl_legacy_get_cmd_string(out_cmd->hdr.cmd),
|
||||
out_cmd->hdr.cmd,
|
||||
le16_to_cpu(out_cmd->hdr.sequence), fix_size,
|
||||
q->write_ptr, idx, priv->cmd_queue);
|
||||
}
|
||||
#endif
|
||||
txq->need_update = 1;
|
||||
|
||||
if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl)
|
||||
/* Set up entry in queue's byte count circular buffer */
|
||||
priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
|
||||
|
||||
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
|
||||
fix_size, PCI_DMA_BIDIRECTIONAL);
|
||||
dma_unmap_addr_set(out_meta, mapping, phys_addr);
|
||||
dma_unmap_len_set(out_meta, len, fix_size);
|
||||
|
||||
trace_iwlwifi_legacy_dev_hcmd(priv, &out_cmd->hdr,
|
||||
fix_size, cmd->flags);
|
||||
|
||||
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
|
||||
phys_addr, fix_size, 1,
|
||||
U32_PAD(cmd->len));
|
||||
|
||||
/* Increment and update queue's write index */
|
||||
q->write_ptr = iwl_legacy_queue_inc_wrap(q->write_ptr, q->n_bd);
|
||||
iwl_legacy_txq_update_write_ptr(priv, txq);
|
||||
|
||||
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
|
||||
*
|
||||
* When FW advances 'R' index, all entries between old and new 'R' index
|
||||
* need to be reclaimed. As result, some free space forms. If there is
|
||||
* enough free space (> low mark), wake the stack that feeds us.
|
||||
*/
|
||||
static void iwl_legacy_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
|
||||
int idx, int cmd_idx)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[txq_id];
|
||||
struct iwl_queue *q = &txq->q;
|
||||
int nfreed = 0;
|
||||
|
||||
if ((idx >= q->n_bd) || (iwl_legacy_queue_used(q, idx) == 0)) {
|
||||
IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
|
||||
"is out of range [0-%d] %d %d.\n", txq_id,
|
||||
idx, q->n_bd, q->write_ptr, q->read_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = iwl_legacy_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
|
||||
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||
|
||||
if (nfreed++ > 0) {
|
||||
IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
|
||||
q->write_ptr, q->read_ptr);
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_legacy_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
|
||||
* @rxb: Rx buffer to reclaim
|
||||
*
|
||||
* If an Rx buffer has an async callback associated with it the callback
|
||||
* will be executed. The attached skb (if present) will only be freed
|
||||
* if the callback returns 1
|
||||
*/
|
||||
void
|
||||
iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
|
||||
int txq_id = SEQ_TO_QUEUE(sequence);
|
||||
int index = SEQ_TO_INDEX(sequence);
|
||||
int cmd_index;
|
||||
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
|
||||
struct iwl_device_cmd *cmd;
|
||||
struct iwl_cmd_meta *meta;
|
||||
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
|
||||
|
||||
/* If a Tx command is being handled and it isn't in the actual
|
||||
* command queue then there a command routing bug has been introduced
|
||||
* in the queue management code. */
|
||||
if (WARN(txq_id != priv->cmd_queue,
|
||||
"wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
|
||||
txq_id, priv->cmd_queue, sequence,
|
||||
priv->txq[priv->cmd_queue].q.read_ptr,
|
||||
priv->txq[priv->cmd_queue].q.write_ptr)) {
|
||||
iwl_print_hex_error(priv, pkt, 32);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is a huge cmd, clear the huge flag on the meta.flags
|
||||
* of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap
|
||||
* the DMA buffer for the scan (huge) command.
|
||||
*/
|
||||
if (huge) {
|
||||
cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0);
|
||||
txq->meta[cmd_index].flags = 0;
|
||||
}
|
||||
cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge);
|
||||
cmd = txq->cmd[cmd_index];
|
||||
meta = &txq->meta[cmd_index];
|
||||
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
dma_unmap_addr(meta, mapping),
|
||||
dma_unmap_len(meta, len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
/* Input error checking is done when commands are added to queue. */
|
||||
if (meta->flags & CMD_WANT_SKB) {
|
||||
meta->source->reply_page = (unsigned long)rxb_addr(rxb);
|
||||
rxb->page = NULL;
|
||||
} else if (meta->callback)
|
||||
meta->callback(priv, cmd, pkt);
|
||||
|
||||
iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
|
||||
|
||||
if (!(meta->flags & CMD_ASYNC)) {
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
|
||||
iwl_legacy_get_cmd_string(cmd->hdr.cmd));
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
}
|
||||
meta->flags = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,18 +1,52 @@
|
|||
config IWLWIFI
|
||||
tristate "Intel Wireless Wifi"
|
||||
config IWLAGN
|
||||
tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) "
|
||||
depends on PCI && MAC80211
|
||||
select FW_LOADER
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select MAC80211_LEDS
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
Intel Wireless WiFi Link Next-Gen AGN
|
||||
|
||||
This option enables support for use with the following hardware:
|
||||
Intel Wireless WiFi Link 6250AGN Adapter
|
||||
Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN)
|
||||
Intel WiFi Link 1000BGN
|
||||
Intel Wireless WiFi 5150AGN
|
||||
Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
|
||||
Intel 6005 Series Wi-Fi Adapters
|
||||
Intel 6030 Series Wi-Fi Adapters
|
||||
Intel Wireless WiFi Link 6150BGN 2 Adapter
|
||||
Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN)
|
||||
Intel 2000 Series Wi-Fi Adapters
|
||||
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
|
||||
If you want to compile the driver as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want),
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwlagn.
|
||||
|
||||
menu "Debugging Options"
|
||||
depends on IWLWIFI
|
||||
depends on IWLAGN
|
||||
|
||||
config IWLWIFI_DEBUG
|
||||
bool "Enable full debugging output in iwlagn and iwl3945 drivers"
|
||||
depends on IWLWIFI
|
||||
bool "Enable full debugging output in the iwlagn driver"
|
||||
depends on IWLAGN
|
||||
---help---
|
||||
This option will enable debug tracing output for the iwlwifi drivers
|
||||
|
||||
|
@ -37,7 +71,7 @@ config IWLWIFI_DEBUG
|
|||
|
||||
config IWLWIFI_DEBUGFS
|
||||
bool "iwlagn debugfs support"
|
||||
depends on IWLWIFI && MAC80211_DEBUGFS
|
||||
depends on IWLAGN && MAC80211_DEBUGFS
|
||||
---help---
|
||||
Enable creation of debugfs files for the iwlwifi drivers. This
|
||||
is a low-impact option that allows getting insight into the
|
||||
|
@ -45,13 +79,13 @@ config IWLWIFI_DEBUGFS
|
|||
|
||||
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||
bool "Experimental uCode support"
|
||||
depends on IWLWIFI && IWLWIFI_DEBUG
|
||||
depends on IWLAGN && IWLWIFI_DEBUG
|
||||
---help---
|
||||
Enable use of experimental ucode for testing and debugging.
|
||||
|
||||
config IWLWIFI_DEVICE_TRACING
|
||||
bool "iwlwifi device access tracing"
|
||||
depends on IWLWIFI
|
||||
depends on IWLAGN
|
||||
depends on EVENT_TRACING
|
||||
help
|
||||
Say Y here to trace all commands, including TX frames and IO
|
||||
|
@ -68,57 +102,9 @@ config IWLWIFI_DEVICE_TRACING
|
|||
occur.
|
||||
endmenu
|
||||
|
||||
config IWLAGN
|
||||
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
|
||||
depends on IWLWIFI
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
Intel Wireless WiFi Link Next-Gen AGN
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
|
||||
If you want to compile the driver as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want),
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwlagn.
|
||||
|
||||
|
||||
config IWL4965
|
||||
bool "Intel Wireless WiFi 4965AGN"
|
||||
depends on IWLAGN
|
||||
---help---
|
||||
This option enables support for Intel Wireless WiFi Link 4965AGN
|
||||
|
||||
config IWL5000
|
||||
bool "Intel Wireless-N/Advanced-N/Ultimate-N WiFi Link"
|
||||
depends on IWLAGN
|
||||
---help---
|
||||
This option enables support for use with the following hardware:
|
||||
Intel Wireless WiFi Link 6250AGN Adapter
|
||||
Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN)
|
||||
Intel WiFi Link 1000BGN
|
||||
Intel Wireless WiFi 5150AGN
|
||||
Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
|
||||
Intel 6005 Series Wi-Fi Adapters
|
||||
Intel 6030 Series Wi-Fi Adapters
|
||||
Intel Wireless WiFi Link 6150BGN 2 Adapter
|
||||
Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN)
|
||||
Intel 2000 Series Wi-Fi Adapters
|
||||
|
||||
config IWL_P2P
|
||||
bool "iwlwifi experimental P2P support"
|
||||
depends on IWL5000
|
||||
depends on IWLAGN
|
||||
help
|
||||
This option enables experimental P2P support for some devices
|
||||
based on microcode support. Since P2P support is still under
|
||||
|
@ -132,27 +118,3 @@ config IWL_P2P
|
|||
|
||||
Say Y only if you want to experiment with P2P.
|
||||
|
||||
config IWL3945
|
||||
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
|
||||
depends on IWLWIFI
|
||||
---help---
|
||||
Select to build the driver supporting the:
|
||||
|
||||
Intel PRO/Wireless 3945ABG/BG Network Connection
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
|
||||
If you want to compile the driver as a module ( = code which can be
|
||||
inserted in and removed from the running kernel whenever you want),
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwl3945.
|
||||
|
|
|
@ -1,36 +1,23 @@
|
|||
obj-$(CONFIG_IWLWIFI) += iwlcore.o
|
||||
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
|
||||
iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o
|
||||
iwlcore-objs += iwl-scan.o iwl-led.o
|
||||
iwlcore-$(CONFIG_IWL3945) += iwl-legacy.o
|
||||
iwlcore-$(CONFIG_IWL4965) += iwl-legacy.o
|
||||
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
|
||||
iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
|
||||
|
||||
# If 3945 is selected only, iwl-legacy.o will be added
|
||||
# to iwlcore-m above, but it needs to be built in.
|
||||
iwlcore-objs += $(iwlcore-m)
|
||||
|
||||
CFLAGS_iwl-devtrace.o := -I$(src)
|
||||
|
||||
# AGN
|
||||
obj-$(CONFIG_IWLAGN) += iwlagn.o
|
||||
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
|
||||
iwlagn-objs += iwl-agn-ucode.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-calib.o
|
||||
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
|
||||
|
||||
iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
|
||||
iwlagn-objs += iwl-rx.o iwl-tx.o iwl-sta.o
|
||||
iwlagn-objs += iwl-scan.o iwl-led.o
|
||||
iwlagn-objs += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o
|
||||
iwlagn-objs += iwl-5000.o
|
||||
iwlagn-objs += iwl-6000.o
|
||||
iwlagn-objs += iwl-1000.o
|
||||
iwlagn-objs += iwl-2000.o
|
||||
|
||||
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
|
||||
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
|
||||
iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
|
||||
|
||||
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
|
||||
iwlagn-$(CONFIG_IWL5000) += iwl-2000.o
|
||||
|
||||
# 3945
|
||||
obj-$(CONFIG_IWL3945) += iwl3945.o
|
||||
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
|
||||
iwl3945-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-3945-debugfs.o
|
||||
CFLAGS_iwl-devtrace.o := -I$(src)
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
|
|
@ -232,8 +232,6 @@ static struct iwl_lib_ops iwl1000_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
|
|
@ -315,8 +315,6 @@ static struct iwl_lib_ops iwl2000_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
@ -418,6 +416,7 @@ static struct iwl_bt_params iwl2030_bt_params = {
|
|||
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
|
||||
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
|
||||
.bt_sco_disable = true,
|
||||
.bt_session_2 = true,
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_2000 \
|
||||
|
|
|
@ -402,8 +402,6 @@ static struct iwl_lib_ops iwl5000_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
@ -471,8 +469,6 @@ static struct iwl_lib_ops iwl5150_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
|
|
@ -343,8 +343,6 @@ static struct iwl_lib_ops iwl6000_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
@ -415,8 +413,6 @@ static struct iwl_lib_ops iwl6030_lib = {
|
|||
.bt_stats_read = iwl_ucode_bt_stats_read,
|
||||
.reply_tx_error = iwl_reply_tx_error_read,
|
||||
},
|
||||
.check_plcp_health = iwl_good_plcp_health,
|
||||
.check_ack_health = iwl_good_ack_health,
|
||||
.txfifo_flush = iwlagn_txfifo_flush,
|
||||
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
|
||||
.tt_ops = {
|
||||
|
|
|
@ -609,6 +609,7 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
|
|||
struct iwl_mod_params iwlagn_mod_params = {
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
.plcp_check = true,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
|
||||
|
@ -1173,7 +1174,7 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
|
|||
|
||||
/* TSF isn't reliable. In order to allow smooth user experience,
|
||||
* this W/A doesn't propagate it to the mac80211 */
|
||||
/*rx_status.flag |= RX_FLAG_TSFT;*/
|
||||
/*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
|
||||
|
||||
priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
|
||||
|
||||
|
@ -1804,26 +1805,39 @@ static const __le32 iwlagn_concurrent_lookup[12] = {
|
|||
|
||||
void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwlagn_bt_cmd bt_cmd = {
|
||||
struct iwl_basic_bt_cmd basic = {
|
||||
.max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
|
||||
.bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
|
||||
.bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
|
||||
.bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
|
||||
};
|
||||
struct iwl6000_bt_cmd bt_cmd_6000;
|
||||
struct iwl2000_bt_cmd bt_cmd_2000;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
|
||||
sizeof(bt_cmd.bt3_lookup_table));
|
||||
sizeof(basic.bt3_lookup_table));
|
||||
|
||||
if (priv->cfg->bt_params)
|
||||
bt_cmd.prio_boost = priv->cfg->bt_params->bt_prio_boost;
|
||||
else
|
||||
bt_cmd.prio_boost = 0;
|
||||
bt_cmd.kill_ack_mask = priv->kill_ack_mask;
|
||||
bt_cmd.kill_cts_mask = priv->kill_cts_mask;
|
||||
if (priv->cfg->bt_params) {
|
||||
if (priv->cfg->bt_params->bt_session_2) {
|
||||
bt_cmd_2000.prio_boost = cpu_to_le32(
|
||||
priv->cfg->bt_params->bt_prio_boost);
|
||||
bt_cmd_2000.tx_prio_boost = 0;
|
||||
bt_cmd_2000.rx_prio_boost = 0;
|
||||
} else {
|
||||
bt_cmd_6000.prio_boost =
|
||||
priv->cfg->bt_params->bt_prio_boost;
|
||||
bt_cmd_6000.tx_prio_boost = 0;
|
||||
bt_cmd_6000.rx_prio_boost = 0;
|
||||
}
|
||||
} else {
|
||||
IWL_ERR(priv, "failed to construct BT Coex Config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_cmd.valid = priv->bt_valid;
|
||||
bt_cmd.tx_prio_boost = 0;
|
||||
bt_cmd.rx_prio_boost = 0;
|
||||
basic.kill_ack_mask = priv->kill_ack_mask;
|
||||
basic.kill_cts_mask = priv->kill_cts_mask;
|
||||
basic.valid = priv->bt_valid;
|
||||
|
||||
/*
|
||||
* Configure BT coex mode to "no coexistence" when the
|
||||
|
@ -1832,32 +1846,43 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
|
|||
* IBSS mode (no proper uCode support for coex then).
|
||||
*/
|
||||
if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) {
|
||||
bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
|
||||
basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
|
||||
} else {
|
||||
bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
|
||||
basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
|
||||
IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
|
||||
if (priv->cfg->bt_params &&
|
||||
priv->cfg->bt_params->bt_sco_disable)
|
||||
bt_cmd.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
|
||||
basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
|
||||
|
||||
if (priv->bt_ch_announce)
|
||||
bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
|
||||
IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags);
|
||||
basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
|
||||
IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", basic.flags);
|
||||
}
|
||||
priv->bt_enable_flag = bt_cmd.flags;
|
||||
priv->bt_enable_flag = basic.flags;
|
||||
if (priv->bt_full_concurrent)
|
||||
memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup,
|
||||
memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
|
||||
sizeof(iwlagn_concurrent_lookup));
|
||||
else
|
||||
memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup,
|
||||
memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
|
||||
sizeof(iwlagn_def_3w_lookup));
|
||||
|
||||
IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n",
|
||||
bt_cmd.flags ? "active" : "disabled",
|
||||
basic.flags ? "active" : "disabled",
|
||||
priv->bt_full_concurrent ?
|
||||
"full concurrency" : "3-wire");
|
||||
|
||||
if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd))
|
||||
if (priv->cfg->bt_params->bt_session_2) {
|
||||
memcpy(&bt_cmd_2000.basic, &basic,
|
||||
sizeof(basic));
|
||||
ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
sizeof(bt_cmd_2000), &bt_cmd_2000);
|
||||
} else {
|
||||
memcpy(&bt_cmd_6000.basic, &basic,
|
||||
sizeof(basic));
|
||||
ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
|
||||
sizeof(bt_cmd_6000), &bt_cmd_6000);
|
||||
}
|
||||
if (ret)
|
||||
IWL_ERR(priv, "failed to send BT Coex Config\n");
|
||||
|
||||
}
|
||||
|
@ -1984,12 +2009,14 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv,
|
|||
(BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
|
||||
BT_UART_MSG_FRAME6DISCOVERABLE_POS);
|
||||
|
||||
IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = "
|
||||
"0x%X, Connectable = 0x%X",
|
||||
IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Page = "
|
||||
"0x%X, Inquiry = 0x%X, Connectable = 0x%X",
|
||||
(BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
|
||||
BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
|
||||
(BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >>
|
||||
BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS,
|
||||
(BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
|
||||
BT_UART_MSG_FRAME7PAGE_POS,
|
||||
(BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
|
||||
BT_UART_MSG_FRAME7INQUIRY_POS,
|
||||
(BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
|
||||
BT_UART_MSG_FRAME7CONNECTABLE_POS);
|
||||
}
|
||||
|
|
|
@ -471,6 +471,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
|||
struct iwl_rxon_context *tmp;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
||||
struct ieee80211_sta_ht_cap *ht_cap;
|
||||
bool need_multiple;
|
||||
|
||||
lockdep_assert_held(&priv->mutex);
|
||||
|
@ -479,23 +480,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
|||
case NL80211_IFTYPE_STATION:
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, bss_conf->bssid);
|
||||
if (sta) {
|
||||
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
int maxstreams;
|
||||
|
||||
maxstreams = (ht_cap->mcs.tx_params &
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
|
||||
>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
|
||||
maxstreams += 1;
|
||||
|
||||
need_multiple = true;
|
||||
|
||||
if ((ht_cap->mcs.rx_mask[1] == 0) &&
|
||||
(ht_cap->mcs.rx_mask[2] == 0))
|
||||
need_multiple = false;
|
||||
if (maxstreams <= 1)
|
||||
need_multiple = false;
|
||||
} else {
|
||||
if (!sta) {
|
||||
/*
|
||||
* If at all, this can only happen through a race
|
||||
* when the AP disconnects us while we're still
|
||||
|
@ -503,7 +488,46 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
|
|||
* will soon tell us about that.
|
||||
*/
|
||||
need_multiple = false;
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
ht_cap = &sta->ht_cap;
|
||||
|
||||
need_multiple = true;
|
||||
|
||||
/*
|
||||
* If the peer advertises no support for receiving 2 and 3
|
||||
* stream MCS rates, it can't be transmitting them either.
|
||||
*/
|
||||
if (ht_cap->mcs.rx_mask[1] == 0 &&
|
||||
ht_cap->mcs.rx_mask[2] == 0) {
|
||||
need_multiple = false;
|
||||
} else if (!(ht_cap->mcs.tx_params &
|
||||
IEEE80211_HT_MCS_TX_DEFINED)) {
|
||||
/* If it can't TX MCS at all ... */
|
||||
need_multiple = false;
|
||||
} else if (ht_cap->mcs.tx_params &
|
||||
IEEE80211_HT_MCS_TX_RX_DIFF) {
|
||||
int maxstreams;
|
||||
|
||||
/*
|
||||
* But if it can receive them, it might still not
|
||||
* be able to transmit them, which is what we need
|
||||
* to check here -- so check the number of streams
|
||||
* it advertises for TX (if different from RX).
|
||||
*/
|
||||
|
||||
maxstreams = (ht_cap->mcs.tx_params &
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
|
||||
maxstreams >>=
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
|
||||
maxstreams += 1;
|
||||
|
||||
if (maxstreams <= 1)
|
||||
need_multiple = false;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
|
|
|
@ -947,7 +947,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
|
|||
*/
|
||||
void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
|
||||
{
|
||||
int ch;
|
||||
int ch, txq_id;
|
||||
unsigned long flags;
|
||||
|
||||
/* Turn off all Tx DMA fifos */
|
||||
|
@ -966,6 +966,16 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
|
|||
iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (!priv->txq)
|
||||
return;
|
||||
|
||||
/* Unmap DMA from host system and free skb's */
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
|
||||
if (txq_id == priv->cmd_queue)
|
||||
iwl_cmd_queue_unmap(priv);
|
||||
else
|
||||
iwl_tx_queue_unmap(priv, txq_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -86,7 +86,6 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
|||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("iwl4965");
|
||||
|
||||
static int iwlagn_ant_coupling;
|
||||
static bool iwlagn_bt_ch_announce = 1;
|
||||
|
@ -466,6 +465,15 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
|
|||
IWL_WARN(priv, "%s uCode did not respond OK.\n",
|
||||
(palive->ver_subtype == INITIALIZE_SUBTYPE) ?
|
||||
"init" : "runtime");
|
||||
/*
|
||||
* If fail to load init uCode,
|
||||
* let's try to load the init uCode again.
|
||||
* We should not get into this situation, but if it
|
||||
* does happen, we should not move on and loading "runtime"
|
||||
* without proper calibrate the device.
|
||||
*/
|
||||
if (palive->ver_subtype == INITIALIZE_SUBTYPE)
|
||||
priv->ucode_type = UCODE_NONE;
|
||||
queue_work(priv->workqueue, &priv->restart);
|
||||
}
|
||||
}
|
||||
|
@ -1405,72 +1413,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|||
iwl_enable_rfkill_int(priv);
|
||||
}
|
||||
|
||||
/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
|
||||
#define ACK_CNT_RATIO (50)
|
||||
#define BA_TIMEOUT_CNT (5)
|
||||
#define BA_TIMEOUT_MAX (16)
|
||||
|
||||
/**
|
||||
* iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
|
||||
*
|
||||
* When the ACK count ratio is low and aggregated BA timeout retries exceeding
|
||||
* the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
|
||||
* operation state.
|
||||
*/
|
||||
bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt)
|
||||
{
|
||||
int actual_delta, expected_delta, ba_timeout_delta;
|
||||
struct statistics_tx *cur, *old;
|
||||
|
||||
if (priv->_agn.agg_tids_count)
|
||||
return true;
|
||||
|
||||
if (iwl_bt_statistics(priv)) {
|
||||
cur = &pkt->u.stats_bt.tx;
|
||||
old = &priv->_agn.statistics_bt.tx;
|
||||
} else {
|
||||
cur = &pkt->u.stats.tx;
|
||||
old = &priv->_agn.statistics.tx;
|
||||
}
|
||||
|
||||
actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
|
||||
le32_to_cpu(old->actual_ack_cnt);
|
||||
expected_delta = le32_to_cpu(cur->expected_ack_cnt) -
|
||||
le32_to_cpu(old->expected_ack_cnt);
|
||||
|
||||
/* Values should not be negative, but we do not trust the firmware */
|
||||
if (actual_delta <= 0 || expected_delta <= 0)
|
||||
return true;
|
||||
|
||||
ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) -
|
||||
le32_to_cpu(old->agg.ba_timeout);
|
||||
|
||||
if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO &&
|
||||
ba_timeout_delta > BA_TIMEOUT_CNT) {
|
||||
IWL_DEBUG_RADIO(priv, "deltas: actual %d expected %d ba_timeout %d\n",
|
||||
actual_delta, expected_delta, ba_timeout_delta);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
/*
|
||||
* This is ifdef'ed on DEBUGFS because otherwise the
|
||||
* statistics aren't available. If DEBUGFS is set but
|
||||
* DEBUG is not, these will just compile out.
|
||||
*/
|
||||
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
|
||||
priv->_agn.delta_statistics.tx.rx_detected_cnt);
|
||||
IWL_DEBUG_RADIO(priv,
|
||||
"ack_or_ba_timeout_collision delta %d\n",
|
||||
priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision);
|
||||
#endif
|
||||
|
||||
if (ba_timeout_delta >= BA_TIMEOUT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* sysfs attributes
|
||||
|
@ -2735,9 +2677,11 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|||
priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
|
||||
}
|
||||
|
||||
if (priv->cfg->bt_params &&
|
||||
!priv->cfg->bt_params->advanced_bt_coexist) {
|
||||
/* Configure Bluetooth device coexistence support */
|
||||
if (!priv->cfg->bt_params || (priv->cfg->bt_params &&
|
||||
!priv->cfg->bt_params->advanced_bt_coexist)) {
|
||||
/*
|
||||
* default is 2-wire BT coexexistence support
|
||||
*/
|
||||
priv->cfg->ops->hcmd->send_bt_config(priv);
|
||||
}
|
||||
|
||||
|
@ -3320,7 +3264,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw)
|
|||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
|
||||
|
@ -3333,7 +3277,6 @@ int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
dev_kfree_skb_any(skb);
|
||||
|
||||
IWL_DEBUG_MACDUMP(priv, "leave\n");
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
|
@ -3799,7 +3742,6 @@ static void iwlagn_bg_roc_done(struct work_struct *work)
|
|||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWL5000
|
||||
static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type,
|
||||
|
@ -3855,7 +3797,6 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
|
@ -4025,7 +3966,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
|
|||
kfree(priv->scan_cmd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWL5000
|
||||
struct ieee80211_ops iwlagn_hw_ops = {
|
||||
.tx = iwlagn_mac_tx,
|
||||
.start = iwlagn_mac_start,
|
||||
|
@ -4050,7 +3990,6 @@ struct ieee80211_ops iwlagn_hw_ops = {
|
|||
.remain_on_channel = iwl_mac_remain_on_channel,
|
||||
.cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void iwl_hw_detect(struct iwl_priv *priv)
|
||||
{
|
||||
|
@ -4118,12 +4057,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if (cfg->mod_params->disable_hw_scan) {
|
||||
dev_printk(KERN_DEBUG, &(pdev->dev),
|
||||
"sw scan support is deprecated\n");
|
||||
#ifdef CONFIG_IWL5000
|
||||
iwlagn_hw_ops.hw_scan = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_IWL4965
|
||||
iwl4965_hw_ops.hw_scan = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
hw = iwl_alloc_all(cfg);
|
||||
|
@ -4502,12 +4436,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
/* Hardware specific file defines the PCI IDs table for that hardware module */
|
||||
static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
||||
#ifdef CONFIG_IWL4965
|
||||
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
#endif /* CONFIG_IWL4965 */
|
||||
#ifdef CONFIG_IWL5000
|
||||
/* 5100 Series WiFi */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
|
@ -4693,8 +4621,6 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
|||
{IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)},
|
||||
|
||||
#endif /* CONFIG_IWL5000 */
|
||||
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
|
||||
|
@ -4793,3 +4719,9 @@ MODULE_PARM_DESC(antenna_coupling,
|
|||
module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(bt_ch_inhibition,
|
||||
"Disable BT channel inhibition (default: enable)");
|
||||
|
||||
module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
|
||||
|
||||
module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
|
||||
|
|
|
@ -121,8 +121,6 @@ void iwl_disable_ict(struct iwl_priv *priv);
|
|||
int iwl_alloc_isr_ict(struct iwl_priv *priv);
|
||||
void iwl_free_isr_ict(struct iwl_priv *priv);
|
||||
irqreturn_t iwl_isr_ict(int irq, void *data);
|
||||
bool iwl_good_ack_health(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
/* tx queue */
|
||||
void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
|
||||
|
@ -248,8 +246,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
|
|||
/* rx */
|
||||
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
bool iwl_good_plcp_health(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl_rx_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_reply_statistics(struct iwl_priv *priv,
|
||||
|
@ -356,7 +352,7 @@ iwlagn_remove_notification(struct iwl_priv *priv,
|
|||
struct iwl_notification_wait *wait_entry);
|
||||
|
||||
/* mac80211 handlers (for 4965) */
|
||||
int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
int iwlagn_mac_start(struct ieee80211_hw *hw);
|
||||
void iwlagn_mac_stop(struct ieee80211_hw *hw);
|
||||
void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue