Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-08-28 23:06:05 -07:00
commit b7f1d43a2b
100 changed files with 4341 additions and 2701 deletions

View file

@ -2653,25 +2653,21 @@ F: drivers/net/ixgbe/
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
M: Zhu Yi <yi.zhu@intel.com>
M: James Ketrenos <jketreno@linux.intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
L: ipw2100-devel@lists.sourceforge.net
W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
W: http://ipw2100.sourceforge.net
S: Supported
S: Odd Fixes
F: Documentation/networking/README.ipw2100
F: drivers/net/wireless/ipw2x00/ipw2100.*
INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
M: Zhu Yi <yi.zhu@intel.com>
M: James Ketrenos <jketreno@linux.intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
L: ipw2100-devel@lists.sourceforge.net
W: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
W: http://ipw2200.sourceforge.net
S: Supported
S: Odd Fixes
F: Documentation/networking/README.ipw2200
F: drivers/net/wireless/ipw2x00/ipw2200.*
@ -2688,8 +2684,8 @@ F: include/linux/wimax/i2400m.h
INTEL WIRELESS WIFI LINK (iwlwifi)
M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
L: ipw3945-devel@lists.sourceforge.net
W: http://intellinuxwireless.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
S: Supported

View file

@ -178,6 +178,7 @@ struct ar9170 {
/* beaconing */
struct sk_buff *beacon;
struct work_struct beacon_work;
bool enable_beacon;
/* cryptographic engine */
u64 usedkeys;

View file

@ -383,24 +383,26 @@ int ar9170_set_beacon_timers(struct ar9170 *ar)
if (ar->vif) {
v |= ar->vif->bss_conf.beacon_int;
switch (ar->vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
v |= BIT(25);
break;
case NL80211_IFTYPE_AP:
v |= BIT(24);
pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16;
break;
default:
if (ar->enable_beacon) {
switch (ar->vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
v |= BIT(25);
break;
case NL80211_IFTYPE_AP:
v |= BIT(24);
pretbtt = (ar->vif->bss_conf.beacon_int - 6) <<
16;
break;
default:
break;
}
}
v |= ar->vif->bss_conf.dtim_period << 16;
}
ar9170_regwrite_begin(ar);
ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
ar9170_regwrite_finish();

View file

@ -2031,12 +2031,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
if (changed & BSS_CHANGED_BEACON_INT) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
/* adjust slot time for 5 GHz */
@ -2148,11 +2142,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
if (changed & BSS_CHANGED_BEACON_ENABLED)
ar->enable_beacon = bss_conf->enable_beacon;
if (changed & BSS_CHANGED_BEACON) {
err = ar9170_update_beacon(ar);
if (err)
goto out;
}
if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_INT)) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
@ -2165,12 +2165,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
#endif /* CONFIG_AR9170_LEDS */
}
if (changed & BSS_CHANGED_BEACON_INT) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
}
if (changed & BSS_CHANGED_HT) {
/* TODO */
err = 0;

View file

@ -306,6 +306,7 @@ struct ath5k_srev_name {
#define AR5K_SREV_AR5311B 0x30 /* Spirit */
#define AR5K_SREV_AR5211 0x40 /* Oahu */
#define AR5K_SREV_AR5212 0x50 /* Venice */
#define AR5K_SREV_AR5212_V4 0x54 /* ??? */
#define AR5K_SREV_AR5213 0x55 /* ??? */
#define AR5K_SREV_AR5213A 0x59 /* Hainan */
#define AR5K_SREV_AR2413 0x78 /* Griffin lite */
@ -1037,6 +1038,7 @@ struct ath5k_hw {
bool ah_turbo;
bool ah_calibration;
bool ah_single_chip;
bool ah_aes_support;
bool ah_combined_mic;
enum ath5k_version ah_version;
@ -1158,7 +1160,7 @@ struct ath5k_hw {
*/
/* Attach/Detach Functions */
extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc);
extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* LED functions */

View file

@ -95,17 +95,17 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
* ath5k_hw_attach - Check if hw is supported and init the needed structs
*
* @sc: The &struct ath5k_softc we got from the driver's attach function
* @mac_version: The mac version id (check out ath5k.h) based on pci id
*
* Check if the device is supported, perform a POST and initialize the needed
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
{
struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev;
struct ath5k_eeprom_info *ee;
int ret;
u32 srev;
@ -135,9 +135,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ah->ah_software_retry = false;
/*
* Set the mac version based on the pci id
* Find the mac version
*/
ah->ah_version = mac_version;
srev = ath5k_hw_reg_read(ah, AR5K_SREV);
if (srev < AR5K_SREV_AR5311)
ah->ah_version = AR5K_AR5210;
else if (srev < AR5K_SREV_AR5212)
ah->ah_version = AR5K_AR5211;
else
ah->ah_version = AR5K_AR5212;
/*Fill the ath5k_hw struct with the needed functions*/
ret = ath5k_hw_init_desc_functions(ah);
@ -150,7 +156,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
/* Get MAC, PHY and RADIO revisions */
srev = ath5k_hw_reg_read(ah, AR5K_SREV);
ah->ah_mac_srev = srev;
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
@ -315,6 +320,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
/* Crypto settings */
ee = &ah->ah_capabilities.cap_eeprom;
ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
!AR5K_EEPROM_AES_DIS(ee->ee_misc5));
if (srev >= AR5K_SREV_AR2414) {
ah->ah_combined_mic = true;
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,

View file

@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
/* Known PCI ids */
static const struct pci_device_id ath5k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
{ PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
{ PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
{ PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
{ PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
{ PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
{ PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
{ PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
{ PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
{ PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */
{ PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */
{ PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
{ PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
{ PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
{ PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
{ PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
{ PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */
{ PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */
{ PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
{ PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
{ PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
{ PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
{ PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
{ PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
@ -566,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
}
/* Initialize device */
sc->ah = ath5k_hw_attach(sc, id->driver_data);
sc->ah = ath5k_hw_attach(sc);
if (IS_ERR(sc->ah)) {
ret = PTR_ERR(sc->ah);
goto err_irq;
@ -1741,7 +1741,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
static void
ath5k_tasklet_rx(unsigned long data)
{
struct ieee80211_rx_status rxs = {};
struct ieee80211_rx_status *rxs;
struct ath5k_rx_status rs = {};
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
@ -1751,6 +1751,7 @@ ath5k_tasklet_rx(unsigned long data)
int ret;
int hdrlen;
int padsize;
int rx_flag;
spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) {
@ -1758,7 +1759,7 @@ ath5k_tasklet_rx(unsigned long data)
goto unlock;
}
do {
rxs.flag = 0;
rx_flag = 0;
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
@ -1802,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data)
goto accept;
}
if (rs.rs_status & AR5K_RXERR_MIC) {
rxs.flag |= RX_FLAG_MMIC_ERROR;
rx_flag |= RX_FLAG_MMIC_ERROR;
goto accept;
}
@ -1840,6 +1841,7 @@ ath5k_tasklet_rx(unsigned long data)
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
rxs = IEEE80211_SKB_RXCB(skb);
/*
* always extend the mac timestamp, since this information is
@ -1861,41 +1863,40 @@ ath5k_tasklet_rx(unsigned long data)
* impossible to comply to that. This affects IBSS merge only
* right now, so it's not too bad...
*/
rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
rxs.flag |= RX_FLAG_TSFT;
rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
rxs->flag = rx_flag | RX_FLAG_TSFT;
rxs.freq = sc->curchan->center_freq;
rxs.band = sc->curband->band;
rxs->freq = sc->curchan->center_freq;
rxs->band = sc->curband->band;
rxs.noise = sc->ah->ah_noise_floor;
rxs.signal = rxs.noise + rs.rs_rssi;
rxs->noise = sc->ah->ah_noise_floor;
rxs->signal = rxs->noise + rs.rs_rssi;
/* An rssi of 35 indicates you should be able use
* 54 Mbps reliably. A more elaborate scheme can be used
* here but it requires a map of SNR/throughput for each
* possible mode used */
rxs.qual = rs.rs_rssi * 100 / 35;
rxs->qual = rs.rs_rssi * 100 / 35;
/* rssi can be more than 35 though, anything above that
* should be considered at 100% */
if (rxs.qual > 100)
rxs.qual = 100;
if (rxs->qual > 100)
rxs->qual = 100;
rxs.antenna = rs.rs_antenna;
rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
rxs->antenna = rs.rs_antenna;
rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
if (rxs.rate_idx >= 0 && rs.rs_rate ==
sc->curband->bitrates[rxs.rate_idx].hw_value_short)
rxs.flag |= RX_FLAG_SHORTPRE;
if (rxs->rate_idx >= 0 && rs.rs_rate ==
sc->curband->bitrates[rxs->rate_idx].hw_value_short)
rxs->flag |= RX_FLAG_SHORTPRE;
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
/* check beacons in IBSS mode */
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_check_ibss_tsf(sc, skb, &rxs);
ath5k_check_ibss_tsf(sc, skb, rxs);
memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
@ -2918,6 +2919,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
struct ath5k_hw *ah = sc->ah;
u32 mfilt[2], rfilt;
mutex_lock(&sc->lock);
mfilt[0] = multicast;
mfilt[1] = multicast >> 32;
@ -2968,22 +2971,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
if (sc->opmode == NL80211_IFTYPE_MONITOR)
rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
if (sc->opmode != NL80211_IFTYPE_STATION)
rfilt |= AR5K_RX_FILTER_PROBEREQ;
if (sc->opmode != NL80211_IFTYPE_AP &&
sc->opmode != NL80211_IFTYPE_MESH_POINT &&
test_bit(ATH_STAT_PROMISC, sc->status))
rfilt |= AR5K_RX_FILTER_PROM;
if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
sc->opmode == NL80211_IFTYPE_ADHOC ||
sc->opmode == NL80211_IFTYPE_AP)
rfilt |= AR5K_RX_FILTER_BEACON;
if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
switch (sc->opmode) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_MONITOR:
rfilt |= AR5K_RX_FILTER_CONTROL |
AR5K_RX_FILTER_BEACON |
AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_PROM;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
rfilt |= AR5K_RX_FILTER_PROBEREQ |
AR5K_RX_FILTER_BEACON;
break;
case NL80211_IFTYPE_STATION:
if (sc->assoc)
rfilt |= AR5K_RX_FILTER_BEACON;
default:
break;
}
/* Set filters */
ath5k_hw_set_rx_filter(ah, rfilt);
@ -2993,6 +2999,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* Set the cached hw filter flags, this will alter actually
* be set in HW */
sc->filter_flags = rfilt;
mutex_unlock(&sc->lock);
}
static int
@ -3014,6 +3022,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case ALG_TKIP:
break;
case ALG_CCMP:
if (sc->ah->ah_aes_support)
break;
return -EOPNOTSUPP;
default:
WARN_ON(1);

View file

@ -414,27 +414,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
break;
}
done:
/* return new offset */
*offset = o;
return 0;
}
/*
* Read turbo mode information on newer EEPROM versions
*/
static int
ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
u32 *offset, unsigned int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u32 o = *offset;
u16 val;
int ret;
/*
* Read turbo mode information on newer EEPROM versions
*/
if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
return 0;
goto done;
switch (mode){
case AR5K_EEPROM_MODE_11A:
@ -468,6 +452,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
break;
}
done:
/* return new offset */
*offset = o;
@ -504,10 +489,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
if (ret)
return ret;
ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
if (ret)
return ret;
}
/* override for older eeprom versions for better performance */

View file

@ -69,6 +69,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
{ ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
/* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */
{ ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) },
/* HP Compaq C700 (nitrousnrg@gmail.com) */
{ ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
/* IBM-specific AR5212 (all others) */
{ PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
{ }

View file

@ -12,7 +12,8 @@ ath9k-y += hw.o \
recv.o \
xmit.o \
virtual.o \
rc.o
rc.o \
btcoex.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o

View file

@ -26,6 +26,7 @@
#include "rc.h"
#include "debug.h"
#include "../ath.h"
#include "btcoex.h"
struct ath_node;
@ -521,6 +522,8 @@ struct ath_led {
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
#define SC_OP_BTCOEX_ENABLED BIT(20)
#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);
@ -609,6 +612,7 @@ struct ath_softc {
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
struct ath_btcoex_info btcoex_info;
};
struct ath_wiphy {
@ -705,4 +709,5 @@ bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */

View file

@ -0,0 +1,319 @@
/*
* Copyright (c) 2009 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "ath9k.h"
static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
/*
* Detects if there is any priority bt traffic
*/
static void ath_detect_bt_priority(struct ath_softc *sc)
{
struct ath_btcoex_info *btinfo = &sc->btcoex_info;
if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
btinfo->bt_priority_cnt++;
if (time_after(jiffies, btinfo->bt_priority_time +
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
DPRINTF(sc, ATH_DBG_BTCOEX,
"BT priority traffic detected");
sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
} else {
sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
}
btinfo->bt_priority_cnt = 0;
btinfo->bt_priority_time = jiffies;
}
}
/*
* Configures appropriate weight based on stomp type.
*/
static void ath_btcoex_bt_stomp(struct ath_softc *sc,
struct ath_btcoex_info *btinfo,
int stomp_type)
{
switch (stomp_type) {
case ATH_BTCOEX_STOMP_ALL:
ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
AR_STOMP_ALL_WLAN_WGHT);
break;
case ATH_BTCOEX_STOMP_LOW:
ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
AR_STOMP_LOW_WLAN_WGHT);
break;
case ATH_BTCOEX_STOMP_NONE:
ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
AR_STOMP_NONE_WLAN_WGHT);
break;
default:
DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
break;
}
ath9k_hw_btcoex_enable(sc->sc_ah);
}
/*
* This is the master bt coex timer which runs for every
* 45ms, bt traffic will be given priority during 55% of this
* period while wlan gets remaining 45%
*/
static void ath_btcoex_period_timer(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *) data;
struct ath_btcoex_info *btinfo = &sc->btcoex_info;
unsigned long flags;
ath_detect_bt_priority(sc);
spin_lock_irqsave(&btinfo->btcoex_lock, flags);
ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
spin_unlock_irqrestore(&btinfo->btcoex_lock, flags);
if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
if (btinfo->hw_timer_enabled)
ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
ath_gen_timer_start(sc->sc_ah,
btinfo->no_stomp_timer,
(ath9k_hw_gettsf32(sc->sc_ah) +
btinfo->btcoex_no_stomp),
btinfo->btcoex_no_stomp * 10);
btinfo->hw_timer_enabled = true;
}
mod_timer(&btinfo->period_timer, jiffies +
msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
}
/*
* Generic tsf based hw timer which configures weight
* registers to time slice between wlan and bt traffic
*/
static void ath_btcoex_no_stomp_timer(void *arg)
{
struct ath_softc *sc = (struct ath_softc *)arg;
struct ath_btcoex_info *btinfo = &sc->btcoex_info;
unsigned long flags;
DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
spin_lock_irqsave(&btinfo->btcoex_lock, flags);
if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
spin_unlock_irqrestore(&btinfo->btcoex_lock, flags);
}
static int ath_init_btcoex_info(struct ath_hw *hw,
struct ath_btcoex_info *btcoex_info)
{
u32 i;
int qnum;
qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
btcoex_info->bt_coex_mode =
(btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
SM(ath_bt_config.bt_mode, AR_BT_MODE) |
SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
SM(qnum, AR_BT_QCU_THRESH);
btcoex_info->bt_coex_mode2 =
SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
AR_BT_DISABLE_BT_ANT;
btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
btcoex_info->btcoex_period / 100;
for (i = 0; i < 32; i++)
hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
(unsigned long) hw->ah_sc);
btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
ath_btcoex_no_stomp_timer,
ath_btcoex_no_stomp_timer,
(void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
if (btcoex_info->no_stomp_timer == NULL)
return -ENOMEM;
spin_lock_init(&btcoex_info->btcoex_lock);
return 0;
}
int ath9k_hw_btcoex_init(struct ath_hw *ah)
{
struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
int ret = 0;
if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
/* connect bt_active to baseband */
REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
(AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
/* Set input mux for bt_active to gpio pin */
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
btcoex_info->btactive_gpio);
/* Configure the desired gpio port for input */
ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
} else {
/* btcoex 3-wire */
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
(AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
/* Set input mux for bt_prority_async and
* bt_active_async to GPIO pins */
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
btcoex_info->btactive_gpio);
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
AR_GPIO_INPUT_MUX1_BT_PRIORITY,
btcoex_info->btpriority_gpio);
/* Configure the desired GPIO ports for input */
ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
ret = ath_init_btcoex_info(ah, btcoex_info);
}
return ret;
}
void ath9k_hw_btcoex_enable(struct ath_hw *ah)
{
struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
/* Configure the desired GPIO port for TX_FRAME output */
ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
} else {
/*
* Program coex mode and weight registers to
* enable coex 3-wire
*/
REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
REG_RMW_FIELD(ah, AR_QUIET1,
AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
REG_RMW_FIELD(ah, AR_PCU_MISC,
AR_PCU_BT_ANT_PREVENT_RX, 0);
ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
}
REG_RMW(ah, AR_GPIO_PDPU,
(0x2 << (btcoex_info->btactive_gpio * 2)),
(0x3 << (btcoex_info->btactive_gpio * 2)));
ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
}
void ath9k_hw_btcoex_disable(struct ath_hw *ah)
{
struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
}
ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
}
/*
* Pause btcoex timer and bt duty cycle timer
*/
void ath_btcoex_timer_pause(struct ath_softc *sc,
struct ath_btcoex_info *btinfo)
{
del_timer_sync(&btinfo->period_timer);
if (btinfo->hw_timer_enabled)
ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
btinfo->hw_timer_enabled = false;
}
/*
* (Re)start btcoex timers
*/
void ath_btcoex_timer_resume(struct ath_softc *sc,
struct ath_btcoex_info *btinfo)
{
DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
/* make sure duty cycle timer is also stopped when resuming */
if (btinfo->hw_timer_enabled)
ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
btinfo->bt_priority_cnt = 0;
btinfo->bt_priority_time = jiffies;
sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
mod_timer(&btinfo->period_timer, jiffies);
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2009 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BTCOEX_H
#define BTCOEX_H
#define ATH_WLANACTIVE_GPIO 5
#define ATH_BTACTIVE_GPIO 6
#define ATH_BTCOEX_DEF_BT_PERIOD 45
#define ATH_BTCOEX_DEF_DUTY_CYCLE 55
#define ATH_BTCOEX_BMISS_THRESH 50
#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */
#define ATH_BT_CNT_THRESHOLD 3
enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_NONE,
ATH_BTCOEX_CFG_2WIRE,
ATH_BTCOEX_CFG_3WIRE,
};
enum ath_stomp_type {
ATH_BTCOEX_NO_STOMP,
ATH_BTCOEX_STOMP_ALL,
ATH_BTCOEX_STOMP_LOW,
ATH_BTCOEX_STOMP_NONE
};
enum ath_bt_mode {
ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
};
struct ath_btcoex_config {
u8 bt_time_extend;
bool bt_txstate_extend;
bool bt_txframe_extend;
enum ath_bt_mode bt_mode; /* coexistence mode */
bool bt_quiet_collision;
bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
u8 bt_priority_time;
u8 bt_first_slot_time;
bool bt_hold_rx_clear;
};
struct ath_btcoex_info {
enum ath_btcoex_scheme btcoex_scheme;
u8 wlanactive_gpio;
u8 btactive_gpio;
u8 btpriority_gpio;
u8 bt_duty_cycle; /* BT duty cycle in percentage */
int bt_stomp_type; /* Types of BT stomping */
u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
u32 btcoex_no_stomp; /* in usec */
u32 btcoex_period; /* in usec */
u32 bt_priority_cnt;
unsigned long bt_priority_time;
bool hw_timer_enabled;
spinlock_t btcoex_lock;
struct timer_list period_timer; /* Timer for BT period */
struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/
};
int ath9k_hw_btcoex_init(struct ath_hw *ah);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
void ath9k_hw_btcoex_disable(struct ath_hw *ah);
void ath_btcoex_timer_resume(struct ath_softc *sc,
struct ath_btcoex_info *btinfo);
void ath_btcoex_timer_pause(struct ath_softc *sc,
struct ath_btcoex_info *btinfo);
static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info,
u32 bt_weight,
u32 wlan_weight)
{
btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
SM(wlan_weight, AR_BTCOEX_WL_WGHT);
}
#endif

View file

@ -861,7 +861,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
REG_WRITE(ah, regList[i][0], regList[i][1]);
}
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{
u32 regVal;
@ -877,6 +877,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
{ 0x7838, 0 },
};
DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
/* PA CAL is not needed for high power solution */
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
AR5416_EEP_TXGAIN_HIGH_POWER)
return;
if (AR_SREV_9285_11(ah)) {
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
udelay(10);
@ -899,13 +906,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
udelay(30);
@ -917,7 +924,6 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
regVal |= (1 << (19 + i));
REG_WRITE(ah, 0x7834, regVal);
udelay(1);
regVal = REG_READ(ah, 0x7834);
regVal &= (~(0x1 << (19 + i)));
reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
regVal |= (reg_field << (19 + i));
@ -936,6 +942,17 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
offs_6_1 = offset>>1;
offs_0 = offset & 1;
if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
ah->pacal_info.max_skipcount =
2 * ah->pacal_info.max_skipcount;
ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
} else {
ah->pacal_info.max_skipcount = 1;
ah->pacal_info.skipcount = 0;
ah->pacal_info.prev_offset = offset;
}
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
@ -982,8 +999,12 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
/* Do periodic PAOffset Cal */
if (AR_SREV_9271(ah))
ath9k_hw_9271_pa_cal(ah);
else if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah);
else if (AR_SREV_9285_11_OR_LATER(ah)) {
if (!ah->pacal_info.skipcount)
ath9k_hw_9285_pa_cal(ah, false);
else
ah->pacal_info.skipcount--;
}
if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah);
@ -1081,7 +1102,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Do PA Calibration */
if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah);
ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,

View file

@ -110,6 +110,13 @@ struct ath9k_nfcal_hist {
u8 invalidNFcount;
};
#define MAX_PACAL_SKIPCOUNT 8
struct ath9k_pacal_info{
int32_t prev_offset; /* Previous value of PA offset value */
int8_t max_skipcount; /* Max No. of times PACAL can be skipped */
int8_t skipcount; /* No. of times the PACAL to be skipped */
};
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);

View file

@ -93,6 +93,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
int i, qcuOffset = 0, dcuOffset = 0;
u32 *qcuBase = &val[0], *dcuBase = &val[4];
ath9k_ps_wakeup(sc);
REG_WRITE(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
@ -159,6 +161,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
ath9k_ps_restore(sc);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

View file

@ -30,6 +30,8 @@ enum ATH_DEBUG {
ATH_DBG_CONFIG = 0x00000200,
ATH_DBG_FATAL = 0x00000400,
ATH_DBG_PS = 0x00000800,
ATH_DBG_HWTIMER = 0x00001000,
ATH_DBG_BTCOEX = 0x00002000,
ATH_DBG_ANY = 0xffffffff
};

View file

@ -143,10 +143,10 @@ void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
IS_CHAN_2GHZ(chan))) {
matchIndex = i;
break;
} else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
IS_CHAN_2GHZ(chan))) &&
(freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
IS_CHAN_2GHZ(chan)))) {
} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
IS_CHAN_2GHZ(chan)) && i > 0 &&
freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}
@ -198,10 +198,10 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
matchIndex = i;
break;
} else
if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
IS_CHAN_2GHZ(chan))) &&
(freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
IS_CHAN_2GHZ(chan)))) {
if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
IS_CHAN_2GHZ(chan)) && i > 0 &&
freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}

View file

@ -2555,6 +2555,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
#endif
}
if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED)
ath9k_hw_btcoex_enable(ah);
return 0;
}
@ -3212,6 +3215,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
if (AR_SREV_9100(ah))
return true;
if (isr & AR_ISR_GENTMR) {
u32 s5_s;
s5_s = REG_READ(ah, AR_ISR_S5_S);
if (isr & AR_ISR_GENTMR) {
ah->intr_gen_timer_trigger =
MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
ah->intr_gen_timer_thresh =
MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
if (ah->intr_gen_timer_trigger)
*masked |= ATH9K_INT_GENTIMER;
}
}
if (sync_cause) {
fatal_int =
(sync_cause &
@ -3486,6 +3506,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
u16 capField = 0, eeval;
@ -3662,9 +3683,15 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
ah->btactive_gpio = 6;
ah->wlanactive_gpio = 5;
btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO;
btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
if (AR_SREV_9285(ah))
btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE;
else
btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE;
} else {
btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE;
}
}
@ -4069,29 +4096,197 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
REG_WRITE(ah, AR_2040_MODE, macmode);
}
/***************************/
/* Bluetooth Coexistence */
/***************************/
/* HW Generic timers configuration */
void ath9k_hw_btcoex_enable(struct ath_hw *ah)
static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
{
/* connect bt_active to baseband */
REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
(AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
{AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001},
{AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4,
AR_NDP2_TIMER_MODE, 0x0002},
{AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4,
AR_NDP2_TIMER_MODE, 0x0004},
{AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4,
AR_NDP2_TIMER_MODE, 0x0008},
{AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4,
AR_NDP2_TIMER_MODE, 0x0010},
{AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4,
AR_NDP2_TIMER_MODE, 0x0020},
{AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4,
AR_NDP2_TIMER_MODE, 0x0040},
{AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4,
AR_NDP2_TIMER_MODE, 0x0080}
};
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
/* HW generic timer primitives */
/* Set input mux for bt_active to gpio pin */
REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
AR_GPIO_INPUT_MUX1_BT_ACTIVE,
ah->btactive_gpio);
/* compute and clear index of rightmost 1 */
static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
{
u32 b;
/* Configure the desired gpio port for input */
ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio);
b = *mask;
b &= (0-b);
*mask &= ~b;
b *= debruijn32;
b >>= 27;
/* Configure the desired GPIO port for TX_FRAME output */
ath9k_hw_cfg_output(ah, ah->wlanactive_gpio,
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
return timer_table->gen_timer_index[b];
}
u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
}
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
void (*overflow)(void *),
void *arg,
u8 timer_index)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
if (timer == NULL) {
printk(KERN_DEBUG "Failed to allocate memory"
"for hw timer[%d]\n", timer_index);
return NULL;
}
/* allocate a hardware generic timer slot */
timer_table->timers[timer_index] = timer;
timer->index = timer_index;
timer->trigger = trigger;
timer->overflow = overflow;
timer->arg = arg;
return timer;
}
void ath_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
u32 timer_next, u32 timer_period)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
u32 tsf;
BUG_ON(!timer_period);
set_bit(timer->index, &timer_table->timer_mask.timer_bits);
tsf = ath9k_hw_gettsf32(ah);
DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
"timer_next %x\n", tsf, timer_period, timer_next);
/*
* Pull timer_next forward if the current TSF already passed it
* because of software latency
*/
if (timer_next < tsf)
timer_next = tsf + timer_period;
/*
* Program generic timer registers
*/
REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr,
timer_next);
REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr,
timer_period);
REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
gen_tmr_configuration[timer->index].mode_mask);
/* Enable both trigger and thresh interrupt masks */
REG_SET_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
ath9k_hw_set_interrupts(ah, 0);
ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
}
}
void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
if ((timer->index < AR_FIRST_NDP_TIMER) ||
(timer->index >= ATH_MAX_GEN_TIMER)) {
return;
}
/* Clear generic timer enable bits. */
REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
gen_tmr_configuration[timer->index].mode_mask);
/* Disable both trigger and thresh interrupt masks */
REG_CLR_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
/* if no timer is enabled, turn off interrupt mask */
if (timer_table->timer_mask.val == 0) {
ath9k_hw_set_interrupts(ah, 0);
ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
}
}
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
/* free the hardware generic timer slot */
timer_table->timers[timer->index] = NULL;
kfree(timer);
}
/*
* Generic Timer Interrupts handling
*/
void ath_gen_timer_isr(struct ath_hw *ah)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
u32 trigger_mask, thresh_mask, index;
/* get hardware generic timer interrupt status */
trigger_mask = ah->intr_gen_timer_trigger;
thresh_mask = ah->intr_gen_timer_thresh;
trigger_mask &= timer_table->timer_mask.val;
thresh_mask &= timer_table->timer_mask.val;
trigger_mask &= ~thresh_mask;
while (thresh_mask) {
index = rightmost_index(timer_table, &thresh_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
"TSF overflow for Gen timer %d\n", index);
timer->overflow(timer->arg);
}
while (trigger_mask) {
index = rightmost_index(timer_table, &trigger_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
"Gen timer[%d] trigger\n", index);
timer->trigger(timer->arg);
}
}

View file

@ -79,6 +79,7 @@
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3
#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
@ -151,7 +152,6 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
ATH9K_HW_CAP_BT_COEX = BIT(17)
};
enum ath9k_capability_type {
@ -238,6 +238,7 @@ enum ath9k_int {
ATH9K_INT_GPIO = 0x01000000,
ATH9K_INT_CABEND = 0x02000000,
ATH9K_INT_TSFOOR = 0x04000000,
ATH9K_INT_GENTIMER = 0x08000000,
ATH9K_INT_CST = 0x10000000,
ATH9K_INT_GTT = 0x20000000,
ATH9K_INT_FATAL = 0x40000000,
@ -391,6 +392,41 @@ struct ath9k_hw_version {
u16 analog2GhzRev;
};
/* Generic TSF timer definitions */
#define ATH_MAX_GEN_TIMER 16
#define AR_GENTMR_BIT(_index) (1 << (_index))
/*
* Using de Bruijin sequence to to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
#define debruijn32 0x077CB531UL
struct ath_gen_timer_configuration {
u32 next_addr;
u32 period_addr;
u32 mode_addr;
u32 mode_mask;
};
struct ath_gen_timer {
void (*trigger)(void *arg);
void (*overflow)(void *arg);
void *arg;
u8 index;
};
struct ath_gen_timer_table {
u32 gen_timer_index[32];
struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
union {
unsigned long timer_bits;
u16 val;
} timer_mask;
};
struct ath_hw {
struct ath_softc *ah_sc;
struct ath9k_hw_version hw_version;
@ -414,8 +450,6 @@ struct ath_hw {
u16 rfsilent;
u32 rfkill_gpio;
u32 rfkill_polarity;
u32 btactive_gpio;
u32 wlanactive_gpio;
u32 ah_flags;
bool htc_reset_init;
@ -424,6 +458,7 @@ struct ath_hw {
enum ath9k_power_mode power_mode;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
struct ath9k_pacal_info pacal_info;
struct ar5416Stats stats;
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@ -538,6 +573,10 @@ struct ath_hw {
struct ar5416IniArray iniModesAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
u32 intr_gen_timer_trigger;
u32 intr_gen_timer_thresh;
struct ath_gen_timer_table hw_gen_timers;
};
/* Initialization, Detach, Reset */
@ -613,6 +652,17 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
/* Generic hw timer primitives */
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
void (*overflow)(void *),
void *arg,
u8 timer_index);
void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
u32 timer_next, u32 timer_period);
void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_isr(struct ath_hw *hw);
u32 ath9k_hw_gettsf32(struct ath_hw *ah);
#endif

View file

@ -4133,7 +4133,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
{ 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
@ -4158,7 +4158,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
{ 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
{ 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
{ 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@ -4601,7 +4601,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
{ 0x00008264, 0xa8a00010 },
{ 0x00008264, 0x88a00010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@ -4650,7 +4650,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00009954, 0x5f3ca3de },
{ 0x00009958, 0x2108ecff },
{ 0x00009968, 0x000003ce },
{ 0x00009970, 0x192bb515 },
{ 0x00009970, 0x192bb514 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@ -4728,7 +4728,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00007800, 0x00140000 },
{ 0x00007804, 0x0e4548d8 },
{ 0x00007808, 0x54214514 },
{ 0x0000780c, 0x02025820 },
{ 0x0000780c, 0x02025830 },
{ 0x00007810, 0x71c0d388 },
{ 0x00007814, 0x924934a8 },
{ 0x0000781c, 0x00000000 },

View file

@ -439,8 +439,8 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
if (is_ht ||
(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
(sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
} else {
@ -602,6 +602,10 @@ irqreturn_t ath_isr(int irq, void *dev)
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(ah);
chip_reset:
ath_debug_stat_interrupt(sc, status);
@ -1279,6 +1283,10 @@ void ath_detach(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
if ((sc->btcoex_info.no_stomp_timer) &&
sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
ath9k_hw_detach(sc->sc_ah);
sc->sc_ah = NULL;
ath9k_exit_debug(sc);
@ -1509,8 +1517,11 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
ath9k_hw_btcoex_enable(sc->sc_ah);
if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
r = ath9k_hw_btcoex_init(ah);
if (r)
goto bad2;
}
return 0;
bad2:
@ -1992,6 +2003,16 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
!(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
AR_STOMP_LOW_WLAN_WGHT);
ath9k_hw_btcoex_enable(sc->sc_ah);
if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
ath_btcoex_timer_resume(sc, &sc->btcoex_info);
}
mutex_unlock:
mutex_unlock(&sc->mutex);
@ -2125,6 +2146,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return; /* another wiphy still in use */
}
if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
ath9k_hw_btcoex_disable(sc->sc_ah);
if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
ath_btcoex_timer_pause(sc, &sc->btcoex_info);
}
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
@ -2713,6 +2740,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
"same time\n");
@ -2720,6 +2748,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
* Do not allow the concurrent scanning state for now. This
* could be improved with scanning control moved into ath9k.
*/
mutex_unlock(&sc->mutex);
return;
}
@ -2729,6 +2758,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
spin_unlock_bh(&sc->ani_lock);
mutex_unlock(&sc->mutex);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@ -2736,11 +2766,13 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
spin_unlock_bh(&sc->ani_lock);
mutex_unlock(&sc->mutex);
}
struct ieee80211_ops ath9k_ops = {

View file

@ -423,11 +423,12 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->rx.rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (sc->sec_wiphy) {
if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* TODO: only needed if more than one BSSID is in use in
* station/adhoc mode */
/* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM
*/
/* The following may also be needed for other older chips */
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}

View file

@ -234,7 +234,15 @@
#define AR_IMR_S5 0x00b8
#define AR_IMR_S5_TIM_TIMER 0x00000010
#define AR_IMR_S5_DTIM_TIMER 0x00000020
#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80
#define AR_ISR_S5_GENTIMER_TRIG_S 0
#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000
#define AR_ISR_S5_GENTIMER_THRESH_S 16
#define AR_ISR_S5_S 0x00d8
#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80
#define AR_IMR_S5_GENTIMER_TRIG_S 0
#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000
#define AR_IMR_S5_GENTIMER_THRESH_S 16
#define AR_IMR 0x00a0
#define AR_IMR_RXOK 0x00000001
@ -962,6 +970,8 @@ enum {
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
@ -970,6 +980,8 @@ enum {
#define AR_GPIO_INPUT_MUX1 0x4058
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16
#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00
#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8
#define AR_GPIO_INPUT_MUX2 0x405c
#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
@ -995,6 +1007,8 @@ enum {
#define AR_OBS 0x4080
#define AR_GPIO_PDPU 0x4088
#define AR_PCIE_MSI 0x4094
#define AR_PCIE_MSI_ENABLE 0x00000001
@ -1428,6 +1442,7 @@ enum {
#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff
#define AR_QUIET1_QUIET_ENABLE 0x00010000
#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000
#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17
#define AR_QUIET2 0x8100
#define AR_QUIET2_QUIET_PERIOD_S 0
#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff
@ -1473,6 +1488,8 @@ enum {
#define AR_PCU_CLEAR_VMF 0x01000000
#define AR_PCU_CLEAR_BA_VALID 0x04000000
#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000
#define AR_PCU_BT_ANT_PREVENT_RX_S 20
#define AR_FILT_OFDM 0x8124
#define AR_FILT_OFDM_COUNT 0x00FFFFFF
@ -1500,6 +1517,46 @@ enum {
#define AR_PHY_ERR_3_COUNT 0x00FFFFFF
#define AR_PHY_ERR_MASK_3 0x816c
#define AR_BT_COEX_MODE 0x8170
#define AR_BT_TIME_EXTEND 0x000000ff
#define AR_BT_TIME_EXTEND_S 0
#define AR_BT_TXSTATE_EXTEND 0x00000100
#define AR_BT_TXSTATE_EXTEND_S 8
#define AR_BT_TX_FRAME_EXTEND 0x00000200
#define AR_BT_TX_FRAME_EXTEND_S 9
#define AR_BT_MODE 0x00000c00
#define AR_BT_MODE_S 10
#define AR_BT_QUIET 0x00001000
#define AR_BT_QUIET_S 12
#define AR_BT_QCU_THRESH 0x0001e000
#define AR_BT_QCU_THRESH_S 13
#define AR_BT_RX_CLEAR_POLARITY 0x00020000
#define AR_BT_RX_CLEAR_POLARITY_S 17
#define AR_BT_PRIORITY_TIME 0x00fc0000
#define AR_BT_PRIORITY_TIME_S 18
#define AR_BT_FIRST_SLOT_TIME 0xff000000
#define AR_BT_FIRST_SLOT_TIME_S 24
#define AR_BT_COEX_WEIGHT 0x8174
#define AR_BT_COEX_WGHT 0xff55
#define AR_STOMP_ALL_WLAN_WGHT 0xffcc
#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8
#define AR_STOMP_NONE_WLAN_WGHT 0xaa00
#define AR_BTCOEX_BT_WGHT 0x0000ffff
#define AR_BTCOEX_BT_WGHT_S 0
#define AR_BTCOEX_WL_WGHT 0xffff0000
#define AR_BTCOEX_WL_WGHT_S 16
#define AR_BT_COEX_MODE2 0x817c
#define AR_BT_BCN_MISS_THRESH 0x000000ff
#define AR_BT_BCN_MISS_THRESH_S 0
#define AR_BT_BCN_MISS_CNT 0x0000ff00
#define AR_BT_BCN_MISS_CNT_S 8
#define AR_BT_HOLD_RX_CLEAR 0x00010000
#define AR_BT_HOLD_RX_CLEAR_S 16
#define AR_BT_DISABLE_BT_ANT 0x00100000
#define AR_BT_DISABLE_BT_ANT_S 20
#define AR_TXSIFS 0x81d0
#define AR_TXSIFS_TIME 0x000000FF
#define AR_TXSIFS_TX_LATENCY 0x00000F00
@ -1516,7 +1573,10 @@ enum {
#define AR_TXOP_8_11 0x81f8
#define AR_TXOP_12_15 0x81fc
#define AR_NEXT_NDP2_TIMER 0x8180
#define AR_FIRST_NDP_TIMER 7
#define AR_NDP2_PERIOD 0x81a0
#define AR_NDP2_TIMER_MODE 0x81c0
#define AR_NEXT_TBTT_TIMER 0x8200
#define AR_NEXT_DMA_BEACON_ALERT 0x8204
#define AR_NEXT_SWBA 0x8208

View file

@ -493,7 +493,12 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
return 0;
aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
aggr_limit = min((max_4ms_framelen * 3) / 8,
(u32)ATH_AMPDU_LIMIT_MAX);
else
aggr_limit = min(max_4ms_framelen,
(u32)ATH_AMPDU_LIMIT_MAX);
/*
* h/w can accept aggregates upto 16 bit lengths (65535).
@ -872,7 +877,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return &sc->tx.txq[qnum];
}
static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
{
int qnum;

View file

@ -82,15 +82,13 @@ config B43_NPHY
config B43_PHY_LP
bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)"
depends on B43 && EXPERIMENTAL
default y
---help---
Support for the LP-PHY.
The LP-PHY is a low-power PHY built into some notebooks
and embedded devices. It supports 802.11a/g
(802.11a support is optional, and currently disabled).
This is heavily experimental, and probably will not work for you.
Say N unless you want to help debug the driver.
# This config option automatically enables b43 LEDS support,
# if it's possible.
config B43_LEDS

View file

@ -1456,7 +1456,8 @@ static u16 b43_antenna_to_phyctl(int antenna)
return B43_TXH_PHY_ANT2;
case B43_ANTENNA3:
return B43_TXH_PHY_ANT3;
case B43_ANTENNA_AUTO:
case B43_ANTENNA_AUTO0:
case B43_ANTENNA_AUTO1:
return B43_TXH_PHY_ANT01AUTO;
}
B43_WARN_ON(1);

View file

@ -531,7 +531,7 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
tmp &= ~B43_PHY_BBANDCFG_RXANT;
tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna)
<< B43_PHY_BBANDCFG_RXANT_SHIFT;
b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);

View file

@ -249,20 +249,35 @@ void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) & mask);
if (dev->phy.ops->phy_maskset) {
assert_mac_suspended(dev);
dev->phy.ops->phy_maskset(dev, offset, mask, 0);
} else {
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) & mask);
}
}
void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
{
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) | set);
if (dev->phy.ops->phy_maskset) {
assert_mac_suspended(dev);
dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set);
} else {
b43_phy_write(dev, offset,
b43_phy_read(dev, offset) | set);
}
}
void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
{
b43_phy_write(dev, offset,
(b43_phy_read(dev, offset) & mask) | set);
if (dev->phy.ops->phy_maskset) {
assert_mac_suspended(dev);
dev->phy.ops->phy_maskset(dev, offset, mask, set);
} else {
b43_phy_write(dev, offset,
(b43_phy_read(dev, offset) & mask) | set);
}
}
int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)

View file

@ -49,11 +49,11 @@ enum b43_interference_mitigation {
/* Antenna identifiers */
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA0 = 0, /* Antenna 0 */
B43_ANTENNA1 = 1, /* Antenna 1 */
B43_ANTENNA_AUTO0 = 2, /* Automatic, starting with antenna 0 */
B43_ANTENNA_AUTO1 = 3, /* Automatic, starting with antenna 1 */
B43_ANTENNA2 = 4,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
@ -95,6 +95,8 @@ enum b43_txpwr_result {
* Must not be NULL.
* @phy_write: Write to a PHY register.
* Must not be NULL.
* @phy_maskset: Maskset a PHY register, taking shortcuts.
* If it is NULL, a generic algorithm is used.
* @radio_read: Read from a Radio register.
* Must not be NULL.
* @radio_write: Write to a Radio register.
@ -154,6 +156,7 @@ struct b43_phy_operations {
/* Register access */
u16 (*phy_read)(struct b43_wldev *dev, u16 reg);
void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value);
void (*phy_maskset)(struct b43_wldev *dev, u16 reg, u16 mask, u16 set);
u16 (*radio_read)(struct b43_wldev *dev, u16 reg);
void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value);

View file

@ -2664,7 +2664,7 @@ static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
tmp &= ~B43_PHY_BBANDCFG_RXANT;
tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna)
<< B43_PHY_BBANDCFG_RXANT_SHIFT;
b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);

View file

@ -182,8 +182,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
temp[1] = temp[0] + 0x1000;
temp[2] = temp[0] + 0x2000;
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
}
static void lpphy_table_init(struct b43_wldev *dev)
@ -223,8 +223,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180);
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800);
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
@ -234,19 +234,15 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
if ((bus->sprom.boardflags_lo & B43_BFL_FEM) &&
((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
(bus->sprom.boardflags_hi & B43_BFH_PAREF))) {
/* TODO:
* Set the LDO voltage to 0x0028 - FIXME: What is this?
* Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage
* as arguments
* Call sb_pmu_paref_ldo_enable with argument TRUE
*/
ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
ssb_pmu_set_ldo_paref(&bus->chipco, true);
if (dev->phy.rev == 0) {
b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
0xFFCF, 0x0010);
}
b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
} else {
//TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE
ssb_pmu_set_ldo_paref(&bus->chipco, false);
b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
0xFFCF, 0x0020);
b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
@ -340,11 +336,11 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
if (dev->phy.rev == 1) {
tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
tmp2 = (tmp & 0x03E0) >> 5;
tmp2 |= tmp << 5;
tmp2 |= tmp2 << 5;
b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0);
tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
tmp2 = (tmp & 0x1F00) >> 8;
tmp2 |= tmp << 5;
tmp2 |= tmp2 << 5;
b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
tmp2 = tmp & 0x00FF;
@ -705,7 +701,7 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev)
u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
if (dev->phy.rev == 1) //FIXME check channel 14!
rc_cap = max_t(u8, rc_cap + 5, 15);
rc_cap = min_t(u8, rc_cap + 5, 15);
b43_radio_write(dev, B2062_N_RXBB_CALIB2,
max_t(u8, lpphy->rc_cap - 4, 0x80));
@ -761,7 +757,7 @@ static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
@ -956,7 +952,7 @@ static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20);
b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
}
static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
@ -968,7 +964,7 @@ static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF);
b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
for (i = 0; i < 500; i++) {
if (!(b43_phy_read(dev,
@ -1008,6 +1004,7 @@ static int lpphy_loopback(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
@ -1031,9 +1028,10 @@ static int lpphy_loopback(struct b43_wldev *dev)
return index;
}
/* Fixed-point division algorithm using only integer math. */
static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
{
u32 quotient, remainder, rbit, roundup, tmp;
u32 quotient, remainder;
if (divisor == 0)
return 0;
@ -1041,20 +1039,16 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
quotient = dividend / divisor;
remainder = dividend % divisor;
rbit = divisor & 0x1;
roundup = (divisor >> 1) + rbit;
while (precision != 0) {
tmp = remainder - roundup;
while (precision > 0) {
quotient <<= 1;
if (remainder >= roundup)
remainder = (tmp << 1) + rbit;
else
remainder <<= 1;
if (remainder << 1 >= divisor) {
quotient++;
remainder = (remainder << 1) - divisor;
}
precision--;
}
if (remainder >= roundup)
if (remainder << 1 >= divisor)
quotient++;
return quotient;
@ -1137,9 +1131,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
}
if (dev->phy.rev >= 2) {
if (mode == B43_LPPHY_TXPCTL_HW)
b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2);
b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
else
b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0);
b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
}
lpphy_write_tx_pctl_mode_to_hardware(dev);
}
@ -1171,7 +1165,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
err = b43_lpphy_op_switch_channel(dev, 7);
if (err) {
b43dbg(dev->wl,
"RC calib: Failed to switch to channel 7, error = %d",
"RC calib: Failed to switch to channel 7, error = %d\n",
err);
}
old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
@ -1213,7 +1207,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
mean_sq_pwr = ideal_pwr - normal_pwr;
mean_sq_pwr *= mean_sq_pwr;
inner_sum += mean_sq_pwr;
if ((i = 128) || (inner_sum < mean_sq_pwr_min)) {
if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
lpphy->rc_cap = i;
mean_sq_pwr_min = inner_sum;
}
@ -1506,6 +1500,14 @@ static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
{
/* Register 1 is a 32-bit register. */
@ -1922,8 +1924,8 @@ static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
{
b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42);
b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62);
b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
udelay(200);
}
@ -1982,7 +1984,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
tmp6 = tmp5 / tmp4;
tmp7 = tmp5 % tmp4;
b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19);
tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
@ -2021,17 +2023,17 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
{
u16 tmp;
b43_phy_mask(dev, B2063_PLL_SP1, ~0x40);
tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
udelay(1);
b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
udelay(1);
b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
udelay(1);
b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
udelay(300);
b43_phy_set(dev, B2063_PLL_SP1, 0x40);
b43_radio_set(dev, B2063_PLL_SP1, 0x40);
}
static int lpphy_b2063_tune(struct b43_wldev *dev,
@ -2126,31 +2128,31 @@ static int lpphy_b2063_tune(struct b43_wldev *dev,
scale = 0;
tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
}
b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
tmp6 *= (tmp5 * 8) * (scale + 1);
if (tmp6 > 150)
tmp6 = 0;
b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
if (crystal_freq > 26000000)
b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
else
b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
if (val1 == 45)
b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
else
b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
b43_phy_set(dev, B2063_PLL_SP2, 0x3);
b43_radio_set(dev, B2063_PLL_SP2, 0x3);
udelay(1);
b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC);
b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
lpphy_b2063_vco_calib(dev);
b43_radio_write(dev, B2063_COMM15, old_comm15);
@ -2160,10 +2162,9 @@ static int lpphy_b2063_tune(struct b43_wldev *dev,
static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
int err;
b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
if (dev->phy.radio_ver == 0x2063) {
err = lpphy_b2063_tune(dev, new_channel);
if (err)
@ -2176,6 +2177,9 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
}
lpphy->channel = new_channel;
b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
return 0;
}
@ -2187,10 +2191,9 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
lpphy_baseband_init(dev);
lpphy_radio_init(dev);
lpphy_calibrate_rc(dev);
err = b43_lpphy_op_switch_channel(dev,
b43_lpphy_op_get_default_chan(dev));
err = b43_lpphy_op_switch_channel(dev, 7);
if (err) {
b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n",
b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
err);
}
lpphy_tx_pctl_init(dev);
@ -2202,7 +2205,14 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
{
//TODO
if (dev->phy.rev >= 2)
return; // rev2+ doesn't support antenna diversity
if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
return;
b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
}
static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
@ -2224,6 +2234,7 @@ const struct b43_phy_operations b43_phyops_lp = {
.init = b43_lpphy_op_init,
.phy_read = b43_lpphy_op_read,
.phy_write = b43_lpphy_op_write,
.phy_maskset = b43_lpphy_op_maskset,
.radio_read = b43_lpphy_op_radio_read,
.radio_write = b43_lpphy_op_radio_write,
.software_rfkill = b43_lpphy_op_software_rfkill,

View file

@ -888,6 +888,9 @@ struct b43_phy_lp {
bool crs_usr_disable, crs_sys_disable;
unsigned int pdiv;
/* The channel we are tuned to */
u8 channel;
};
enum tssi_mux_mode {

View file

@ -624,30 +624,35 @@ u32 b43_lptab_read(struct b43_wldev *dev, u32 offset)
void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, void *_data)
{
u32 type, value;
u32 type;
u8 *data = _data;
unsigned int i;
type = offset & B43_LPTAB_TYPEMASK;
offset &= ~B43_LPTAB_TYPEMASK;
B43_WARN_ON(offset > 0xFFFF);
b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset);
for (i = 0; i < nr_elements; i++) {
value = b43_lptab_read(dev, offset);
switch (type) {
case B43_LPTAB_8BIT:
*data = value;
*data = b43_phy_read(dev, B43_LPPHY_TABLEDATALO) & 0xFF;
data++;
break;
case B43_LPTAB_16BIT:
*((u16 *)data) = value;
*((u16 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATALO);
data += 2;
break;
case B43_LPTAB_32BIT:
*((u32 *)data) = value;
*((u32 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATAHI);
*((u32 *)data) <<= 16;
*((u32 *)data) |= b43_phy_read(dev, B43_LPPHY_TABLEDATALO);
data += 4;
break;
default:
B43_WARN_ON(1);
}
offset++;
}
}
@ -688,26 +693,34 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset,
unsigned int i;
type = offset & B43_LPTAB_TYPEMASK;
offset &= ~B43_LPTAB_TYPEMASK;
B43_WARN_ON(offset > 0xFFFF);
b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset);
for (i = 0; i < nr_elements; i++) {
switch (type) {
case B43_LPTAB_8BIT:
value = *data;
data++;
B43_WARN_ON(value & ~0xFF);
b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
case B43_LPTAB_16BIT:
value = *((u16 *)data);
data += 2;
B43_WARN_ON(value & ~0xFFFF);
b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
case B43_LPTAB_32BIT:
value = *((u32 *)data);
data += 4;
b43_phy_write(dev, B43_LPPHY_TABLEDATAHI, value >> 16);
b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value);
break;
default:
B43_WARN_ON(1);
value = 0;
}
b43_lptab_write(dev, offset, value);
offset++;
}
}
@ -777,7 +790,7 @@ static const u8 lpphy_pll_fraction_table[] = {
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
static const u16 lpphy_iq_local_table[] = {
static const u16 lpphy_iqlo_cal_table[] = {
0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
@ -789,10 +802,17 @@ static const u16 lpphy_iq_local_table[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
static const u16 lpphy_ofdm_cck_gain_table[] = {
static const u16 lpphy_rev0_ofdm_cck_gain_table[] = {
0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001,
0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075,
0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d,
0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d,
};
static const u16 lpphy_rev1_ofdm_cck_gain_table[] = {
0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001,
0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075,
0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d,
@ -2263,11 +2283,18 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev)
b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0),
ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0),
ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0),
ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0),
ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table);
ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table);
if (dev->phy.rev == 0) {
b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0),
ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0),
ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table);
} else {
b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0),
ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0),
ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table);
}
b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0),
ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table);
b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0),
@ -2281,22 +2308,6 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev)
B43_WARN_ON(dev->phy.rev < 2);
/*
* FIXME This code follows the specs, but it looks wrong:
* In each pass, it writes 4 bytes to an offset in table ID 7,
* then increments the offset by 1 for the next pass. This results
* in the first 3 bytes of each pass except the first one getting
* written to a location that has already been zeroed in the previous
* pass.
* This is what the vendor driver does, but it still looks suspicious.
*
* This should probably suffice:
*
* for (i = 0; i < 704; i+=4)
* b43_lptab_write(dev, B43_LPTAB32(7, i), 0)
*
* This should be tested once the code is functional.
*/
for (i = 0; i < 704; i++)
b43_lptab_write(dev, B43_LPTAB32(7, i), 0);
@ -2323,7 +2334,7 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev)
b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0),
ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table);
b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0),
ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table);
ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table);
b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0),
ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table);
b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0),

View file

@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
Portions of this file are based on the sample_* files provided by Wireless
@ -1673,7 +1673,7 @@ static int ipw2100_start_scan(struct ipw2100_priv *priv)
return err;
}
static const struct ieee80211_geo ipw_geos[] = {
static const struct libipw_geo ipw_geos[] = {
{ /* Restricted */
"---",
.bg_channels = 14,
@ -1694,7 +1694,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Age scan list entries found before suspend */
if (priv->suspend_time) {
ieee80211_networks_age(priv->ieee, priv->suspend_time);
libipw_networks_age(priv->ieee, priv->suspend_time);
priv->suspend_time = 0;
}
@ -1752,11 +1752,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
}
/* Initialize the geo */
if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) {
if (libipw_set_geo(priv->ieee, &ipw_geos[0])) {
printk(KERN_WARNING DRV_NAME "Could not set geo\n");
return 0;
}
priv->ieee->freq_band = IEEE80211_24GHZ_BAND;
priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
lock = LOCK_NONE;
if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
@ -1817,7 +1817,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Called by register_netdev() */
static int ipw2100_net_init(struct net_device *dev)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
return ipw2100_up(priv, 1);
}
@ -2340,8 +2340,8 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
*
* When packet is provided by the firmware, it contains the following:
*
* . ieee80211_hdr
* . ieee80211_snap_hdr
* . libipw_hdr
* . libipw_snap_hdr
*
* The size of the constructed ethernet
*
@ -2396,7 +2396,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
}
static void isr_rx(struct ipw2100_priv *priv, int i,
struct ieee80211_rx_stats *stats)
struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
struct ipw2100_status *status = &priv->status_queue.drv[i];
@ -2435,13 +2435,13 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#ifdef IPW2100_RX_DEBUG
/* Make a copy of the frame so we can dump it to the logs if
* ieee80211_rx fails */
* libipw_rx fails */
skb_copy_from_linear_data(packet->skb, packet_data,
min_t(u32, status->frame_size,
IPW_RX_NIC_BUFFER_LENGTH));
#endif
if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
if (!libipw_rx(priv->ieee, packet->skb, stats)) {
#ifdef IPW2100_RX_DEBUG
IPW_DEBUG_DROP("%s: Non consumed packet:\n",
dev->name);
@ -2449,7 +2449,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#endif
dev->stats.rx_errors++;
/* ieee80211_rx failed, so it didn't free the SKB */
/* libipw_rx failed, so it didn't free the SKB */
dev_kfree_skb_any(packet->skb);
packet->skb = NULL;
}
@ -2470,7 +2470,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#ifdef CONFIG_IPW2100_MONITOR
static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
struct ieee80211_rx_stats *stats)
struct libipw_rx_stats *stats)
{
struct net_device *dev = priv->net_dev;
struct ipw2100_status *status = &priv->status_queue.drv[i];
@ -2528,10 +2528,10 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
if (!libipw_rx(priv->ieee, packet->skb, stats)) {
dev->stats.rx_errors++;
/* ieee80211_rx failed, so it didn't free the SKB */
/* libipw_rx failed, so it didn't free the SKB */
dev_kfree_skb_any(packet->skb);
packet->skb = NULL;
}
@ -2615,7 +2615,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
u16 frame_type;
u32 r, w, i, s;
struct ipw2100_rx *u;
struct ieee80211_rx_stats stats = {
struct libipw_rx_stats stats = {
.mac_time = jiffies,
};
@ -2661,8 +2661,8 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
stats.mask = 0;
if (stats.rssi != 0)
stats.mask |= IEEE80211_STATMASK_RSSI;
stats.freq = IEEE80211_24GHZ_BAND;
stats.mask |= LIBIPW_STATMASK_RSSI;
stats.freq = LIBIPW_24GHZ_BAND;
IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
priv->net_dev->name, frame_types[frame_type],
@ -2686,11 +2686,11 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
#endif
if (stats.len < sizeof(struct ieee80211_hdr_3addr))
if (stats.len < sizeof(struct libipw_hdr_3addr))
break;
switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
case IEEE80211_FTYPE_MGMT:
ieee80211_rx_mgt(priv->ieee,
libipw_rx_mgt(priv->ieee,
&u->rx_data.header, &stats);
break;
@ -2884,7 +2884,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv)
tbd->buf_length, PCI_DMA_TODEVICE);
}
ieee80211_txb_free(packet->info.d_struct.txb);
libipw_txb_free(packet->info.d_struct.txb);
packet->info.d_struct.txb = NULL;
list_add_tail(element, &priv->tx_free_list);
@ -3028,7 +3028,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
int next = txq->next;
int i = 0;
struct ipw2100_data_header *ipw_hdr;
struct ieee80211_hdr_3addr *hdr;
struct libipw_hdr_3addr *hdr;
while (!list_empty(&priv->tx_pend_list)) {
/* if there isn't enough space in TBD queue, then
@ -3062,7 +3062,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
packet->index = txq->next;
ipw_hdr = packet->info.d_struct.data;
hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
fragments[0]->data;
if (priv->ieee->iw_mode == IW_MODE_INFRA) {
@ -3086,7 +3086,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
if (packet->info.d_struct.txb->nr_frags > 1)
ipw_hdr->fragment_size =
packet->info.d_struct.txb->frag_size -
IEEE80211_3ADDR_LEN;
LIBIPW_3ADDR_LEN;
else
ipw_hdr->fragment_size = 0;
@ -3119,13 +3119,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
tbd->buf_length = packet->info.d_struct.txb->
fragments[i]->len - IEEE80211_3ADDR_LEN;
fragments[i]->len - LIBIPW_3ADDR_LEN;
tbd->host_addr = pci_map_single(priv->pci_dev,
packet->info.d_struct.
txb->fragments[i]->
data +
IEEE80211_3ADDR_LEN,
LIBIPW_3ADDR_LEN,
tbd->buf_length,
PCI_DMA_TODEVICE);
@ -3330,10 +3330,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data)
return IRQ_NONE;
}
static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev,
int pri)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct list_head *element;
struct ipw2100_tx_packet *packet;
unsigned long flags;
@ -4488,7 +4488,7 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
/* We simply drop any SKBs that have been queued for
* transmit */
if (priv->tx_buffers[i].info.d_struct.txb) {
ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
libipw_txb_free(priv->tx_buffers[i].info.d_struct.
txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@ -4527,7 +4527,7 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv)
for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
if (priv->tx_buffers[i].info.d_struct.txb) {
ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
libipw_txb_free(priv->tx_buffers[i].info.d_struct.
txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@ -5558,9 +5558,9 @@ static void ipw2100_security_work(struct work_struct *work)
}
static void shim__set_security(struct net_device *dev,
struct ieee80211_security *sec)
struct libipw_security *sec)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int i, force_update = 0;
mutex_lock(&priv->action_mutex);
@ -5753,7 +5753,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
* method as well) to talk to the firmware */
static int ipw2100_set_address(struct net_device *dev, void *p)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct sockaddr *addr = p;
int err = 0;
@ -5781,7 +5781,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p)
static int ipw2100_open(struct net_device *dev)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
unsigned long flags;
IPW_DEBUG_INFO("dev->open\n");
@ -5797,7 +5797,7 @@ static int ipw2100_open(struct net_device *dev)
static int ipw2100_close(struct net_device *dev)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
unsigned long flags;
struct list_head *element;
struct ipw2100_tx_packet *packet;
@ -5818,7 +5818,7 @@ static int ipw2100_close(struct net_device *dev)
list_del(element);
DEC_STAT(&priv->tx_pend_stat);
ieee80211_txb_free(packet->info.d_struct.txb);
libipw_txb_free(packet->info.d_struct.txb);
packet->info.d_struct.txb = NULL;
list_add_tail(element, &priv->tx_free_list);
@ -5836,7 +5836,7 @@ static int ipw2100_close(struct net_device *dev)
*/
static void ipw2100_tx_timeout(struct net_device *dev)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
dev->stats.tx_errors++;
@ -5861,8 +5861,8 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
{
struct ieee80211_device *ieee = priv->ieee;
struct ieee80211_security sec = {
struct libipw_device *ieee = priv->ieee;
struct libipw_security sec = {
.flags = SEC_AUTH_MODE,
};
int ret = 0;
@ -5907,7 +5907,7 @@ static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
static void ipw_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
char fw_ver[64], ucode_ver[64];
strcpy(info->driver, DRV_NAME);
@ -5924,7 +5924,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
static u32 ipw2100_ethtool_get_link(struct net_device *dev)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
}
@ -6011,8 +6011,8 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
static const struct net_device_ops ipw2100_netdev_ops = {
.ndo_open = ipw2100_open,
.ndo_stop = ipw2100_close,
.ndo_start_xmit = ieee80211_xmit,
.ndo_change_mtu = ieee80211_change_mtu,
.ndo_start_xmit = libipw_xmit,
.ndo_change_mtu = libipw_change_mtu,
.ndo_init = ipw2100_net_init,
.ndo_tx_timeout = ipw2100_tx_timeout,
.ndo_set_mac_address = ipw2100_set_address,
@ -6029,10 +6029,10 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
struct ipw2100_priv *priv;
struct net_device *dev;
dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
if (!dev)
return NULL;
priv = ieee80211_priv(dev);
priv = libipw_priv(dev);
priv->ieee = netdev_priv(dev);
priv->pci_dev = pci_dev;
priv->net_dev = dev;
@ -6046,7 +6046,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
dev->netdev_ops = &ipw2100_netdev_ops;
dev->ethtool_ops = &ipw2100_ethtool_ops;
dev->wireless_handlers = &ipw2100_wx_handler_def;
priv->wireless_data.ieee80211 = priv->ieee;
priv->wireless_data.libipw = priv->ieee;
dev->wireless_data = &priv->wireless_data;
dev->watchdog_timeo = 3 * HZ;
dev->irq = 0;
@ -6202,7 +6202,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
return err;
}
priv = ieee80211_priv(dev);
priv = libipw_priv(dev);
pci_set_master(pci_dev);
pci_set_drvdata(pci_dev, priv);
@ -6342,7 +6342,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
sysfs_remove_group(&pci_dev->dev.kobj,
&ipw2100_attribute_group);
free_ieee80211(dev);
free_ieee80211(dev, 0);
pci_set_drvdata(pci_dev, NULL);
}
@ -6400,7 +6400,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
if (dev->base_addr)
iounmap((void __iomem *)dev->base_addr);
free_ieee80211(dev);
free_ieee80211(dev, 0);
}
pci_release_regions(pci_dev);
@ -6629,7 +6629,7 @@ static int ipw2100_wx_get_name(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (!(priv->status & STATUS_ASSOCIATED))
strcpy(wrqu->name, "unassociated");
else
@ -6643,7 +6643,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_freq *fwrq = &wrqu->freq;
int err = 0;
@ -6693,7 +6693,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->freq.e = 0;
@ -6714,7 +6714,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
@ -6757,7 +6757,7 @@ static int ipw2100_wx_get_mode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->mode = priv->ieee->iw_mode;
IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
@ -6792,7 +6792,7 @@ static int ipw2100_wx_get_range(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_range *range = (struct iw_range *)extra;
u16 val;
int i, level;
@ -6913,7 +6913,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
static const unsigned char any[] = {
@ -6962,7 +6962,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@ -6980,7 +6980,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
char *essid = ""; /* ANY */
int length = 0;
int err = 0;
@ -7035,7 +7035,7 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
DECLARE_SSID_BUF(ssid);
/* If we are associated, trying to associate, or have a statically
@ -7063,7 +7063,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
@ -7085,7 +7085,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
@ -7100,7 +7100,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
u32 target_rate = wrqu->bitrate.value;
u32 rate;
int err = 0;
@ -7140,7 +7140,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int val;
unsigned int len = sizeof(val);
int err = 0;
@ -7192,7 +7192,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int value, err;
/* Auto RTS not yet supported */
@ -7231,7 +7231,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
wrqu->rts.fixed = 1; /* no auto select */
@ -7248,7 +7248,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0, value;
if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
@ -7293,7 +7293,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
@ -7320,7 +7320,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (!wrqu->frag.fixed)
return -EINVAL;
@ -7350,7 +7350,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
wrqu->frag.fixed = 0; /* no auto select */
wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
@ -7364,7 +7364,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
@ -7412,7 +7412,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
wrqu->retry.disabled = 0; /* can't be disabled */
@ -7440,7 +7440,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
mutex_lock(&priv->action_mutex);
@ -7472,8 +7472,8 @@ static int ipw2100_wx_get_scan(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
struct ipw2100_priv *priv = libipw_priv(dev);
return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
}
/*
@ -7487,8 +7487,8 @@ static int ipw2100_wx_set_encode(struct net_device *dev,
* No check of STATUS_INITIALIZED required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
struct ipw2100_priv *priv = libipw_priv(dev);
return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
}
static int ipw2100_wx_get_encode(struct net_device *dev,
@ -7499,15 +7499,15 @@ static int ipw2100_wx_get_encode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
struct ipw2100_priv *priv = libipw_priv(dev);
return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
}
static int ipw2100_wx_set_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0;
mutex_lock(&priv->action_mutex);
@ -7556,7 +7556,7 @@ static int ipw2100_wx_get_power(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (!(priv->power_mode & IPW_POWER_ENABLED))
wrqu->power.disabled = 1;
@ -7580,8 +7580,8 @@ static int ipw2100_wx_set_genie(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
u8 *buf;
if (!ieee->wpa_enabled)
@ -7615,8 +7615,8 @@ static int ipw2100_wx_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
wrqu->data.length = 0;
@ -7637,8 +7637,8 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
struct lib80211_crypt_data *crypt;
unsigned long flags;
@ -7682,7 +7682,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
* can use this to determine if the CAP_PRIVACY_ON bit should
* be set.
*/
struct ieee80211_security sec = {
struct libipw_security sec = {
.flags = SEC_ENABLED,
.enabled = param->value,
};
@ -7730,8 +7730,8 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
struct lib80211_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
int ret = 0;
@ -7792,8 +7792,8 @@ static int ipw2100_wx_set_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
struct ipw2100_priv *priv = libipw_priv(dev);
return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCGIWENCODEEXT */
@ -7801,8 +7801,8 @@ static int ipw2100_wx_get_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
struct ipw2100_priv *priv = libipw_priv(dev);
return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
}
/* SIOCSIWMLME */
@ -7810,7 +7810,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
__le16 reason;
@ -7841,7 +7841,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int *parms = (int *)extra;
int enable = (parms[0] > 0);
int err = 0;
@ -7872,7 +7872,7 @@ static int ipw2100_wx_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->status & STATUS_INITIALIZED)
schedule_reset(priv);
return 0;
@ -7884,7 +7884,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err = 0, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@ -7912,7 +7912,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int level = IPW_POWER_LEVEL(priv->power_mode);
s32 timeout, period;
@ -7948,7 +7948,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@ -7981,7 +7981,7 @@ static int ipw2100_wx_get_preamble(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->config & CFG_LONG_PREAMBLE)
snprintf(wrqu->name, IFNAMSIZ, "long (1)");
@ -7996,7 +7996,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
int err, mode = *(int *)extra;
mutex_lock(&priv->action_mutex);
@ -8028,7 +8028,7 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev,
* This can be called at any time. No action lock required
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
if (priv->config & CFG_CRC_CHECK)
snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
@ -8181,7 +8181,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
int beacon_qual;
int quality;
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ipw2100_priv *priv = libipw_priv(dev);
struct iw_statistics *wstats;
u32 rssi, tx_retries, missed_beacons, tx_failures;
u32 ord_len = sizeof(u32);

View file

@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@ -46,7 +46,7 @@
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include "ieee80211.h"
#include "libipw.h"
struct ipw2100_priv;
struct ipw2100_tx_packet;
@ -343,7 +343,7 @@ struct ipw2100_tx_packet {
struct { /* DATA */
struct ipw2100_data_header *data;
dma_addr_t data_phys;
struct ieee80211_txb *txb;
struct libipw_txb *txb;
} d_struct;
} info;
int jiffy_start;
@ -492,7 +492,7 @@ struct ipw2100_priv {
int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
struct ieee80211_device *ieee;
struct libipw_device *ieee;
unsigned long status;
unsigned long config;
unsigned long capability;
@ -788,7 +788,7 @@ struct ipw2100_priv {
#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr)
#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr)
#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
@ -803,13 +803,13 @@ struct ipw2100_priv {
IPW_802_11_FCS_LENGTH)
#define IPW_802_11_PAYLOAD_OFFSET \
(sizeof(struct ieee80211_hdr_3addr) + \
sizeof(struct ieee80211_snap_hdr))
(sizeof(struct libipw_hdr_3addr) + \
sizeof(struct libipw_snap_hdr))
struct ipw2100_rx {
union {
unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
struct ieee80211_hdr_4addr header;
struct libipw_hdr_4addr header;
u32 status;
struct ipw2100_notification notification;
struct ipw2100_cmd_header command;

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@ -55,7 +55,7 @@
#include <linux/workqueue.h>
#include "ieee80211.h"
#include "libipw.h"
/* Authentication and Association States */
enum connection_manager_assoc_states {
@ -365,8 +365,8 @@ enum connection_manager_assoc_states {
/* QoS sturctures */
struct ipw_qos_info {
int qos_enable;
struct ieee80211_qos_parameters *def_qos_parm_OFDM;
struct ieee80211_qos_parameters *def_qos_parm_CCK;
struct libipw_qos_parameters *def_qos_parm_OFDM;
struct libipw_qos_parameters *def_qos_parm_CCK;
u32 burst_duration_CCK;
u32 burst_duration_OFDM;
u16 qos_no_ack_mask;
@ -534,7 +534,7 @@ typedef void destructor_func(const void *);
struct clx2_tx_queue {
struct clx2_queue q;
struct tfd_frame *bd;
struct ieee80211_txb **txb;
struct libipw_txb **txb;
};
/*
@ -1144,7 +1144,7 @@ enum ipw_prom_filter {
struct ipw_priv;
struct ipw_prom_priv {
struct ipw_priv *priv;
struct ieee80211_device *ieee;
struct libipw_device *ieee;
enum ipw_prom_filter filter;
int tx_packets;
int rx_packets;
@ -1175,7 +1175,7 @@ struct ipw_rt_hdr {
struct ipw_priv {
/* ieee device used by generic ieee processing code */
struct ieee80211_device *ieee;
struct libipw_device *ieee;
spinlock_t lock;
spinlock_t irq_lock;
@ -1222,7 +1222,7 @@ struct ipw_priv {
u32 roaming_threshold;
struct ipw_associate assoc_request;
struct ieee80211_network *assoc_network;
struct libipw_network *assoc_network;
unsigned long ts_scan_abort;
struct ipw_supported_rates rates;

View file

@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@ -41,9 +41,9 @@
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include "ieee80211.h"
#include "libipw.h"
int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel)
{
int i;
@ -52,27 +52,27 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return 0;
if (ieee->freq_band & IEEE80211_24GHZ_BAND)
if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
/* NOTE: If G mode is currently supported but
* this is a B only channel, we don't see it
* as valid. */
if ((ieee->geo.bg[i].channel == channel) &&
!(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) &&
!(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) &&
(!(ieee->mode & IEEE_G) ||
!(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
return IEEE80211_24GHZ_BAND;
!(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY)))
return LIBIPW_24GHZ_BAND;
if (ieee->freq_band & IEEE80211_52GHZ_BAND)
if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if ((ieee->geo.a[i].channel == channel) &&
!(ieee->geo.a[i].flags & IEEE80211_CH_INVALID))
return IEEE80211_52GHZ_BAND;
!(ieee->geo.a[i].flags & LIBIPW_CH_INVALID))
return LIBIPW_52GHZ_BAND;
return 0;
}
int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
int libipw_channel_to_index(struct libipw_device *ieee, u8 channel)
{
int i;
@ -81,12 +81,12 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return -1;
if (ieee->freq_band & IEEE80211_24GHZ_BAND)
if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
if (ieee->geo.bg[i].channel == channel)
return i;
if (ieee->freq_band & IEEE80211_52GHZ_BAND)
if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if (ieee->geo.a[i].channel == channel)
return i;
@ -94,22 +94,22 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
return -1;
}
u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel)
{
const struct ieee80211_channel * ch;
const struct libipw_channel * ch;
/* Driver needs to initialize the geography map before using
* these helper functions */
if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
return 0;
ch = ieee80211_get_channel(ieee, channel);
ch = libipw_get_channel(ieee, channel);
if (!ch->channel)
return 0;
return ch->freq;
}
u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
{
int i;
@ -120,12 +120,12 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
freq /= 100000;
if (ieee->freq_band & IEEE80211_24GHZ_BAND)
if (ieee->freq_band & LIBIPW_24GHZ_BAND)
for (i = 0; i < ieee->geo.bg_channels; i++)
if (ieee->geo.bg[i].freq == freq)
return ieee->geo.bg[i].channel;
if (ieee->freq_band & IEEE80211_52GHZ_BAND)
if (ieee->freq_band & LIBIPW_52GHZ_BAND)
for (i = 0; i < ieee->geo.a_channels; i++)
if (ieee->geo.a[i].freq == freq)
return ieee->geo.a[i].channel;
@ -133,63 +133,63 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
return 0;
}
int ieee80211_set_geo(struct ieee80211_device *ieee,
const struct ieee80211_geo *geo)
int libipw_set_geo(struct libipw_device *ieee,
const struct libipw_geo *geo)
{
memcpy(ieee->geo.name, geo->name, 3);
ieee->geo.name[3] = '\0';
ieee->geo.bg_channels = geo->bg_channels;
ieee->geo.a_channels = geo->a_channels;
memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
sizeof(struct ieee80211_channel));
sizeof(struct libipw_channel));
memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
sizeof(struct ieee80211_channel));
sizeof(struct libipw_channel));
return 0;
}
const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee)
const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
{
return &ieee->geo;
}
u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel)
u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel)
{
int index = ieee80211_channel_to_index(ieee, channel);
int index = libipw_channel_to_index(ieee, channel);
if (index == -1)
return IEEE80211_CH_INVALID;
return LIBIPW_CH_INVALID;
if (channel <= IEEE80211_24GHZ_CHANNELS)
if (channel <= LIBIPW_24GHZ_CHANNELS)
return ieee->geo.bg[index].flags;
return ieee->geo.a[index].flags;
}
static const struct ieee80211_channel bad_channel = {
static const struct libipw_channel bad_channel = {
.channel = 0,
.flags = IEEE80211_CH_INVALID,
.flags = LIBIPW_CH_INVALID,
.max_power = 0,
};
const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device
const struct libipw_channel *libipw_get_channel(struct libipw_device
*ieee, u8 channel)
{
int index = ieee80211_channel_to_index(ieee, channel);
int index = libipw_channel_to_index(ieee, channel);
if (index == -1)
return &bad_channel;
if (channel <= IEEE80211_24GHZ_CHANNELS)
if (channel <= LIBIPW_24GHZ_CHANNELS)
return &ieee->geo.bg[index];
return &ieee->geo.a[index];
}
EXPORT_SYMBOL(ieee80211_get_channel);
EXPORT_SYMBOL(ieee80211_get_channel_flags);
EXPORT_SYMBOL(ieee80211_is_valid_channel);
EXPORT_SYMBOL(ieee80211_freq_to_channel);
EXPORT_SYMBOL(ieee80211_channel_to_freq);
EXPORT_SYMBOL(ieee80211_channel_to_index);
EXPORT_SYMBOL(ieee80211_set_geo);
EXPORT_SYMBOL(ieee80211_get_geo);
EXPORT_SYMBOL(libipw_get_channel);
EXPORT_SYMBOL(libipw_get_channel_flags);
EXPORT_SYMBOL(libipw_is_valid_channel);
EXPORT_SYMBOL(libipw_freq_to_channel);
EXPORT_SYMBOL(libipw_channel_to_freq);
EXPORT_SYMBOL(libipw_channel_to_index);
EXPORT_SYMBOL(libipw_set_geo);
EXPORT_SYMBOL(libipw_get_geo);

View file

@ -25,7 +25,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@ -50,11 +50,11 @@
#include <net/net_namespace.h>
#include <net/arp.h>
#include "ieee80211.h"
#include "libipw.h"
#define DRV_DESCRIPTION "802.11 data/management/control stack"
#define DRV_NAME "ieee80211"
#define DRV_VERSION IEEE80211_VERSION
#define DRV_VERSION LIBIPW_VERSION
#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
MODULE_VERSION(DRV_VERSION);
@ -62,13 +62,16 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
struct cfg80211_ops libipw_config_ops = { };
void *libipw_wiphy_privid = &libipw_wiphy_privid;
static int libipw_networks_allocate(struct libipw_device *ieee)
{
if (ieee->networks)
return 0;
ieee->networks =
kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network),
GFP_KERNEL);
if (!ieee->networks) {
printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
@ -79,7 +82,7 @@ static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
return 0;
}
void ieee80211_network_reset(struct ieee80211_network *network)
void libipw_network_reset(struct libipw_network *network)
{
if (!network)
return;
@ -90,7 +93,7 @@ void ieee80211_network_reset(struct ieee80211_network *network)
}
}
static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
static inline void libipw_networks_free(struct libipw_device *ieee)
{
int i;
@ -105,10 +108,10 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
ieee->networks = NULL;
}
void ieee80211_networks_age(struct ieee80211_device *ieee,
void libipw_networks_age(struct libipw_device *ieee,
unsigned long age_secs)
{
struct ieee80211_network *network = NULL;
struct libipw_network *network = NULL;
unsigned long flags;
unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
@ -118,9 +121,9 @@ void ieee80211_networks_age(struct ieee80211_device *ieee,
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
EXPORT_SYMBOL(ieee80211_networks_age);
EXPORT_SYMBOL(libipw_networks_age);
static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
static void libipw_networks_initialize(struct libipw_device *ieee)
{
int i;
@ -131,38 +134,59 @@ static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
&ieee->network_free_list);
}
int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
int libipw_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
return -EINVAL;
dev->mtu = new_mtu;
return 0;
}
EXPORT_SYMBOL(ieee80211_change_mtu);
EXPORT_SYMBOL(libipw_change_mtu);
struct net_device *alloc_ieee80211(int sizeof_priv)
struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
{
struct ieee80211_device *ieee;
struct libipw_device *ieee;
struct net_device *dev;
int err;
IEEE80211_DEBUG_INFO("Initializing...\n");
LIBIPW_DEBUG_INFO("Initializing...\n");
dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
if (!dev) {
IEEE80211_ERROR("Unable to allocate network device.\n");
LIBIPW_ERROR("Unable to allocate network device.\n");
goto failed;
}
ieee = netdev_priv(dev);
ieee->dev = dev;
err = ieee80211_networks_allocate(ieee);
if (err) {
IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
goto failed_free_netdev;
if (!monitor) {
ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
if (!ieee->wdev.wiphy) {
LIBIPW_ERROR("Unable to allocate wiphy.\n");
goto failed_free_netdev;
}
ieee->dev->ieee80211_ptr = &ieee->wdev;
ieee->wdev.iftype = NL80211_IFTYPE_STATION;
/* Fill-out wiphy structure bits we know... Not enough info
here to call set_wiphy_dev or set MAC address or channel info
-- have to do that in ->ndo_init... */
ieee->wdev.wiphy->privid = libipw_wiphy_privid;
ieee->wdev.wiphy->max_scan_ssids = 1;
ieee->wdev.wiphy->max_scan_ie_len = 0;
ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
| BIT(NL80211_IFTYPE_ADHOC);
}
ieee80211_networks_initialize(ieee);
err = libipw_networks_allocate(ieee);
if (err) {
LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
goto failed_free_wiphy;
}
libipw_networks_initialize(ieee);
/* Default fragmentation threshold is maximum payload size */
ieee->fts = DEFAULT_FTS;
@ -193,33 +217,45 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
return dev;
failed_free_wiphy:
if (!monitor)
wiphy_free(ieee->wdev.wiphy);
failed_free_netdev:
free_netdev(dev);
failed:
return NULL;
}
void free_ieee80211(struct net_device *dev)
void free_ieee80211(struct net_device *dev, int monitor)
{
struct ieee80211_device *ieee = netdev_priv(dev);
struct libipw_device *ieee = netdev_priv(dev);
lib80211_crypt_info_free(&ieee->crypt_info);
ieee80211_networks_free(ieee);
libipw_networks_free(ieee);
/* free cfg80211 resources */
if (!monitor) {
wiphy_unregister(ieee->wdev.wiphy);
kfree(ieee->a_band.channels);
kfree(ieee->bg_band.channels);
wiphy_free(ieee->wdev.wiphy);
}
free_netdev(dev);
}
#ifdef CONFIG_LIBIPW_DEBUG
static int debug = 0;
u32 ieee80211_debug_level = 0;
EXPORT_SYMBOL_GPL(ieee80211_debug_level);
static struct proc_dir_entry *ieee80211_proc = NULL;
u32 libipw_debug_level = 0;
EXPORT_SYMBOL_GPL(libipw_debug_level);
static struct proc_dir_entry *libipw_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
int count, int *eof, void *data)
{
return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
return snprintf(page, count, "0x%08X\n", libipw_debug_level);
}
static int store_debug_level(struct file *file, const char __user * buffer,
@ -236,29 +272,29 @@ static int store_debug_level(struct file *file, const char __user * buffer,
printk(KERN_INFO DRV_NAME
": %s is not in hex or decimal form.\n", buf);
else
ieee80211_debug_level = val;
libipw_debug_level = val;
return strnlen(buf, len);
}
#endif /* CONFIG_LIBIPW_DEBUG */
static int __init ieee80211_init(void)
static int __init libipw_init(void)
{
#ifdef CONFIG_LIBIPW_DEBUG
struct proc_dir_entry *e;
ieee80211_debug_level = debug;
ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
if (ieee80211_proc == NULL) {
IEEE80211_ERROR("Unable to create " DRV_NAME
libipw_debug_level = debug;
libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
if (libipw_proc == NULL) {
LIBIPW_ERROR("Unable to create " DRV_NAME
" proc directory\n");
return -EIO;
}
e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
ieee80211_proc);
libipw_proc);
if (!e) {
remove_proc_entry(DRV_NAME, init_net.proc_net);
ieee80211_proc = NULL;
libipw_proc = NULL;
return -EIO;
}
e->read_proc = show_debug_level;
@ -272,13 +308,13 @@ static int __init ieee80211_init(void)
return 0;
}
static void __exit ieee80211_exit(void)
static void __exit libipw_exit(void)
{
#ifdef CONFIG_LIBIPW_DEBUG
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
if (libipw_proc) {
remove_proc_entry("debug_level", libipw_proc);
remove_proc_entry(DRV_NAME, init_net.proc_net);
ieee80211_proc = NULL;
libipw_proc = NULL;
}
#endif /* CONFIG_LIBIPW_DEBUG */
}
@ -289,8 +325,8 @@ module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
#endif /* CONFIG_LIBIPW_DEBUG */
module_exit(ieee80211_exit);
module_init(ieee80211_init);
module_exit(libipw_exit);
module_init(libipw_init);
EXPORT_SYMBOL(alloc_ieee80211);
EXPORT_SYMBOL(free_ieee80211);

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@ -41,7 +41,7 @@
#include <linux/etherdevice.h>
#include <asm/uaccess.h>
#include "ieee80211.h"
#include "libipw.h"
/*
@ -126,12 +126,12 @@ payload of each frame is reduced to 492 bytes.
static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
static int libipw_copy_snap(u8 * data, __be16 h_proto)
{
struct ieee80211_snap_hdr *snap;
struct libipw_snap_hdr *snap;
u8 *oui;
snap = (struct ieee80211_snap_hdr *)data;
snap = (struct libipw_snap_hdr *)data;
snap->dsap = 0xaa;
snap->ssap = 0xaa;
snap->ctrl = 0x03;
@ -149,7 +149,7 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
return SNAP_SIZE + sizeof(u16);
}
static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
static int libipw_encrypt_fragment(struct libipw_device *ieee,
struct sk_buff *frag, int hdr_len)
{
struct lib80211_crypt_data *crypt =
@ -177,7 +177,7 @@ static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
return 0;
}
void ieee80211_txb_free(struct ieee80211_txb *txb)
void libipw_txb_free(struct libipw_txb *txb)
{
int i;
if (unlikely(!txb))
@ -188,17 +188,17 @@ void ieee80211_txb_free(struct ieee80211_txb *txb)
kfree(txb);
}
static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size,
int headroom, gfp_t gfp_mask)
{
struct ieee80211_txb *txb;
struct libipw_txb *txb;
int i;
txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
txb = kmalloc(sizeof(struct libipw_txb) + (sizeof(u8 *) * nr_frags),
gfp_mask);
if (!txb)
return NULL;
memset(txb, 0, sizeof(struct ieee80211_txb));
memset(txb, 0, sizeof(struct libipw_txb));
txb->nr_frags = nr_frags;
txb->frag_size = txb_size;
@ -220,7 +220,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
return txb;
}
static int ieee80211_classify(struct sk_buff *skb)
static int libipw_classify(struct sk_buff *skb)
{
struct ethhdr *eth;
struct iphdr *ip;
@ -252,11 +252,11 @@ static int ieee80211_classify(struct sk_buff *skb)
/* Incoming skb is converted to a txb which consists of
* a block of 802.11 fragment packets (stored as skbs) */
int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
int libipw_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addrqos *frag_hdr;
struct libipw_device *ieee = netdev_priv(dev);
struct libipw_txb *txb = NULL;
struct libipw_hdr_3addrqos *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
rts_required;
unsigned long flags;
@ -264,7 +264,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
__be16 ether_type;
int bytes, fc, hdr_len;
struct sk_buff *skb_frag;
struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
.duration_id = 0,
.seq_ctl = 0,
.qos_ctl = 0
@ -331,14 +331,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy(header.addr2, src, ETH_ALEN);
memcpy(header.addr3, ieee->bssid, ETH_ALEN);
}
hdr_len = IEEE80211_3ADDR_LEN;
hdr_len = LIBIPW_3ADDR_LEN;
if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdr_len += 2;
skb->priority = ieee80211_classify(skb);
header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
skb->priority = libipw_classify(skb);
header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID);
}
header.frame_ctl = cpu_to_le16(fc);
@ -362,12 +362,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
snapped = 1;
ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
ether_type);
skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
if (res < 0) {
IEEE80211_ERROR("msdu encryption failed\n");
LIBIPW_ERROR("msdu encryption failed\n");
dev_kfree_skb_any(skb_new);
goto failed;
}
@ -393,8 +393,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
* for it when determining the amount of payload space. */
bytes_per_frag = frag_size - hdr_len;
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
bytes_per_frag -= IEEE80211_FCS_LEN;
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
bytes_per_frag -= LIBIPW_FCS_LEN;
/* Each fragment may need to have room for encryptiong
* pre/postfix */
@ -417,14 +417,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
rts_required = (frag_size > ieee->rts
&& ieee->config & CFG_IEEE80211_RTS);
&& ieee->config & CFG_LIBIPW_RTS);
if (rts_required)
nr_frags++;
/* When we allocate the TXB we allocate enough space for the reserve
* and full fragment bytes (bytes_per_frag doesn't include prefix,
* postfix, header, FCS, etc.) */
txb = ieee80211_alloc_txb(nr_frags, frag_size,
txb = libipw_alloc_txb(nr_frags, frag_size,
ieee->tx_headroom, GFP_ATOMIC);
if (unlikely(!txb)) {
printk(KERN_WARNING "%s: Could not allocate TXB\n",
@ -441,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (rts_required) {
skb_frag = txb->fragments[0];
frag_hdr =
(struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
(struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
/*
* Set header frame_ctl to the RTS.
@ -456,7 +456,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
header.frame_ctl = cpu_to_le16(fc);
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
skb_put(skb_frag, 4);
txb->rts_included = 1;
@ -472,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
crypt->ops->extra_mpdu_prefix_len);
frag_hdr =
(struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
(struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
memcpy(frag_hdr, &header, hdr_len);
/* If this is not the last fragment, then add the MOREFRAGS
@ -487,7 +487,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (i == 0 && !snapped) {
ieee80211_copy_snap(skb_put
libipw_copy_snap(skb_put
(skb_frag, SNAP_SIZE + sizeof(u16)),
ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
@ -501,7 +501,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */
if (host_encrypt)
ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
else if (host_build_iv) {
atomic_inc(&crypt->refcnt);
if (crypt->ops->build_iv)
@ -513,7 +513,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (ieee->config &
(CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
skb_put(skb_frag, 4);
}
@ -530,7 +530,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
libipw_txb_free(txb);
}
return NETDEV_TX_OK;
@ -541,6 +541,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
return NETDEV_TX_BUSY;
}
EXPORT_SYMBOL(ieee80211_xmit);
EXPORT_SYMBOL(libipw_xmit);
EXPORT_SYMBOL(ieee80211_txb_free);
EXPORT_SYMBOL(libipw_txb_free);

View file

@ -25,7 +25,7 @@
file called LICENSE.
Contact Information:
James P. Ketrenos <ipw2100-admin@linux.intel.com>
Intel Linux Wireless <ilw@linux.intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
******************************************************************************/
@ -37,9 +37,9 @@
#include <net/lib80211.h>
#include <linux/wireless.h>
#include "ieee80211.h"
#include "libipw.h"
static const char *ieee80211_modes[] = {
static const char *libipw_modes[] = {
"?", "a", "b", "ab", "g", "ag", "bg", "abg"
};
@ -54,9 +54,9 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
}
#define MAX_CUSTOM_LEN 64
static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
static char *libipw_translate_scan(struct libipw_device *ieee,
char *start, char *stop,
struct ieee80211_network *network,
struct libipw_network *network,
struct iw_request_info *info)
{
char custom[MAX_CUSTOM_LEN];
@ -84,7 +84,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
ieee80211_modes[network->mode]);
libipw_modes[network->mode]);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
/* Add mode */
@ -102,7 +102,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
/* Add channel and frequency */
/* Note : userspace automatically computes channel using iwrange */
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
iwe.u.freq.e = 6;
iwe.u.freq.i = 0;
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
@ -155,7 +155,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
IW_QUAL_NOISE_UPDATED;
if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
IW_QUAL_LEVEL_INVALID;
iwe.u.qual.qual = 0;
@ -180,14 +180,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
iwe.u.qual.qual = 0;
}
if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
iwe.u.qual.noise = 0;
} else {
iwe.u.qual.noise = network->stats.noise;
}
if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
iwe.u.qual.level = 0;
} else {
@ -237,14 +237,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
if (ieee80211_get_channel_flags(ieee, network->channel) &
IEEE80211_CH_INVALID) {
if (libipw_get_channel_flags(ieee, network->channel) &
LIBIPW_CH_INVALID) {
iwe.cmd = IWEVCUSTOM;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
}
if (ieee80211_get_channel_flags(ieee, network->channel) &
IEEE80211_CH_RADAR_DETECT) {
if (libipw_get_channel_flags(ieee, network->channel) &
LIBIPW_CH_RADAR_DETECT) {
iwe.cmd = IWEVCUSTOM;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
}
@ -259,11 +259,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
#define SCAN_ITEM_SIZE 128
int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
int libipw_wx_get_scan(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ieee80211_network *network;
struct libipw_network *network;
unsigned long flags;
int err = 0;
@ -272,7 +272,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
int i = 0;
DECLARE_SSID_BUF(ssid);
IEEE80211_DEBUG_WX("Getting scan\n");
LIBIPW_DEBUG_WX("Getting scan\n");
spin_lock_irqsave(&ieee->lock, flags);
@ -285,10 +285,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
if (ieee->scan_age == 0 ||
time_after(network->last_scanned + ieee->scan_age, jiffies))
ev = ieee80211_translate_scan(ieee, ev, stop, network,
ev = libipw_translate_scan(ieee, ev, stop, network,
info);
else {
IEEE80211_DEBUG_SCAN("Not showing network '%s ("
LIBIPW_DEBUG_SCAN("Not showing network '%s ("
"%pM)' due to age (%ums).\n",
print_ssid(ssid, network->ssid,
network->ssid_len),
@ -303,18 +303,18 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
wrqu->data.length = ev - extra;
wrqu->data.flags = 0;
IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
return err;
}
int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
int libipw_wx_set_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
struct net_device *dev = ieee->dev;
struct ieee80211_security sec = {
struct libipw_security sec = {
.flags = 0
};
int i, key, key_provided, len;
@ -322,7 +322,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
DECLARE_SSID_BUF(ssid);
IEEE80211_DEBUG_WX("SET_ENCODE\n");
LIBIPW_DEBUG_WX("SET_ENCODE\n");
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
@ -335,18 +335,18 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
key = ieee->crypt_info.tx_keyidx;
}
IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
"provided" : "default");
crypt = &ieee->crypt_info.crypt[key];
if (erq->flags & IW_ENCODE_DISABLED) {
if (key_provided && *crypt) {
IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
key);
lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
} else
IEEE80211_DEBUG_WX("Disabling encryption.\n");
LIBIPW_DEBUG_WX("Disabling encryption.\n");
/* Check all the keys to see if any are still configured,
* and if no key index was provided, de-init them all */
@ -410,7 +410,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
/* If a new key was provided, set it up */
if (erq->length > 0) {
#ifdef CONFIG_IEEE80211_DEBUG
#ifdef CONFIG_LIBIPW_DEBUG
DECLARE_SSID_BUF(ssid);
#endif
@ -419,7 +419,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
if (len > erq->length)
memset(sec.keys[key] + erq->length, 0,
len - erq->length);
IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
key, print_ssid(ssid, sec.keys[key], len),
erq->length, len);
sec.key_sizes[key] = len;
@ -438,7 +438,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
NULL, (*crypt)->priv);
if (len == 0) {
/* Set a default key of all 0 */
IEEE80211_DEBUG_WX("Setting key %d to all "
LIBIPW_DEBUG_WX("Setting key %d to all "
"zero.\n", key);
memset(sec.keys[key], 0, 13);
(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
@ -449,7 +449,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
}
/* No key data - just set the default TX key index */
if (key_provided) {
IEEE80211_DEBUG_WX("Setting key %d to default Tx "
LIBIPW_DEBUG_WX("Setting key %d to default Tx "
"key.\n", key);
ieee->crypt_info.tx_keyidx = key;
sec.active_key = key;
@ -461,7 +461,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
WLAN_AUTH_SHARED_KEY;
sec.flags |= SEC_AUTH_MODE;
IEEE80211_DEBUG_WX("Auth: %s\n",
LIBIPW_DEBUG_WX("Auth: %s\n",
sec.auth_mode == WLAN_AUTH_OPEN ?
"OPEN" : "SHARED KEY");
}
@ -490,16 +490,16 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
return 0;
}
int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
int libipw_wx_get_encode(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *keybuf)
{
struct iw_point *erq = &(wrqu->encoding);
int len, key;
struct lib80211_crypt_data *crypt;
struct ieee80211_security *sec = &ieee->sec;
struct libipw_security *sec = &ieee->sec;
IEEE80211_DEBUG_WX("GET_ENCODE\n");
LIBIPW_DEBUG_WX("GET_ENCODE\n");
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
@ -532,7 +532,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
return 0;
}
int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
int libipw_wx_set_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
@ -545,7 +545,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
struct lib80211_crypto_ops *ops;
struct lib80211_crypt_data **crypt;
struct ieee80211_security sec = {
struct libipw_security sec = {
.flags = 0,
};
@ -611,7 +611,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
module = "lib80211_crypt_ccmp";
break;
default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
@ -623,7 +623,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
ops = lib80211_get_crypto_ops(alg);
}
if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
@ -653,7 +653,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
if (ext->key_len > 0 && (*crypt)->ops->set_key &&
(*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
(*crypt)->priv) < 0) {
IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
ret = -EINVAL;
goto done;
}
@ -700,20 +700,20 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name);
return -EINVAL;
}
return ret;
}
int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
int libipw_wx_get_encodeext(struct libipw_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct ieee80211_security *sec = &ieee->sec;
struct libipw_security *sec = &ieee->sec;
int idx, max_key_len;
max_key_len = encoding->length - sizeof(*ext);
@ -763,9 +763,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
return 0;
}
EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
EXPORT_SYMBOL(libipw_wx_set_encodeext);
EXPORT_SYMBOL(libipw_wx_get_encodeext);
EXPORT_SYMBOL(ieee80211_wx_get_scan);
EXPORT_SYMBOL(ieee80211_wx_set_encode);
EXPORT_SYMBOL(ieee80211_wx_get_encode);
EXPORT_SYMBOL(libipw_wx_get_scan);
EXPORT_SYMBOL(libipw_wx_set_encode);
EXPORT_SYMBOL(libipw_wx_get_encode);

View file

@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 3
#define IWL6050_UCODE_API_MAX 3
#define IWL6000_UCODE_API_MAX 4
#define IWL6050_UCODE_API_MAX 4
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@ -126,6 +126,7 @@ static struct iwl_lib_ops iwl6000_lib = {
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
.update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,

View file

@ -2546,6 +2546,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
rate_idx = rate_lowest_index(sband, sta);
else if (sband->band == IEEE80211_BAND_5GHZ)
rate_idx -= IWL_FIRST_OFDM_RATE;
info->control.rates[0].flags = 0;
}
info->control.rates[0].idx = rate_idx;

View file

@ -2155,7 +2155,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
priv->is_open = 0;
if (iwl_is_ready_rf(priv)) {
if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
/* stop mac, cancel any scan request and clear
* RXON_FILTER_ASSOC_MSK BIT
*/
@ -2477,10 +2477,15 @@ static ssize_t store_tx_power(struct device *d,
ret = strict_strtoul(buf, 10, &val);
if (ret)
IWL_INFO(priv, "%s is not in decimal form.\n", buf);
else
iwl_set_tx_power(priv, val, false);
return count;
else {
ret = iwl_set_tx_power(priv, val, false);
if (ret)
IWL_ERR(priv, "failed setting tx power (0x%d).\n",
ret);
else
ret = count;
}
return ret;
}
static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);

View file

@ -886,7 +886,6 @@ struct iwl_qosparam_cmd {
#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2);
#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17)
#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18)
#define STA_FLG_MAX_AGG_SIZE_POS (19)
@ -2930,6 +2929,20 @@ struct statistics_rx {
struct statistics_rx_ht_phy ofdm_ht;
} __attribute__ ((packed));
/**
* struct statistics_tx_power - current tx power
*
* @ant_a: current tx power on chain a in 1/2 dB step
* @ant_b: current tx power on chain b in 1/2 dB step
* @ant_c: current tx power on chain c in 1/2 dB step
*/
struct statistics_tx_power {
u8 ant_a;
u8 ant_b;
u8 ant_c;
u8 reserved;
} __attribute__ ((packed));
struct statistics_tx_non_phy_agg {
__le32 ba_timeout;
__le32 ba_reschedule_frames;
@ -2941,8 +2954,6 @@ struct statistics_tx_non_phy_agg {
__le32 underrun;
__le32 bt_prio_kill;
__le32 rx_ba_rsp_cnt;
__le32 reserved2;
__le32 reserved3;
} __attribute__ ((packed));
struct statistics_tx {
@ -2961,6 +2972,8 @@ struct statistics_tx {
__le32 cts_timeout_collision;
__le32 ack_or_ba_timeout_collision;
struct statistics_tx_non_phy_agg agg;
struct statistics_tx_power tx_power;
__le32 reserved1;
} __attribute__ ((packed));

View file

@ -543,8 +543,8 @@ int iwlcore_init_geos(struct iwl_priv *priv)
geo_ch->flags |= ch->ht40_extension_channel;
if (ch->max_power_avg > priv->tx_power_channel_lmt)
priv->tx_power_channel_lmt = ch->max_power_avg;
if (ch->max_power_avg > priv->tx_power_device_lmt)
priv->tx_power_device_lmt = ch->max_power_avg;
} else {
geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
@ -1671,7 +1671,10 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->qos_data.qos_cap.val = 0;
priv->rates_mask = IWL_RATES_MASK;
priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX;
/* Set the tx_power_user_lmt to the lowest power level
* this value will get overwritten by channel max power avg
* from eeprom */
priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN;
ret = iwl_init_channel_map(priv);
if (ret) {
@ -1698,6 +1701,8 @@ EXPORT_SYMBOL(iwl_init_drv);
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
int ret = 0;
s8 prev_tx_power = priv->tx_power_user_lmt;
if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
tx_power,
@ -1705,25 +1710,37 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
return -EINVAL;
}
if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) {
IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n",
tx_power,
IWL_TX_POWER_TARGET_POWER_MAX);
if (tx_power > priv->tx_power_device_lmt) {
IWL_WARN(priv,
"Requested user TXPOWER %d above upper limit %d.\n",
tx_power, priv->tx_power_device_lmt);
return -EINVAL;
}
if (priv->tx_power_user_lmt != tx_power)
force = true;
priv->tx_power_user_lmt = tx_power;
/* if nic is not up don't send command */
if (!iwl_is_ready_rf(priv))
return ret;
if (force && priv->cfg->ops->lib->send_tx_power)
ret = priv->cfg->ops->lib->send_tx_power(priv);
if (iwl_is_ready_rf(priv)) {
priv->tx_power_user_lmt = tx_power;
if (force && priv->cfg->ops->lib->send_tx_power)
ret = priv->cfg->ops->lib->send_tx_power(priv);
else if (!priv->cfg->ops->lib->send_tx_power)
ret = -EOPNOTSUPP;
/*
* if fail to set tx_power, restore the orig. tx power
*/
if (ret)
priv->tx_power_user_lmt = prev_tx_power;
}
/*
* Even this is an async host command, the command
* will always report success from uCode
* So once driver can placing the command into the queue
* successfully, driver can use priv->tx_power_user_lmt
* to reflect the current tx power
*/
return ret;
}
EXPORT_SYMBOL(iwl_set_tx_power);
@ -1806,7 +1823,7 @@ int iwl_reset_ict(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
iwl_disable_interrupts(priv);
memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT);
memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
@ -1884,13 +1901,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
/* read all entries that not 0 start with ict_index */
while (priv->ict_tbl[priv->ict_index]) {
val |= priv->ict_tbl[priv->ict_index];
val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]);
IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
priv->ict_index,
priv->ict_tbl[priv->ict_index]);
priv->ict_index,
le32_to_cpu(priv->ict_tbl[priv->ict_index]));
priv->ict_tbl[priv->ict_index] = 0;
priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
ICT_COUNT);
ICT_COUNT);
}

View file

@ -107,6 +107,7 @@ struct iwl_debugfs {
struct dentry *file_ucode_general_stats;
struct dentry *file_sensitivity;
struct dentry *file_chain_noise;
struct dentry *file_tx_power;
} dbgfs_debug_files;
u32 sram_offset;
u32 sram_len;

View file

@ -1563,6 +1563,57 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
return ret;
}
static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
char buf[128];
int pos = 0;
ssize_t ret;
const size_t bufsz = sizeof(buf);
struct statistics_tx *tx;
if (!iwl_is_alive(priv))
pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
else {
/* make request to uCode to retrieve statistics information */
mutex_lock(&priv->mutex);
ret = iwl_send_statistics_request(priv, 0);
mutex_unlock(&priv->mutex);
if (ret) {
IWL_ERR(priv, "Error sending statistics request: %zd\n",
ret);
return -EAGAIN;
}
tx = &priv->statistics.tx;
if (tx->tx_power.ant_a ||
tx->tx_power.ant_b ||
tx->tx_power.ant_c) {
pos += scnprintf(buf + pos, bufsz - pos,
"tx power: (1/2 dB step)\n");
if ((priv->cfg->valid_tx_ant & ANT_A) &&
tx->tx_power.ant_a)
pos += scnprintf(buf + pos, bufsz - pos,
"\tantenna A: 0x%X\n",
tx->tx_power.ant_a);
if ((priv->cfg->valid_tx_ant & ANT_B) &&
tx->tx_power.ant_b)
pos += scnprintf(buf + pos, bufsz - pos,
"\tantenna B: 0x%X\n",
tx->tx_power.ant_b);
if ((priv->cfg->valid_tx_ant & ANT_C) &&
tx->tx_power.ant_c)
pos += scnprintf(buf + pos, bufsz - pos,
"\tantenna C: 0x%X\n",
tx->tx_power.ant_c);
} else
pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
}
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@ -1573,6 +1624,7 @@ DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
DEBUGFS_READ_FILE_OPS(ucode_general_stats);
DEBUGFS_READ_FILE_OPS(sensitivity);
DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(tx_power);
/*
* Create the debugfs files and directories
@ -1621,6 +1673,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(traffic_log, debug);
DEBUGFS_ADD_FILE(rx_queue, debug);
DEBUGFS_ADD_FILE(tx_queue, debug);
DEBUGFS_ADD_FILE(tx_power, debug);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
@ -1674,6 +1727,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats);

View file

@ -1170,7 +1170,7 @@ struct iwl_priv {
struct iwl_hw_params hw_params;
/* INT ICT Table */
u32 *ict_tbl;
__le32 *ict_tbl;
dma_addr_t ict_tbl_dma;
dma_addr_t aligned_ict_tbl_dma;
int ict_index;
@ -1215,7 +1215,7 @@ struct iwl_priv {
/* TX Power */
s8 tx_power_user_lmt;
s8 tx_power_channel_lmt;
s8 tx_power_device_lmt;
#ifdef CONFIG_IWLWIFI_DEBUG

View file

@ -135,6 +135,78 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
};
/**
* struct iwl_txpwr_section: eeprom section information
* @offset: indirect address into eeprom image
* @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section
* @band: band type for the section
* @is_common - true: common section, false: channel section
* @is_cck - true: cck section, false: not cck section
* @is_ht_40 - true: all channel in the section are HT40 channel,
* false: legacy or HT 20 MHz
* ignore if it is common section
* @iwl_eeprom_section_channel: channel array in the section,
* ignore if common section
*/
struct iwl_txpwr_section {
u32 offset;
u8 count;
enum ieee80211_band band;
bool is_common;
bool is_cck;
bool is_ht40;
u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS];
};
/**
* section 1 - 3 are regulatory tx power apply to all channels based on
* modulation: CCK, OFDM
* Band: 2.4GHz, 5.2GHz
* section 4 - 10 are regulatory tx power apply to specified channels
* For example:
* 1L - Channel 1 Legacy
* 1HT - Channel 1 HT
* (1,+1) - Channel 1 HT40 "_above_"
*
* Section 1: all CCK channels
* Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels
* Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
* Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT
* Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1)
* Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT
* Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1)
* Section 8: 2.4 GHz channel: 13L, 13HT
* Section 9: 2.4 GHz channel: 140L, 140HT
* Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1)
*
*/
static const struct iwl_txpwr_section enhinfo[] = {
{ EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false },
{ EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false },
{ EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false },
{ EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ,
false, false, false,
{1, 1, 2, 2, 10, 10, 11, 11 } },
{ EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ,
false, false, true,
{ 1, 2, 6, 7, 9 } },
{ EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ,
false, false, false,
{ 36, 64, 100, 36, 64, 100 } },
{ EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ,
false, false, true,
{ 36, 60, 100 } },
{ EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ,
false, false, false,
{ 13, 13 } },
{ EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ,
false, false, false,
{ 140, 140 } },
{ EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ,
false, false, true,
{ 132, 44 } },
};
/******************************************************************************
*
* EEPROM related functions
@ -643,6 +715,178 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
return 0;
}
/**
* iwl_get_max_txpower_avg - get the highest tx power from all chains.
* find the highest tx power from all chains for the channel
*/
static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
{
s8 max_txpower_avg = 0; /* (dBm) */
IWL_DEBUG_INFO(priv, "%d - "
"chain_a: %d dB chain_b: %d dB "
"chain_c: %d dB mimo2: %d dB mimo3: %d dB\n",
element,
enhanced_txpower[element].chain_a_max >> 1,
enhanced_txpower[element].chain_b_max >> 1,
enhanced_txpower[element].chain_c_max >> 1,
enhanced_txpower[element].mimo2_max >> 1,
enhanced_txpower[element].mimo3_max >> 1);
/* Take the highest tx power from any valid chains */
if ((priv->cfg->valid_tx_ant & ANT_A) &&
(enhanced_txpower[element].chain_a_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_a_max;
if ((priv->cfg->valid_tx_ant & ANT_B) &&
(enhanced_txpower[element].chain_b_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_b_max;
if ((priv->cfg->valid_tx_ant & ANT_C) &&
(enhanced_txpower[element].chain_c_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_c_max;
if (((priv->cfg->valid_tx_ant == ANT_AB) |
(priv->cfg->valid_tx_ant == ANT_BC) |
(priv->cfg->valid_tx_ant == ANT_AC)) &&
(enhanced_txpower[element].mimo2_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo2_max;
if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
(enhanced_txpower[element].mimo3_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo3_max;
/* max. tx power in EEPROM is in 1/2 dBm format
* convert from 1/2 dBm to dBm
*/
return max_txpower_avg >> 1;
}
/**
* iwl_update_common_txpower: update channel tx power
* update tx power per band based on EEPROM enhanced tx power info.
*/
static s8 iwl_update_common_txpower(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
int section, int element)
{
struct iwl_channel_info *ch_info;
int ch;
bool is_ht40 = false;
s8 max_txpower_avg; /* (dBm) */
/* it is common section, contain all type (Legacy, HT and HT40)
* based on the element in the section to determine
* is it HT 40 or not
*/
if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
is_ht40 = true;
max_txpower_avg =
iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
ch_info = priv->channel_info;
for (ch = 0; ch < priv->channel_count; ch++) {
/* find matching band and update tx power if needed */
if ((ch_info->band == enhinfo[section].band) &&
(ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
/* Update regulatory-based run-time data */
ch_info->max_power_avg = ch_info->curr_txpow =
max_txpower_avg;
ch_info->scan_power = max_txpower_avg;
}
if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
ch_info->ht40_max_power_avg &&
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
ch_info->ht40_curr_txpow = max_txpower_avg;
ch_info->ht40_scan_power = max_txpower_avg;
}
ch_info++;
}
return max_txpower_avg;
}
/**
* iwl_update_channel_txpower: update channel tx power
* update channel tx power based on EEPROM enhanced tx power info.
*/
static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
int section, int element)
{
struct iwl_channel_info *ch_info;
int ch;
u8 channel;
s8 max_txpower_avg; /* (dBm) */
channel = enhinfo[section].iwl_eeprom_section_channel[element];
max_txpower_avg =
iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
ch_info = priv->channel_info;
for (ch = 0; ch < priv->channel_count; ch++) {
/* find matching channel and update tx power if needed */
if (ch_info->channel == channel) {
if ((ch_info->max_power_avg < max_txpower_avg) &&
(!enhinfo[section].is_ht40)) {
/* Update regulatory-based run-time data */
ch_info->max_power_avg = max_txpower_avg;
ch_info->curr_txpow = max_txpower_avg;
ch_info->scan_power = max_txpower_avg;
}
if ((enhinfo[section].is_ht40) &&
(ch_info->ht40_max_power_avg) &&
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
/* Update regulatory-based run-time data */
ch_info->ht40_max_power_avg = max_txpower_avg;
ch_info->ht40_curr_txpow = max_txpower_avg;
ch_info->ht40_scan_power = max_txpower_avg;
}
break;
}
ch_info++;
}
return max_txpower_avg;
}
/**
* iwlcore_eeprom_enhanced_txpower: process enhanced tx power info
*/
void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
{
int eeprom_section_count = 0;
int section, element;
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
u32 offset;
s8 max_txpower_avg; /* (dBm) */
/* Loop through all the sections
* adjust bands and channel's max tx power
* Set the tx_power_user_lmt to the highest power
* supported by any channels and chains
*/
for (section = 0; section < ARRAY_SIZE(enhinfo); section++) {
eeprom_section_count = enhinfo[section].count;
offset = enhinfo[section].offset;
enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
iwl_eeprom_query_addr(priv, offset);
for (element = 0; element < eeprom_section_count; element++) {
if (enhinfo[section].is_common)
max_txpower_avg =
iwl_update_common_txpower(priv,
enhanced_txpower, section, element);
else
max_txpower_avg =
iwl_update_channel_txpower(priv,
enhanced_txpower, section, element);
/* Update the tx_power_user_lmt to the highest power
* supported by any channel */
if (max_txpower_avg > priv->tx_power_user_lmt)
priv->tx_power_user_lmt = max_txpower_avg;
}
}
}
EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower);
#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
? # x " " : "")
@ -790,6 +1034,14 @@ int iwl_init_channel_map(struct iwl_priv *priv)
}
}
/* for newer device (6000 series and up)
* EEPROM contain enhanced tx power information
* driver need to process addition information
* to determine the max channel tx power limits
*/
if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower)
priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv);
return 0;
}
EXPORT_SYMBOL(iwl_init_channel_map);

View file

@ -118,6 +118,30 @@ struct iwl_eeprom_channel {
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
} __attribute__ ((packed));
/**
* iwl_eeprom_enhanced_txpwr structure
* This structure presents the enhanced regulatory tx power limit layout
* in eeprom image
* Enhanced regulatory tx power portion of eeprom image can be broken down
* into individual structures; each one is 8 bytes in size and contain the
* following information
* @chain_a_max_pwr: chain a max power in 1/2 dBm
* @chain_b_max_pwr: chain b max power in 1/2 dBm
* @chain_c_max_pwr: chain c max power in 1/2 dBm
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
*
*/
struct iwl_eeprom_enhanced_txpwr {
u16 reserved;
s8 chain_a_max;
s8 chain_b_max;
s8 chain_c_max;
s8 reserved1;
s8 mimo2_max;
s8 mimo3_max;
} __attribute__ ((packed));
/* 3945 Specific */
#define EEPROM_3945_EEPROM_VERSION (0x2f)
@ -175,6 +199,59 @@ struct iwl_eeprom_channel {
#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
/* 6000 and up regulatory tx power - indirect access */
/* max. elements per section */
#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8)
#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2)
/**
* Partition the enhanced tx power portion of eeprom image into
* 10 sections based on band, modulation, frequency and channel
*
* Section 1: all CCK channels
* Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels
* Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels
* Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT
* Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_)
* Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT
* Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_)
* Section 8: 2.4 GHz channel 13, Both Legacy and HT
* Section 9: 2.4 GHz channel 140, Both Legacy and HT
* Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_)
*/
/* 2.4 GHz band: CCK */
#define EEPROM_LB_CCK_20_COMMON ((0xAA)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */
/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
#define EEPROM_LB_OFDM_COMMON ((0xB2)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
#define EEPROM_HB_OFDM_COMMON ((0xCA)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 2.4GHz band channels:
* 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */
#define EEPROM_LB_OFDM_20_BAND ((0xE2)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */
/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */
#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */
/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */
#define EEPROM_HB_OFDM_20_BAND ((0x14A)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */
/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */
#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 2.4 GHz band, channnel 13: Legacy, HT */
#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
/* 5.2 GHz band, channnel 140: Legacy, HT */
#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */
#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
/* 5050 Specific */
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
@ -389,6 +466,7 @@ struct iwl_eeprom_ops {
void (*release_semaphore) (struct iwl_priv *priv);
u16 (*calib_version) (struct iwl_priv *priv);
const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
void (*update_enhanced_txpower) (struct iwl_priv *priv);
};
@ -403,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv);
const struct iwl_channel_info *iwl_get_channel_info(

View file

@ -915,6 +915,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
u32 len;
u32 ampdu_status;
u16 fc;
u32 rate_n_flags;
/**
* REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
@ -1032,6 +1033,15 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
rx_status.flag |= RX_FLAG_SHORTPRE;
/* Set up the HT phy flags */
rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
if (rate_n_flags & RATE_MCS_HT_MSK)
rx_status.flag |= RX_FLAG_HT;
if (rate_n_flags & RATE_MCS_HT40_MSK)
rx_status.flag |= RX_FLAG_40MHZ;
if (rate_n_flags & RATE_MCS_SGI_MSK)
rx_status.flag |= RX_FLAG_SHORT_GI;
if (iwl_is_network_packet(priv, header)) {
priv->last_rx_rssi = rx_status.signal;
priv->last_beacon_time = priv->ucode_beacon_time;

View file

@ -796,7 +796,8 @@ void iwl_bg_abort_scan(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
if (!iwl_is_ready(priv))
if (!test_bit(STATUS_READY, &priv->status) ||
!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
return;
mutex_lock(&priv->mutex);

View file

@ -520,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
struct iwl_host_cmd cmd = {
.id = REPLY_WEPKEY,
.data = wep_cmd,
.flags = CMD_ASYNC,
.flags = CMD_SYNC,
};
memset(wep_cmd, 0, cmd_size +

View file

@ -718,10 +718,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
#endif
/* drop all data frame if we are not associated */
/* drop all non-injected data frame if we are not associated */
if (ieee80211_is_data(fc) &&
(!iwl_is_monitor_mode(priv) ||
!(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
!priv->assoc_station_added)) {
@ -732,7 +731,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
sta_id = iwl_get_sta_id(priv, hdr);
if (info->flags & IEEE80211_TX_CTL_INJECTED)
sta_id = priv->hw_params.bcast_sta_id;
else
sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);

View file

@ -518,9 +518,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
#endif
/* drop all data frame if we are not associated */
/* drop all non-injected data frame if we are not associated */
if (ieee80211_is_data(fc) &&
(!iwl_is_monitor_mode(priv)) && /* packet injection */
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
(!iwl_is_associated(priv) ||
((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
@ -532,7 +532,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
sta_id = iwl_get_sta_id(priv, hdr);
if (info->flags & IEEE80211_TX_CTL_INJECTED)
sta_id = priv->hw_params.bcast_sta_id;
else
sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);

View file

@ -34,7 +34,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*
* @param priv A pointer to struct lbs_private structure
* @param rates the buffer which keeps input and output
* @param rates_size the size of rate1 buffer; new size of buffer on return
* @param rates_size the size of rates buffer; new size of buffer on return,
* which will be less than or equal to original rates_size
*
* @return 0 on success, or -1 on error
*/
@ -42,48 +43,42 @@ static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
u8 *tmp;
size_t tmp_size = 0;
int i, j;
u8 intersection[MAX_RATES];
u16 intersection_size;
u16 num_rates = 0;
tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1),
GFP_KERNEL);
if (!tmp)
return -1;
intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
/* For each rate in card_rates that exists in rate1, copy to tmp */
for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
for (j = 0; rates[j] && (j < *rates_size); j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
/* Allow each rate from 'rates' that is supported by the hardware */
for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
for (j = 0; j < intersection_size && rates[j]; j++) {
if (rates[j] == lbs_bg_rates[i])
intersection[num_rates++] = rates[j];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
ARRAY_SIZE(lbs_bg_rates));
lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->enablehwauto) {
for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate)
for (i = 0; i < num_rates; i++) {
if (intersection[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
goto done;
return -1;
}
ret = 0;
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
memcpy(rates, tmp, *rates_size);
kfree(tmp);
return ret;
*rates_size = num_rates;
memcpy(rates, intersection, num_rates);
return 0;
}
@ -325,8 +320,8 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
memcpy(&rates->rates, &bss->rates, MAX_RATES);
tmplen = MAX_RATES;
tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
memcpy(&rates->rates, &bss->rates, tmplen);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@ -600,7 +595,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");

View file

@ -45,6 +45,8 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
ssize_t res;
if (!buf)
return -ENOMEM;
pos += snprintf(buf+pos, len-pos, "state = %s\n",
szStates[priv->connect_status]);
@ -68,6 +70,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
char *buf = (char *)addr;
DECLARE_SSID_BUF(ssid);
struct bss_descriptor * iter_bss;
if (!buf)
return -ENOMEM;
pos += snprintf(buf+pos, len-pos,
"# | ch | rssi | bssid | cap | Qual | SSID \n");
@ -110,6 +114,8 @@ static ssize_t lbs_sleepparams_write(struct file *file,
int p1, p2, p3, p4, p5, p6;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
@ -148,6 +154,8 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
struct sleep_params sp;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
@ -433,6 +441,8 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
offval.offset = priv->mac_offset;
offval.value = 0;
@ -457,6 +467,8 @@ static ssize_t lbs_rdmac_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -481,6 +493,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -515,6 +529,8 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
offval.offset = priv->bbp_offset;
offval.value = 0;
@ -540,6 +556,8 @@ static ssize_t lbs_rdbbp_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -564,6 +582,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -598,6 +618,8 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
offval.offset = priv->rf_offset;
offval.value = 0;
@ -623,6 +645,8 @@ static ssize_t lbs_rdrf_write(struct file *file,
ssize_t res, buf_size;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -647,6 +671,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
@ -853,6 +879,8 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
struct debug_data *d;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
p = buf;

View file

@ -59,6 +59,7 @@ struct if_cs_card {
struct pcmcia_device *p_dev;
struct lbs_private *priv;
void __iomem *iobase;
bool align_regs;
};
@ -274,16 +275,25 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
#define IF_CS_PRODUCT_ID 0x0000001C
#define IF_CS_CF8385_B1_REV 0x12
#define IF_CS_CF8381_B3_REV 0x04
#define IF_CS_CF8305_B1_REV 0x03
/*
* Used to detect other cards than CF8385 since their revisions of silicon
* doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
*/
#define CF8305_MANFID 0x02db
#define CF8305_CARDID 0x8103
#define CF8381_MANFID 0x02db
#define CF8381_CARDID 0x6064
#define CF8385_MANFID 0x02df
#define CF8385_CARDID 0x8103
static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
{
return (p_dev->manf_id == CF8305_MANFID &&
p_dev->card_id == CF8305_CARDID);
}
static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
{
return (p_dev->manf_id == CF8381_MANFID &&
@ -556,7 +566,15 @@ static int if_cs_prog_helper(struct if_cs_card *card)
lbs_deb_enter(LBS_DEB_CS);
scratch = if_cs_read8(card, IF_CS_SCRATCH);
/*
* This is the only place where an unaligned register access happens on
* the CF8305 card, therefore for the sake of speed of the driver, we do
* the alignment correction here.
*/
if (card->align_regs)
scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
else
scratch = if_cs_read8(card, IF_CS_SCRATCH);
/* "If the value is 0x5a, the firmware is already
* downloaded successfully"
@ -880,8 +898,24 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
/*
* Most of the libertas cards can do unaligned register access, but some
* weird ones can not. That's especially true for the CF8305 card.
*/
card->align_regs = 0;
/* Check if we have a current silicon */
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
if (if_cs_hw_is_cf8305(p_dev)) {
card->align_regs = 1;
if (prod_id < IF_CS_CF8305_B1_REV) {
lbs_pr_err("old chips like 8305 rev B3 "
"aren't supported\n");
ret = -ENODEV;
goto out2;
}
}
if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
ret = -ENODEV;
@ -896,7 +930,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/* Load the firmware early, before calling into libertas.ko */
ret = if_cs_prog_helper(card);
if (ret == 0)
if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
ret = if_cs_prog_real(card);
if (ret)
goto out2;
@ -976,6 +1010,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
/********************************************************************/
static struct pcmcia_device_id if_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
PCMCIA_DEVICE_NULL,

View file

@ -164,7 +164,7 @@ struct mwl8k_priv {
u16 num_mcaddrs;
u8 hw_rev;
__le32 fw_rev;
u32 fw_rev;
/*
* Running count of TX packets in flight, to avoid
@ -1439,8 +1439,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
return -ENOMEM;
rc = mwl8k_fw_lock(hw);
if (rc)
if (rc) {
pci_unmap_single(priv->pdev, dma_addr, dma_size,
PCI_DMA_BIDIRECTIONAL);
return rc;
}
priv->hostcmd_wait = &cmd_wait;
iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
@ -1471,7 +1474,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
printk(KERN_ERR "%s: Command %s error 0x%x\n",
priv->name,
mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
cmd->result);
le16_to_cpu(cmd->result));
}
return rc;
@ -2617,7 +2620,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
priv->capture_beacon = false;
rc = mwl8k_fw_lock(hw);
if (!rc)
if (rc)
return;
if (info->assoc) {
@ -2822,11 +2825,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
static int __devinit mwl8k_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
static int printed_version = 0;
struct ieee80211_hw *hw;
struct mwl8k_priv *priv;
int rc;
int i;
u8 *fw;
if (!printed_version) {
printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
printed_version = 1;
}
rc = pci_enable_device(pdev);
if (rc) {
@ -3001,13 +3009,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
goto err_stop_firmware;
}
fw = (u8 *)&priv->fw_rev;
printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num,
MWL8K_DESC);
printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
hw->wiphy->perm_addr);
printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n",
wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev,
hw->wiphy->perm_addr,
(priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
(priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
return 0;

View file

@ -623,6 +623,9 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
*flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
*queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
switch (priv->mode) {

View file

@ -50,7 +50,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv,
/* check for holes in the arrays caused by multi fragment frames
* searching for the last fragment of a frame */
if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
if (priv->pci_map_tx_address[index]) {
/* entry is the last fragment of a frame
* free the skb structure and unmap pci memory */
skb = priv->data_low_tx[index];
@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv)
pci_map_single(priv->pdev, (void *) skb->data,
MAX_FRAGMENT_SIZE_RX + 2,
PCI_DMA_FROMDEVICE);
if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) {
if (unlikely(!priv->pci_map_rx_address[index])) {
/* error mapping the buffer to device accessable memory address */
DEBUG(SHOW_ERROR_MESSAGES,
"Error mapping DMA address\n");

File diff suppressed because it is too large Load diff

View file

@ -582,7 +582,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
unsigned int delayed = 0;
int update_bssid = 0;
/*
@ -645,13 +644,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
*/
if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
spin_lock(&intf->lock);
if (delayed) {
intf->delayed_flags |= delayed;
schedule_work(&rt2x00dev->intf_work);
}
spin_unlock(&intf->lock);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);

View file

@ -1,5 +1,5 @@
rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o
rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o
obj-$(CONFIG_RTL8180) += rtl8180.o
obj-$(CONFIG_RTL8187) += rtl8187.o

View file

@ -133,6 +133,7 @@ struct rtl8187_priv {
__le16 bits16;
__le32 bits32;
} *io_dmabuf;
bool rfkill_off;
};
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);

View file

@ -32,6 +32,7 @@
#ifdef CONFIG_RTL8187_LEDS
#include "rtl8187_leds.h"
#endif
#include "rtl8187_rfkill.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@ -648,10 +649,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
/* setup card */
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 1);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@ -674,11 +675,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
/* host_usb_init */
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
@ -907,12 +908,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
u32 reg;
int ret;
mutex_lock(&priv->conf_mutex);
ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
rtl8187b_init_hw(dev);
if (ret)
return ret;
mutex_lock(&priv->conf_mutex);
goto rtl8187_start_exit;
init_usb_anchor(&priv->anchored);
priv->dev = dev;
@ -939,8 +940,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev);
rtl8187b_init_status_urb(dev);
mutex_unlock(&priv->conf_mutex);
return 0;
goto rtl8187_start_exit;
}
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
@ -984,9 +984,10 @@ static int rtl8187_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_RX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
INIT_DELAYED_WORK(&priv->work, rtl8187_work);
mutex_unlock(&priv->conf_mutex);
return 0;
rtl8187_start_exit:
mutex_unlock(&priv->conf_mutex);
return ret;
}
static void rtl8187_stop(struct ieee80211_hw *dev)
@ -1014,9 +1015,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
dev_kfree_skb_any(skb);
usb_kill_anchored_urbs(&priv->anchored);
mutex_unlock(&priv->conf_mutex);
if (!priv->is_rtl8187b)
cancel_delayed_work_sync(&priv->work);
mutex_unlock(&priv->conf_mutex);
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
@ -1276,7 +1278,8 @@ static const struct ieee80211_ops rtl8187_ops = {
.bss_info_changed = rtl8187_bss_info_changed,
.prepare_multicast = rtl8187_prepare_multicast,
.configure_filter = rtl8187_configure_filter,
.conf_tx = rtl8187_conf_tx
.conf_tx = rtl8187_conf_tx,
.rfkill_poll = rtl8187_rfkill_poll
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@ -1516,6 +1519,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
reg &= 0xFF;
rtl8187_leds_init(dev, reg);
#endif
rtl8187_rfkill_init(dev);
return 0;
@ -1539,6 +1543,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
#ifdef CONFIG_RTL8187_LEDS
rtl8187_leds_exit(dev);
#endif
rtl8187_rfkill_exit(dev);
ieee80211_unregister_hw(dev);
priv = dev->priv;

View file

@ -42,7 +42,7 @@ static void led_turn_on(struct work_struct *work)
mutex_lock(&priv->conf_mutex);
switch (led->ledpin) {
case LED_PIN_GPIO0:
rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
break;
case LED_PIN_LED0:
@ -80,7 +80,7 @@ static void led_turn_off(struct work_struct *work)
mutex_lock(&priv->conf_mutex);
switch (led->ledpin) {
case LED_PIN_GPIO0:
rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
break;
case LED_PIN_LED0:

View file

@ -0,0 +1,63 @@
/*
* Linux RFKILL support for RTL8187
*
* Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br>
*
* Based on the RFKILL handling in the r8187 driver, which is:
* Copyright (c) Realtek Semiconductor Corp. All rights reserved.
*
* Thanks to Realtek for their support!
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/usb.h>
#include <net/mac80211.h>
#include "rtl8187.h"
static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
{
u8 gpio;
gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02);
gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
return gpio & 0x02;
}
void rtl8187_rfkill_init(struct ieee80211_hw *hw)
{
struct rtl8187_priv *priv = hw->priv;
priv->rfkill_off = rtl8187_is_radio_enabled(priv);
printk(KERN_INFO "rtl8187: wireless switch is %s\n",
priv->rfkill_off ? "on" : "off");
wiphy_rfkill_set_hw_state(hw->wiphy, !priv->rfkill_off);
wiphy_rfkill_start_polling(hw->wiphy);
}
void rtl8187_rfkill_poll(struct ieee80211_hw *hw)
{
bool enabled;
struct rtl8187_priv *priv = hw->priv;
mutex_lock(&priv->conf_mutex);
enabled = rtl8187_is_radio_enabled(priv);
if (unlikely(enabled != priv->rfkill_off)) {
priv->rfkill_off = enabled;
printk(KERN_INFO "rtl8187: wireless radio switch turned %s\n",
enabled ? "on" : "off");
wiphy_rfkill_set_hw_state(hw->wiphy, !enabled);
}
mutex_unlock(&priv->conf_mutex);
}
void rtl8187_rfkill_exit(struct ieee80211_hw *hw)
{
wiphy_rfkill_stop_polling(hw->wiphy);
}

View file

@ -0,0 +1,8 @@
#ifndef RTL8187_RFKILL_H
#define RTL8187_RFKILL_H
void rtl8187_rfkill_init(struct ieee80211_hw *hw);
void rtl8187_rfkill_poll(struct ieee80211_hw *hw);
void rtl8187_rfkill_exit(struct ieee80211_hw *hw);
#endif /* RTL8187_RFKILL_H */

View file

@ -138,8 +138,9 @@ struct rtl818x_csr {
__le32 RF_PARA;
__le32 RF_TIMING;
u8 GP_ENABLE;
u8 GPIO;
u8 reserved_12[2];
u8 GPIO0;
u8 GPIO1;
u8 reserved_12;
__le32 HSSI_PARA;
u8 reserved_13[4];
u8 TX_AGC_CTL;

View file

@ -28,6 +28,21 @@ static void ssb_chipco_pll_write(struct ssb_chipcommon *cc,
chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
}
static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc,
u32 offset, u32 mask, u32 set)
{
u32 value;
chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset);
chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
value &= mask;
value |= set;
chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value);
chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
}
struct pmu0_plltab_entry {
u16 freq; /* Crystal frequency in kHz.*/
u8 xf; /* Crystal frequency value for PMU control */
@ -506,3 +521,82 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)
ssb_pmu_pll_init(cc);
ssb_pmu_resources_init(cc);
}
void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
enum ssb_pmu_ldo_volt_id id, u32 voltage)
{
struct ssb_bus *bus = cc->dev->bus;
u32 addr, shift, mask;
switch (bus->chip_id) {
case 0x4328:
case 0x5354:
switch (id) {
case LDO_VOLT1:
addr = 2;
shift = 25;
mask = 0xF;
break;
case LDO_VOLT2:
addr = 3;
shift = 1;
mask = 0xF;
break;
case LDO_VOLT3:
addr = 3;
shift = 9;
mask = 0xF;
break;
case LDO_PAREF:
addr = 3;
shift = 17;
mask = 0x3F;
break;
default:
SSB_WARN_ON(1);
return;
}
break;
case 0x4312:
if (SSB_WARN_ON(id != LDO_PAREF))
return;
addr = 0;
shift = 21;
mask = 0x3F;
break;
default:
return;
}
ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift),
(voltage & mask) << shift);
}
void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)
{
struct ssb_bus *bus = cc->dev->bus;
int ldo;
switch (bus->chip_id) {
case 0x4312:
ldo = SSB_PMURES_4312_PA_REF_LDO;
break;
case 0x4328:
ldo = SSB_PMURES_4328_PA_REF_LDO;
break;
case 0x5354:
ldo = SSB_PMURES_5354_PA_REF_LDO;
break;
default:
return;
}
if (on)
chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo);
else
chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo));
chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read?
}
EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);

View file

@ -115,7 +115,7 @@
#define IEEE80211_MAX_SSID_LEN 32
#define IEEE80211_MAX_MESH_ID_LEN 32
#define IEEE80211_MESH_CONFIG_LEN 19
#define IEEE80211_MESH_CONFIG_LEN 24
#define IEEE80211_QOS_CTL_LEN 2
#define IEEE80211_QOS_CTL_TID_MASK 0x000F

View file

@ -629,5 +629,15 @@ extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
/* PMU support */
extern void ssb_pmu_init(struct ssb_chipcommon *cc);
enum ssb_pmu_ldo_volt_id {
LDO_PAREF = 0,
LDO_VOLT1,
LDO_VOLT2,
LDO_VOLT3,
};
void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
enum ssb_pmu_ldo_volt_id id, u32 voltage);
void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on);
#endif /* LINUX_SSB_CHIPCO_H_ */

View file

@ -416,13 +416,13 @@ struct iw_spy_data
* data (i.e. valid as long as struct net_device exist, same locking rules).
*/
/* Forward declaration */
struct ieee80211_device;
struct libipw_device;
/* The struct */
struct iw_public_data {
/* Driver enhanced spy support */
struct iw_spy_data * spy_data;
/* Structure managed by the in-kernel IEEE 802.11 layer */
struct ieee80211_device * ieee80211;
/* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */
struct libipw_device * libipw;
};
/**************************** PROTOTYPES ****************************/

View file

@ -1657,12 +1657,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
*/
void ieee80211_restart_hw(struct ieee80211_hw *hw);
/*
* trick to avoid symbol clashes with the ieee80211 subsystem,
* use the inline below instead
*/
void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
* ieee80211_rx - receive frame
*
@ -1678,10 +1672,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
*/
static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
__ieee80211_rx(hw, skb);
}
void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
* ieee80211_rx_irqsafe - receive frame

View file

@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
static inline int drv_start(struct ieee80211_local *local)
{
int ret = local->ops->start(&local->hw);
int ret;
local->started = true;
smp_mb();
ret = local->ops->start(&local->hw);
trace_drv_start(local, ret);
return ret;
}
@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local)
{
local->ops->stop(&local->hw);
trace_drv_stop(local);
/* sync away all work on the tasklet before clearing started */
tasklet_disable(&local->tasklet);
tasklet_enable(&local->tasklet);
barrier();
local->started = false;
}
static inline int drv_add_interface(struct ieee80211_local *local,

View file

@ -367,6 +367,10 @@ struct ieee80211_if_mesh {
u8 mesh_pm_id[4];
/* Congestion Control Mode Identifier */
u8 mesh_cc_id[4];
/* Synchronization Protocol Identifier */
u8 mesh_sp_id[4];
/* Authentication Protocol Identifier */
u8 mesh_auth_id[4];
/* Local mesh Destination Sequence Number */
u32 dsn;
/* Last used PREQ ID */
@ -663,6 +667,9 @@ struct ieee80211_local {
*/
bool quiescing;
/* device is started */
bool started;
int tx_headroom; /* required headroom for hardware/radiotap */
/* Tasklet and skb queue to process calls from IRQ mode. All frames
@ -1082,6 +1089,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
/* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local);
void ieee80211_stop_device(struct ieee80211_local *local);
#ifdef CONFIG_PM
int __ieee80211_suspend(struct ieee80211_hw *hw);

View file

@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev)
}
}
if (local->open_count == 0) {
tasklet_enable(&local->tx_pending_tasklet);
tasklet_enable(&local->tasklet);
}
/*
* set_multicast_list will be invoked by the networking core
* which will check whether any increments here were done in
@ -502,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev)
}
/* fall through */
default:
if (local->scan_sdata == sdata) {
if (!local->ops->hw_scan)
cancel_delayed_work_sync(&local->scan_work);
/*
* The software scan can no longer run now, so we can
* clear out the scan_sdata reference. However, the
* hardware scan may still be running. The complete
* function must be prepared to handle a NULL value.
*/
local->scan_sdata = NULL;
/*
* The memory barrier guarantees that another CPU
* that is hardware-scanning will now see the fact
* that this interface is gone.
*/
smp_mb();
/*
* If software scanning, complete the scan but since
* the scan_sdata is NULL already don't send out a
* scan event to userspace -- the scan is incomplete.
*/
if (test_bit(SCAN_SW_SCANNING, &local->scanning))
ieee80211_scan_completed(&local->hw, true);
}
if (local->scan_sdata == sdata)
ieee80211_scan_cancel(local);
/*
* Disable beaconing for AP and mesh, IBSS can't
@ -552,14 +525,8 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
drv_stop(local);
ieee80211_led_radio(local, false);
flush_workqueue(local->workqueue);
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
ieee80211_clear_tx_pending(local);
ieee80211_stop_device(local);
/* no reconfiguring after stop! */
hw_reconf_flags = 0;

View file

@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->pending[i]);
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
tasklet_disable(&local->tx_pending_tasklet);
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);
tasklet_disable(&local->tasklet);
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);

View file

@ -18,8 +18,11 @@
#define PP_OFFSET 1 /* Path Selection Protocol */
#define PM_OFFSET 5 /* Path Selection Metric */
#define CC_OFFSET 9 /* Congestion Control Mode */
#define CAPAB_OFFSET 17
#define ACCEPT_PLINKS 0x80
#define SP_OFFSET 13 /* Synchronization Protocol */
#define AUTH_OFFSET 17 /* Authentication Protocol */
#define CAPAB_OFFSET 22
#define CAPAB_ACCEPT_PLINKS 0x80
#define CAPAB_FORWARDING 0x10
#define TMR_RUNNING_HK 0
#define TMR_RUNNING_MP 1
@ -84,7 +87,9 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 &&
memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 &&
memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0)
return true;
return false;
@ -97,7 +102,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
*/
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
{
return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0;
}
/**
@ -123,11 +128,18 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
void mesh_ids_set_default(struct ieee80211_if_mesh *sta)
{
u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
u8 oui[3] = {0x00, 0x0F, 0xAC};
memcpy(sta->mesh_pp_id, def_id, 4);
memcpy(sta->mesh_pm_id, def_id, 4);
memcpy(sta->mesh_cc_id, def_id, 4);
memcpy(sta->mesh_pp_id, oui, sizeof(oui));
memcpy(sta->mesh_pm_id, oui, sizeof(oui));
memcpy(sta->mesh_cc_id, oui, sizeof(oui));
memcpy(sta->mesh_sp_id, oui, sizeof(oui));
memcpy(sta->mesh_auth_id, oui, sizeof(oui));
sta->mesh_pp_id[sizeof(oui)] = 0;
sta->mesh_pm_id[sizeof(oui)] = 0;
sta->mesh_cc_id[sizeof(oui)] = 0xff;
sta->mesh_sp_id[sizeof(oui)] = 0xff;
sta->mesh_auth_id[sizeof(oui)] = 0x0;
}
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@ -245,7 +257,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
if (sdata->u.mesh.mesh_id_len)
memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
pos = skb_put(skb, 21);
pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
*pos++ = WLAN_EID_MESH_CONFIG;
*pos++ = IEEE80211_MESH_CONFIG_LEN;
/* Version */
@ -263,15 +275,22 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
memcpy(pos, sdata->u.mesh.mesh_cc_id, 4);
pos += 4;
/* Channel precedence:
* Not running simple channel unification protocol
*/
memset(pos, 0x00, 4);
/* Synchronization protocol identifier */
memcpy(pos, sdata->u.mesh.mesh_sp_id, 4);
pos += 4;
/* Authentication Protocol identifier */
memcpy(pos, sdata->u.mesh.mesh_auth_id, 4);
pos += 4;
/* Mesh Formation Info */
memset(pos, 0x00, 1);
pos += 1;
/* Mesh capability */
sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
*pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00;
*pos = CAPAB_FORWARDING;
*pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
return;

View file

@ -2123,25 +2123,9 @@ static void ieee80211_sta_work(struct work_struct *work)
}
}
list_for_each_entry(wk, &ifmgd->work_list, list) {
if (wk->state != IEEE80211_MGD_STATE_IDLE) {
anybusy = true;
break;
}
}
ieee80211_recalc_idle(local);
if (!anybusy) {
mutex_unlock(&ifmgd->mtx);
if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
ieee80211_queue_delayed_work(&local->hw,
&local->scan_work,
round_jiffies_relative(0));
return;
}
list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
if (time_is_after_jiffies(wk->timeout)) {
/*
@ -2187,6 +2171,18 @@ static void ieee80211_sta_work(struct work_struct *work)
}
}
list_for_each_entry(wk, &ifmgd->work_list, list) {
if (wk->state != IEEE80211_MGD_STATE_IDLE) {
anybusy = true;
break;
}
}
if (!anybusy &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
ieee80211_queue_delayed_work(&local->hw,
&local->scan_work,
round_jiffies_relative(0));
mutex_unlock(&ifmgd->mtx);
list_for_each_entry_safe(wk, tmp, &free_work, list) {

View file

@ -107,17 +107,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
}
/* stop hardware - this must stop RX */
if (local->open_count) {
ieee80211_led_radio(local, false);
drv_stop(local);
}
/*
* flush again, in case driver queued work -- it
* shouldn't be doing (or cancel everything in the
* stop callback) that but better safe than sorry.
*/
flush_workqueue(local->workqueue);
if (local->open_count)
ieee80211_stop_device(local);
local->suspended = true;
/* need suspended to be visible before quiescing is false */

View file

@ -33,7 +33,6 @@ struct minstrel_rate {
/* per-rate throughput */
u32 cur_tp;
u32 throughput;
u64 succ_hist;
u64 att_hist;

View file

@ -83,7 +83,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
p += sprintf(p, "%3u%s", mr->bitrate / 2,
(mr->bitrate & 1 ? ".5" : " "));
tp = ((mr->cur_tp * 96) / 18000) >> 10;
tp = mr->cur_tp / ((18000 << 10) / 96);
prob = mr->cur_prob / 18;
eprob = mr->probability / 18;

View file

@ -2440,24 +2440,20 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
* This is the receive path handler. It is called by a low level driver when an
* 802.11 MPDU is received from the hardware.
*/
void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
if (status->band < 0 ||
status->band >= IEEE80211_NUM_BANDS) {
WARN_ON(1);
return;
}
if (WARN_ON(status->band < 0 ||
status->band >= IEEE80211_NUM_BANDS))
goto drop;
sband = local->hw.wiphy->bands[status->band];
if (!sband) {
WARN_ON(1);
return;
}
if (WARN_ON(!sband))
goto drop;
/*
* If we're suspending, it is possible although not too likely
@ -2466,16 +2462,21 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
* that might, for example, cause stations to be added or other
* driver callbacks be invoked.
*/
if (unlikely(local->quiescing || local->suspended)) {
kfree_skb(skb);
return;
}
if (unlikely(local->quiescing || local->suspended))
goto drop;
/*
* The same happens when we're not even started,
* but that's worth a warning.
*/
if (WARN_ON(!local->started))
goto drop;
if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= 76))
return;
goto drop;
/* HT rates are not in the table - use the highest legacy rate
* for now since other parts of mac80211 may not yet be fully
* MCS aware. */
@ -2483,7 +2484,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
} else {
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= sband->n_bitrates))
return;
goto drop;
rate = &sband->bitrates[status->rate_idx];
}
@ -2522,8 +2523,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
__ieee80211_rx_handle_packet(hw, skb, rate);
rcu_read_unlock();
return;
drop:
kfree_skb(skb);
}
EXPORT_SYMBOL(__ieee80211_rx);
EXPORT_SYMBOL(ieee80211_rx);
/* This is a version of the rx handler that can be called from hard irq
* context. Post the skb on the queue and schedule the tasklet */

View file

@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (local->scan_req != local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL;
local->scan_sdata = NULL;
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
local->scanning = 0;
@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work)
int rc;
local->scan_req = NULL;
local->scan_sdata = NULL;
rc = __ieee80211_start_scan(sdata, req);
mutex_unlock(&local->scan_mtx);
@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
bool swscan;
bool abortscan;
cancel_delayed_work_sync(&local->scan_work);
@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* queued -- mostly at suspend under RTNL.
*/
mutex_lock(&local->scan_mtx);
swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
(!local->scanning && local->scan_req);
mutex_unlock(&local->scan_mtx);
if (swscan)
if (abortscan)
ieee80211_scan_completed(&local->hw, true);
}

View file

@ -1007,6 +1007,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
return supp_rates;
}
void ieee80211_stop_device(struct ieee80211_local *local)
{
ieee80211_led_radio(local, false);
cancel_work_sync(&local->reconfig_filter);
drv_stop(local);
flush_workqueue(local->workqueue);
}
int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;

View file

@ -17,6 +17,23 @@ config NL80211_TESTMODE
Say N.
config CFG80211_DEVELOPER_WARNINGS
bool "enable developer warnings"
depends on CFG80211
default n
help
This option enables some additional warnings that help
cfg80211 developers and driver developers, but that can
trigger due to races with userspace.
For example, when a driver reports that it was disconnected
from the AP, but the user disconnects manually at the same
time, the warning might trigger spuriously due to races.
Say Y only if you are developing cfg80211 or a driver based
on it (or mac80211).
config CFG80211_REG_DEBUG
bool "cfg80211 regulatory debugging"
depends on CFG80211

View file

@ -294,69 +294,17 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work)
cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
}
static void cfg80211_process_events(struct wireless_dev *wdev)
{
struct cfg80211_event *ev;
unsigned long flags;
spin_lock_irqsave(&wdev->event_lock, flags);
while (!list_empty(&wdev->event_list)) {
ev = list_first_entry(&wdev->event_list,
struct cfg80211_event, list);
list_del(&ev->list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
wdev_lock(wdev);
switch (ev->type) {
case EVENT_CONNECT_RESULT:
__cfg80211_connect_result(
wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ?
NULL : ev->cr.bssid,
ev->cr.req_ie, ev->cr.req_ie_len,
ev->cr.resp_ie, ev->cr.resp_ie_len,
ev->cr.status,
ev->cr.status == WLAN_STATUS_SUCCESS,
NULL);
break;
case EVENT_ROAMED:
__cfg80211_roamed(wdev, ev->rm.bssid,
ev->rm.req_ie, ev->rm.req_ie_len,
ev->rm.resp_ie, ev->rm.resp_ie_len);
break;
case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev,
ev->dc.ie, ev->dc.ie_len,
ev->dc.reason, true);
break;
case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
break;
}
wdev_unlock(wdev);
kfree(ev);
spin_lock_irqsave(&wdev->event_lock, flags);
}
spin_unlock_irqrestore(&wdev->event_lock, flags);
}
static void cfg80211_event_work(struct work_struct *work)
{
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
rdev = container_of(work, struct cfg80211_registered_device,
event_work);
rtnl_lock();
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list)
cfg80211_process_events(wdev);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_process_rdev_events(rdev);
cfg80211_unlock_rdev(rdev);
rtnl_unlock();
}
@ -664,7 +612,7 @@ static void wdev_cleanup_work(struct work_struct *work)
if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev);
___cfg80211_scan_done(rdev, true);
}
cfg80211_unlock_rdev(rdev);
@ -755,6 +703,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
default:
break;
}
break;
case NETDEV_DOWN:
dev_hold(dev);
schedule_work(&wdev->cleanup_work);
break;

View file

@ -370,8 +370,12 @@ void cfg80211_sme_scan_done(struct net_device *dev);
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
void cfg80211_sme_disassoc(struct net_device *dev, int idx);
void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype,
u32 *flags, struct vif_params *params);
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
struct ieee80211_channel *
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
@ -380,4 +384,15 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev,
int freq, enum nl80211_channel_type channel_type);
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
#else
/*
* Trick to enable using it as a condition,
* and also not give a warning when it's
* not used that way.
*/
#define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; })
#endif
#endif /* __NET_WIRELESS_CORE_H */

View file

@ -22,7 +22,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
return;
if (WARN_ON(!wdev->ssid_len))
if (!wdev->ssid_len)
return;
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
@ -58,6 +58,8 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
struct cfg80211_event *ev;
unsigned long flags;
CFG80211_DEV_WARN_ON(!wdev->ssid_len);
ev = kzalloc(sizeof(*ev), gfp);
if (!ev)
return;

View file

@ -977,12 +977,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
}
if (!rdev->ops->change_virtual_intf ||
!(rdev->wiphy.interface_modes & (1 << ntype))) {
err = -EOPNOTSUPP;
goto unlock;
}
if (info->attrs[NL80211_ATTR_MESH_ID]) {
if (ntype != NL80211_IFTYPE_MESH_POINT) {
err = -EINVAL;
@ -1008,18 +1002,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
if (change)
err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
ntype, flags, &params);
err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
else
err = 0;
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
if (!err && (ntype != otype)) {
if (otype == NL80211_IFTYPE_ADHOC)
cfg80211_clear_ibss(dev, false);
}
unlock:
dev_put(dev);
cfg80211_unlock_rdev(rdev);
@ -2195,7 +2181,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
err = -EOPNOTSUPP;
goto out;
goto out_err;
}
while (1) {

View file

@ -18,7 +18,7 @@
#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
struct net_device *dev;
@ -26,8 +26,13 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
union iwreq_data wrqu;
#endif
ASSERT_RDEV_LOCK(rdev);
request = rdev->scan_req;
if (!request)
return;
dev = request->dev;
/*
@ -53,7 +58,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
dev_put(dev);
rdev->scan_req = NULL;
kfree(request);
/*
* OK. If this is invoked with "leak" then we can't
* free this ... but we've cleaned it up anyway. The
* driver failed to call the scan_done callback, so
* all bets are off, it might still be trying to use
* the scan request or not ... if it accesses the dev
* in there (it shouldn't anyway) then it may crash.
*/
if (!leak)
kfree(request);
}
void __cfg80211_scan_done(struct work_struct *wk)
@ -64,7 +79,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
scan_done_wk);
cfg80211_lock_rdev(rdev);
___cfg80211_scan_done(rdev);
___cfg80211_scan_done(rdev, false);
cfg80211_unlock_rdev(rdev);
}

View file

@ -351,7 +351,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return;
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING))
if (wdev->sme_state != CFG80211_SME_CONNECTING)
return;
nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
@ -445,6 +445,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
struct cfg80211_event *ev;
unsigned long flags;
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
if (!ev)
return;
@ -481,7 +483,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return;
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return;
/* internal error -- how did we get to CONNECTED w/o BSS? */
@ -540,6 +542,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
struct cfg80211_event *ev;
unsigned long flags;
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
if (!ev)
return;
@ -575,7 +579,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return;
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
if (wdev->sme_state != CFG80211_SME_CONNECTED)
return;
if (wdev->current_bss) {
@ -639,6 +643,8 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
struct cfg80211_event *ev;
unsigned long flags;
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
ev = kzalloc(sizeof(*ev) + ie_len, gfp);
if (!ev)
return;

View file

@ -574,3 +574,111 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;
}
static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
{
struct cfg80211_event *ev;
unsigned long flags;
const u8 *bssid = NULL;
spin_lock_irqsave(&wdev->event_lock, flags);
while (!list_empty(&wdev->event_list)) {
ev = list_first_entry(&wdev->event_list,
struct cfg80211_event, list);
list_del(&ev->list);
spin_unlock_irqrestore(&wdev->event_lock, flags);
wdev_lock(wdev);
switch (ev->type) {
case EVENT_CONNECT_RESULT:
if (!is_zero_ether_addr(ev->cr.bssid))
bssid = ev->cr.bssid;
__cfg80211_connect_result(
wdev->netdev, bssid,
ev->cr.req_ie, ev->cr.req_ie_len,
ev->cr.resp_ie, ev->cr.resp_ie_len,
ev->cr.status,
ev->cr.status == WLAN_STATUS_SUCCESS,
NULL);
break;
case EVENT_ROAMED:
__cfg80211_roamed(wdev, ev->rm.bssid,
ev->rm.req_ie, ev->rm.req_ie_len,
ev->rm.resp_ie, ev->rm.resp_ie_len);
break;
case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev,
ev->dc.ie, ev->dc.ie_len,
ev->dc.reason, true);
break;
case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
break;
}
wdev_unlock(wdev);
kfree(ev);
spin_lock_irqsave(&wdev->event_lock, flags);
}
spin_unlock_irqrestore(&wdev->event_lock, flags);
}
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
{
struct wireless_dev *wdev;
ASSERT_RTNL();
ASSERT_RDEV_LOCK(rdev);
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list)
cfg80211_process_wdev_events(wdev);
mutex_unlock(&rdev->devlist_mtx);
}
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype,
u32 *flags, struct vif_params *params)
{
int err;
enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
ASSERT_RDEV_LOCK(rdev);
/* don't support changing VLANs, you just re-create them */
if (otype == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
if (!rdev->ops->change_virtual_intf ||
!(rdev->wiphy.interface_modes & (1 << ntype)))
return -EOPNOTSUPP;
if (ntype != otype) {
switch (otype) {
case NL80211_IFTYPE_ADHOC:
cfg80211_leave_ibss(rdev, dev, false);
break;
case NL80211_IFTYPE_STATION:
cfg80211_disconnect(rdev, dev,
WLAN_REASON_DEAUTH_LEAVING, true);
break;
case NL80211_IFTYPE_MESH_POINT:
/* mesh should be handled? */
break;
default:
break;
}
cfg80211_process_rdev_events(rdev);
}
err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
ntype, flags, params);
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
return err;
}

View file

@ -70,18 +70,8 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
enum nl80211_iftype type;
int ret;
if (!wdev)
return -EOPNOTSUPP;
rdev = wiphy_to_dev(wdev->wiphy);
if (!rdev->ops->change_virtual_intf)
return -EOPNOTSUPP;
/* don't support changing VLANs, you just re-create them */
if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
switch (*mode) {
case IW_MODE_INFRA:
type = NL80211_IFTYPE_STATION;
@ -104,9 +94,9 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
memset(&vifparams, 0, sizeof(vifparams));
ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
NULL, &vifparams);
WARN_ON(!ret && wdev->iftype != type);
cfg80211_lock_rdev(rdev);
ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
cfg80211_unlock_rdev(rdev);
return ret;
}