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-10-29 02:47:13 -07:00
commit ed3f2e40f3
137 changed files with 13466 additions and 6000 deletions

View File

@ -1086,7 +1086,6 @@ F: include/net/ax25.h
F: net/ax25/ F: net/ax25/
B43 WIRELESS DRIVER B43 WIRELESS DRIVER
M: Michael Buesch <mb@bu3sch.de>
M: Stefano Brivio <stefano.brivio@polimi.it> M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/users/Drivers/b43 W: http://linuxwireless.org/en/users/Drivers/b43

View File

@ -5660,7 +5660,8 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
pci_save_state(pdev); pci_save_state(pdev);
return pci_set_power_state(pdev, pci_choose_state(pdev, state)); pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
} }
static int airo_pci_resume(struct pci_dev *pdev) static int airo_pci_resume(struct pci_dev *pdev)

View File

@ -231,7 +231,7 @@ struct ar9170 {
struct sk_buff_head tx_status_ampdu; struct sk_buff_head tx_status_ampdu;
spinlock_t tx_ampdu_list_lock; spinlock_t tx_ampdu_list_lock;
struct list_head tx_ampdu_list; struct list_head tx_ampdu_list;
unsigned int tx_ampdu_pending; atomic_t tx_ampdu_pending;
/* rxstream mpdu merge */ /* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu; struct ar9170_rxstream_mpdu_merge rx_mpdu;

View File

@ -152,14 +152,14 @@ enum ar9170_cmd {
#define AR9170_MAC_REG_FTF_BIT14 BIT(14) #define AR9170_MAC_REG_FTF_BIT14 BIT(14)
#define AR9170_MAC_REG_FTF_BIT15 BIT(15) #define AR9170_MAC_REG_FTF_BIT15 BIT(15)
#define AR9170_MAC_REG_FTF_BAR BIT(24) #define AR9170_MAC_REG_FTF_BAR BIT(24)
#define AR9170_MAC_REG_FTF_BIT25 BIT(25) #define AR9170_MAC_REG_FTF_BA BIT(25)
#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) #define AR9170_MAC_REG_FTF_PSPOLL BIT(26)
#define AR9170_MAC_REG_FTF_RTS BIT(27) #define AR9170_MAC_REG_FTF_RTS BIT(27)
#define AR9170_MAC_REG_FTF_CTS BIT(28) #define AR9170_MAC_REG_FTF_CTS BIT(28)
#define AR9170_MAC_REG_FTF_ACK BIT(29) #define AR9170_MAC_REG_FTF_ACK BIT(29)
#define AR9170_MAC_REG_FTF_CFE BIT(30) #define AR9170_MAC_REG_FTF_CFE BIT(30)
#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) #define AR9170_MAC_REG_FTF_CFE_ACK BIT(31)
#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff #define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff
#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff #define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff
#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) #define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0)

View File

@ -414,9 +414,9 @@ static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
skb_queue_tail(&ar->tx_status_ampdu, skb); skb_queue_tail(&ar->tx_status_ampdu, skb);
ar9170_tx_fake_ampdu_status(ar); ar9170_tx_fake_ampdu_status(ar);
ar->tx_ampdu_pending--;
if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending) if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
!list_empty(&ar->tx_ampdu_list))
ar9170_tx_ampdu(ar); ar9170_tx_ampdu(ar);
} }
@ -1248,6 +1248,7 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
ar->global_ampdu_density = 6; ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3; ar->global_ampdu_factor = 3;
atomic_set(&ar->tx_ampdu_pending, 0);
ar->bad_hw_nagger = jiffies; ar->bad_hw_nagger = jiffies;
err = ar->open(ar); err = ar->open(ar);
@ -1773,7 +1774,7 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_TX_TIMEOUT); msecs_to_jiffies(AR9170_TX_TIMEOUT);
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
ar->tx_ampdu_pending++; atomic_inc(&ar->tx_ampdu_pending);
#ifdef AR9170_QUEUE_DEBUG #ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n", printk(KERN_DEBUG "%s: send frame q:%d =>\n",
@ -1784,7 +1785,7 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb); err = ar->tx(ar, skb);
if (unlikely(err)) { if (unlikely(err)) {
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
ar->tx_ampdu_pending--; atomic_dec(&ar->tx_ampdu_pending);
frames_failed++; frames_failed++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
@ -1931,7 +1932,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_AMPDU) { if (info->flags & IEEE80211_TX_CTL_AMPDU) {
bool run = ar9170_tx_ampdu_queue(ar, skb); bool run = ar9170_tx_ampdu_queue(ar, skb);
if (run || !ar->tx_ampdu_pending) if (run || !atomic_read(&ar->tx_ampdu_pending))
ar9170_tx_ampdu(ar); ar9170_tx_ampdu(ar);
} else { } else {
unsigned int queue = skb_get_queue_mapping(skb); unsigned int queue = skb_get_queue_mapping(skb);

View File

@ -108,15 +108,15 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
return ; return ;
spin_lock_irqsave(&aru->tx_urb_lock, flags); spin_lock_irqsave(&aru->tx_urb_lock, flags);
if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
spin_unlock_irqrestore(&aru->tx_urb_lock, flags); spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ; return ;
} }
aru->tx_submitted_urbs++; atomic_inc(&aru->tx_submitted_urbs);
urb = usb_get_from_anchor(&aru->tx_pending); urb = usb_get_from_anchor(&aru->tx_pending);
if (!urb) { if (!urb) {
aru->tx_submitted_urbs--; atomic_dec(&aru->tx_submitted_urbs);
spin_unlock_irqrestore(&aru->tx_urb_lock, flags); spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ; return ;
@ -133,7 +133,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
err); err);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
aru->tx_submitted_urbs--; atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, urb->context); ar9170_tx_callback(&aru->common, urb->context);
} }
@ -151,7 +151,7 @@ static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
return ; return ;
} }
aru->tx_submitted_urbs--; atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, skb); ar9170_tx_callback(&aru->common, skb);
@ -794,7 +794,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
spin_lock_init(&aru->tx_urb_lock); spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0; aru->tx_pending_urbs = 0;
aru->tx_submitted_urbs = 0; atomic_set(&aru->tx_submitted_urbs, 0);
aru->common.stop = ar9170_usb_stop; aru->common.stop = ar9170_usb_stop;
aru->common.flush = ar9170_usb_flush; aru->common.flush = ar9170_usb_flush;

View File

@ -67,7 +67,7 @@ struct ar9170_usb {
bool req_one_stage_fw; bool req_one_stage_fw;
spinlock_t tx_urb_lock; spinlock_t tx_urb_lock;
unsigned int tx_submitted_urbs; atomic_t tx_submitted_urbs;
unsigned int tx_pending_urbs; unsigned int tx_pending_urbs;
struct completion cmd_wait; struct completion cmd_wait;

View File

@ -198,6 +198,7 @@
#define AR5K_TUNE_CWMAX_11B 1023 #define AR5K_TUNE_CWMAX_11B 1023
#define AR5K_TUNE_CWMAX_XR 7 #define AR5K_TUNE_CWMAX_XR 7
#define AR5K_TUNE_NOISE_FLOOR -72 #define AR5K_TUNE_NOISE_FLOOR -72
#define AR5K_TUNE_CCA_MAX_GOOD_VALUE -95
#define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_MAX_TXPOWER 63
#define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_DEFAULT_TXPOWER 25
#define AR5K_TUNE_TPC_TXPOWER false #define AR5K_TUNE_TPC_TXPOWER false
@ -1006,6 +1007,14 @@ struct ath5k_capabilities {
} cap_queues; } cap_queues;
}; };
/* size of noise floor history (keep it a power of two) */
#define ATH5K_NF_CAL_HIST_MAX 8
struct ath5k_nfcal_hist
{
s16 index; /* current index into nfval */
s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
};
/***************************************\ /***************************************\
HARDWARE ABSTRACTION LAYER STRUCTURE HARDWARE ABSTRACTION LAYER STRUCTURE
@ -1112,6 +1121,8 @@ struct ath5k_hw {
struct ieee80211_channel r_last_channel; struct ieee80211_channel r_last_channel;
} ah_radar; } ah_radar;
struct ath5k_nfcal_hist ah_nfcal_hist;
/* noise floor from last periodic calibration */ /* noise floor from last periodic calibration */
s32 ah_noise_floor; s32 ah_noise_floor;
@ -1274,8 +1285,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
/* PHY calibration */ /* PHY calibration */
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
/* Spur mitigation */ /* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,

View File

@ -331,6 +331,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
ath5k_hw_rfgain_opt_init(ah); ath5k_hw_rfgain_opt_init(ah);
ath5k_hw_init_nfcal_hist(ah);
/* turn on HW LEDs */ /* turn on HW LEDs */
ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);

View File

@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
} }
} }
/** static int sign_extend(int val, const int nbits)
* ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
*
* @ah: struct ath5k_hw pointer we are operating on
* @freq: the channel frequency, just used for error logging
*
* This function performs a noise floor calibration of the PHY and waits for
* it to complete. Then the noise floor value is compared to some maximum
* noise floor we consider valid.
*
* Note that this is different from what the madwifi HAL does: it reads the
* noise floor and afterwards initiates the calibration. Since the noise floor
* calibration can take some time to finish, depending on the current channel
* use, that avoids the occasional timeout warnings we are seeing now.
*
* See the following link for an Atheros patent on noise floor calibration:
* http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
* &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
*
* XXX: Since during noise floor calibration antennas are detached according to
* the patent, we should stop tx queues here.
*/
int
ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
{ {
int ret; int order = BIT(nbits-1);
unsigned int i; return (val ^ order) - order;
s32 noise_floor; }
/* static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
* Enable noise floor calibration {
*/ s32 val;
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_NF);
ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
AR5K_PHY_AGCCTL_NF, 0, false); return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
if (ret) { }
ATH5K_ERR(ah->ah_sc,
"noise floor calibration timeout (%uMHz)\n", freq);
return -EAGAIN;
}
/* Wait until the noise floor is calibrated and read the value */ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
for (i = 20; i > 0; i--) { {
mdelay(1); int i;
noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
if (noise_floor & AR5K_PHY_NF_ACTIVE) {
noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) ah->ah_nfcal_hist.index = 0;
break; for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
}
static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
{
struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
hist->nfval[hist->index] = noise_floor;
}
static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
{
s16 sort[ATH5K_NF_CAL_HIST_MAX];
s16 tmp;
int i, j;
memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
if (sort[j] > sort[j-1]) {
tmp = sort[j];
sort[j] = sort[j-1];
sort[j-1] = tmp;
}
} }
} }
for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
"cal %d:%d\n", i, sort[i]);
}
return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
}
ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, /*
"noise floor %d\n", noise_floor); * When we tell the hardware to perform a noise floor calibration
* by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
* sample-and-hold the minimum noise level seen at the antennas.
* This value is then stored in a ring buffer of recently measured
* noise floor values so we have a moving window of the last few
* samples.
*
* The median of the values in the history is then loaded into the
* hardware for its own use for RSSI and CCA measurements.
*/
void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u32 val;
s16 nf, threshold;
u8 ee_mode;
if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { /* keep last value if calibration hasn't completed */
ATH5K_ERR(ah->ah_sc, if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
"noise floor calibration failed (%uMHz)\n", freq); ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
return -EAGAIN; "NF did not complete in calibration window\n");
return;
} }
ah->ah_noise_floor = noise_floor; switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_T:
case CHANNEL_XR:
ee_mode = AR5K_EEPROM_MODE_11A;
break;
case CHANNEL_G:
case CHANNEL_TG:
ee_mode = AR5K_EEPROM_MODE_11G;
break;
default:
case CHANNEL_B:
ee_mode = AR5K_EEPROM_MODE_11B;
break;
}
return 0;
/* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah);
threshold = ee->ee_noise_floor_thr[ee_mode];
if (nf > threshold) {
ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
"noise floor failure detected; "
"read %d, threshold %d\n",
nf, threshold);
nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
}
ath5k_hw_update_nfcal_hist(ah, nf);
nf = ath5k_hw_get_median_noise_floor(ah);
/* load noise floor (in .5 dBm) so the hardware will use it */
val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
val |= (nf * 2) & AR5K_PHY_NF_M;
ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
0, false);
/*
* Load a high max CCA Power value (-50 dBm in .5 dBm units)
* so that we're not capped by the median we just loaded.
* This will be used as the initial value for the next noise
* floor calibration.
*/
val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_NF_EN |
AR5K_PHY_AGCCTL_NF_NOUPDATE |
AR5K_PHY_AGCCTL_NF);
ah->ah_noise_floor = nf;
ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
"noise floor calibrated: %d\n", nf);
} }
/* /*
@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret; return ret;
} }
ath5k_hw_noise_floor_calibration(ah, channel->center_freq); ath5k_hw_update_noise_floor(ah);
/* /*
* Re-enable RX/TX and beacons * Re-enable RX/TX and beacons
@ -1360,7 +1431,7 @@ done:
* since noise floor calibration interrupts rx path while I/Q * since noise floor calibration interrupts rx path while I/Q
* calibration doesn't. We don't need to run noise floor calibration * calibration doesn't. We don't need to run noise floor calibration
* as often as I/Q calibration.*/ * as often as I/Q calibration.*/
ath5k_hw_noise_floor_calibration(ah, channel->center_freq); ath5k_hw_update_noise_floor(ah);
/* Initiate a gain_F calibration */ /* Initiate a gain_F calibration */
ath5k_hw_request_rfgain_probe(ah); ath5k_hw_request_rfgain_probe(ah);

View File

@ -2033,17 +2033,14 @@
#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */
/* /*
* PHY noise floor status register * PHY noise floor status register (CCA = Clear Channel Assessment)
*/ */
#define AR5K_PHY_NF 0x9864 /* Register address */ #define AR5K_PHY_NF 0x9864 /* Register address */
#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ #define AR5K_PHY_NF_M 0x000001ff /* Noise floor, written to hardware in 1/2 dBm units */
#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M)
#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1)
#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ #define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */
#define AR5K_PHY_NF_THRESH62_S 12 #define AR5K_PHY_NF_THRESH62_S 12
#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ #define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* Minimum measured noise level, read from hardware in 1 dBm units */
#define AR5K_PHY_NF_MINCCA_PWR_S 19 #define AR5K_PHY_NF_MINCCA_PWR_S 19
/* /*

View File

@ -1293,7 +1293,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* out and/or noise floor calibration might timeout. * out and/or noise floor calibration might timeout.
*/ */
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL); AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
/* At the same time start I/Q calibration for QAM constellation /* At the same time start I/Q calibration for QAM constellation
* -no need for CCK- */ * -no need for CCK- */
@ -1314,21 +1314,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
channel->center_freq); channel->center_freq);
} }
/*
* If we run NF calibration before AGC, it always times out.
* Binary HAL starts NF and AGC calibration at the same time
* and only waits for AGC to finish. Also if AGC or NF cal.
* times out, reset doesn't fail on binary HAL. I believe
* that's wrong because since rx path is routed to a detector,
* if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
* enables noise floor calibration after offset calibration and if noise
* floor calibration fails, reset fails. I believe that's
* a better approach, we just need to find a polling interval
* that suits best, even if reset continues we need to make
* sure that rx path is ready.
*/
ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/* Restore antenna mode */ /* Restore antenna mode */
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);

View File

@ -29,15 +29,13 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
static void ath_ahb_cleanup(struct ath_common *common) static void ath_ahb_cleanup(struct ath_common *common)
{ {
struct ath_hw *ah = (struct ath_hw *) common->ah; struct ath_softc *sc = (struct ath_softc *)common->priv;
struct ath_softc *sc = ah->ah_sc;
iounmap(sc->mem); iounmap(sc->mem);
} }
static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{ {
struct ath_hw *ah = (struct ath_hw *) common->ah; struct ath_softc *sc = (struct ath_softc *)common->priv;
struct ath_softc *sc = ah->ah_sc;
struct platform_device *pdev = to_platform_device(sc->dev); struct platform_device *pdev = to_platform_device(sc->dev);
struct ath9k_platform_data *pdata; struct ath9k_platform_data *pdata;

View File

@ -813,7 +813,7 @@ static void ath9k_olc_temp_compensation(struct ath_hw *ah)
} }
} }
static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
{ {
u32 regVal; u32 regVal;
unsigned int i; unsigned int i;
@ -889,10 +889,19 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
REG_WRITE(ah, 0x7834, regVal); REG_WRITE(ah, 0x7834, regVal);
} }
/* Empirical offset correction */ regVal = (regVal >>20) & 0x7f;
#if 0
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20); /* Update PA cal info */
#endif if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
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 = regVal;
}
regVal = REG_READ(ah, 0x7834); regVal = REG_READ(ah, 0x7834);
regVal |= 0x1; regVal |= 0x1;
@ -1043,7 +1052,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
if (longcal) { if (longcal) {
/* Do periodic PAOffset Cal */ /* Do periodic PAOffset Cal */
if (AR_SREV_9271(ah)) if (AR_SREV_9271(ah))
ath9k_hw_9271_pa_cal(ah); ath9k_hw_9271_pa_cal(ah, false);
else if (AR_SREV_9285_11_OR_LATER(ah)) { else if (AR_SREV_9285_11_OR_LATER(ah)) {
if (!ah->pacal_info.skipcount) if (!ah->pacal_info.skipcount)
ath9k_hw_9285_pa_cal(ah, false); ath9k_hw_9285_pa_cal(ah, false);
@ -1070,6 +1079,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
} }
EXPORT_SYMBOL(ath9k_hw_calibrate); EXPORT_SYMBOL(ath9k_hw_calibrate);
/* Carrier leakage Calibration fix */
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
@ -1115,7 +1125,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
if (AR_SREV_9285_12_OR_LATER(ah)) { if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
if (!ar9285_clc(ah, chan)) if (!ar9285_clc(ah, chan))
return false; return false;
} else { } else {
@ -1151,7 +1161,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
} }
/* Do PA Calibration */ /* Do PA Calibration */
if (AR_SREV_9285_11_OR_LATER(ah)) if (AR_SREV_9271(ah))
ath9k_hw_9271_pa_cal(ah, true);
else if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah, true); ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */ /* Do NF Calibration after DC offset and other calibrations */

View File

@ -2079,7 +2079,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
if (needreset) { if (needreset) {
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
"tx hung, resetting the chip\n"); "tx hung, resetting the chip\n");
ath9k_ps_wakeup(sc);
ath_reset(sc, false); ath_reset(sc, false);
ath9k_ps_restore(sc);
} }
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,

View File

@ -65,10 +65,13 @@ enum CountryCode {
CTRY_ALGERIA = 12, CTRY_ALGERIA = 12,
CTRY_ARGENTINA = 32, CTRY_ARGENTINA = 32,
CTRY_ARMENIA = 51, CTRY_ARMENIA = 51,
CTRY_ARUBA = 533,
CTRY_AUSTRALIA = 36, CTRY_AUSTRALIA = 36,
CTRY_AUSTRIA = 40, CTRY_AUSTRIA = 40,
CTRY_AZERBAIJAN = 31, CTRY_AZERBAIJAN = 31,
CTRY_BAHRAIN = 48, CTRY_BAHRAIN = 48,
CTRY_BANGLADESH = 50,
CTRY_BARBADOS = 52,
CTRY_BELARUS = 112, CTRY_BELARUS = 112,
CTRY_BELGIUM = 56, CTRY_BELGIUM = 56,
CTRY_BELIZE = 84, CTRY_BELIZE = 84,
@ -77,6 +80,7 @@ enum CountryCode {
CTRY_BRAZIL = 76, CTRY_BRAZIL = 76,
CTRY_BRUNEI_DARUSSALAM = 96, CTRY_BRUNEI_DARUSSALAM = 96,
CTRY_BULGARIA = 100, CTRY_BULGARIA = 100,
CTRY_CAMBODIA = 116,
CTRY_CANADA = 124, CTRY_CANADA = 124,
CTRY_CHILE = 152, CTRY_CHILE = 152,
CTRY_CHINA = 156, CTRY_CHINA = 156,
@ -97,7 +101,11 @@ enum CountryCode {
CTRY_GEORGIA = 268, CTRY_GEORGIA = 268,
CTRY_GERMANY = 276, CTRY_GERMANY = 276,
CTRY_GREECE = 300, CTRY_GREECE = 300,
CTRY_GREENLAND = 304,
CTRY_GRENEDA = 308,
CTRY_GUAM = 316,
CTRY_GUATEMALA = 320, CTRY_GUATEMALA = 320,
CTRY_HAITI = 332,
CTRY_HONDURAS = 340, CTRY_HONDURAS = 340,
CTRY_HONG_KONG = 344, CTRY_HONG_KONG = 344,
CTRY_HUNGARY = 348, CTRY_HUNGARY = 348,

View File

@ -288,13 +288,16 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_DEFAULT, FCC1_FCCA, "CO"}, {CTRY_DEFAULT, FCC1_FCCA, "CO"},
{CTRY_ALBANIA, NULL1_WORLD, "AL"}, {CTRY_ALBANIA, NULL1_WORLD, "AL"},
{CTRY_ALGERIA, NULL1_WORLD, "DZ"}, {CTRY_ALGERIA, NULL1_WORLD, "DZ"},
{CTRY_ARGENTINA, APL3_WORLD, "AR"}, {CTRY_ARGENTINA, FCC3_WORLD, "AR"},
{CTRY_ARMENIA, ETSI4_WORLD, "AM"}, {CTRY_ARMENIA, ETSI4_WORLD, "AM"},
{CTRY_ARUBA, ETSI1_WORLD, "AW"},
{CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, {CTRY_AUSTRALIA, FCC2_WORLD, "AU"},
{CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"},
{CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"},
{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"},
{CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"},
{CTRY_BANGLADESH, NULL1_WORLD, "BD"},
{CTRY_BARBADOS, FCC2_WORLD, "BB"},
{CTRY_BELARUS, ETSI1_WORLD, "BY"}, {CTRY_BELARUS, ETSI1_WORLD, "BY"},
{CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM, ETSI1_WORLD, "BE"},
{CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"},
@ -304,13 +307,14 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_BRAZIL, FCC3_WORLD, "BR"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"},
{CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"},
{CTRY_BULGARIA, ETSI6_WORLD, "BG"}, {CTRY_BULGARIA, ETSI6_WORLD, "BG"},
{CTRY_CANADA, FCC2_FCCA, "CA"}, {CTRY_CAMBODIA, ETSI1_WORLD, "KH"},
{CTRY_CANADA, FCC3_FCCA, "CA"},
{CTRY_CANADA2, FCC6_FCCA, "CA"}, {CTRY_CANADA2, FCC6_FCCA, "CA"},
{CTRY_CHILE, APL6_WORLD, "CL"}, {CTRY_CHILE, APL6_WORLD, "CL"},
{CTRY_CHINA, APL1_WORLD, "CN"}, {CTRY_CHINA, APL1_WORLD, "CN"},
{CTRY_COLOMBIA, FCC1_FCCA, "CO"}, {CTRY_COLOMBIA, FCC1_FCCA, "CO"},
{CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, {CTRY_COSTA_RICA, FCC1_WORLD, "CR"},
{CTRY_CROATIA, ETSI3_WORLD, "HR"}, {CTRY_CROATIA, ETSI1_WORLD, "HR"},
{CTRY_CYPRUS, ETSI1_WORLD, "CY"}, {CTRY_CYPRUS, ETSI1_WORLD, "CY"},
{CTRY_CZECH, ETSI3_WORLD, "CZ"}, {CTRY_CZECH, ETSI3_WORLD, "CZ"},
{CTRY_DENMARK, ETSI1_WORLD, "DK"}, {CTRY_DENMARK, ETSI1_WORLD, "DK"},
@ -324,18 +328,22 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_GEORGIA, ETSI4_WORLD, "GE"}, {CTRY_GEORGIA, ETSI4_WORLD, "GE"},
{CTRY_GERMANY, ETSI1_WORLD, "DE"}, {CTRY_GERMANY, ETSI1_WORLD, "DE"},
{CTRY_GREECE, ETSI1_WORLD, "GR"}, {CTRY_GREECE, ETSI1_WORLD, "GR"},
{CTRY_GREENLAND, ETSI1_WORLD, "GL"},
{CTRY_GRENEDA, FCC3_FCCA, "GD"},
{CTRY_GUAM, FCC1_FCCA, "GU"},
{CTRY_GUATEMALA, FCC1_FCCA, "GT"}, {CTRY_GUATEMALA, FCC1_FCCA, "GT"},
{CTRY_HAITI, ETSI1_WORLD, "HT"},
{CTRY_HONDURAS, NULL1_WORLD, "HN"}, {CTRY_HONDURAS, NULL1_WORLD, "HN"},
{CTRY_HONG_KONG, FCC2_WORLD, "HK"}, {CTRY_HONG_KONG, FCC3_WORLD, "HK"},
{CTRY_HUNGARY, ETSI1_WORLD, "HU"}, {CTRY_HUNGARY, ETSI1_WORLD, "HU"},
{CTRY_ICELAND, ETSI1_WORLD, "IS"}, {CTRY_ICELAND, ETSI1_WORLD, "IS"},
{CTRY_INDIA, APL6_WORLD, "IN"}, {CTRY_INDIA, APL6_WORLD, "IN"},
{CTRY_INDONESIA, APL1_WORLD, "ID"}, {CTRY_INDONESIA, NULL1_WORLD, "ID"},
{CTRY_IRAN, APL1_WORLD, "IR"}, {CTRY_IRAN, APL1_WORLD, "IR"},
{CTRY_IRELAND, ETSI1_WORLD, "IE"}, {CTRY_IRELAND, ETSI1_WORLD, "IE"},
{CTRY_ISRAEL, NULL1_WORLD, "IL"}, {CTRY_ISRAEL, NULL1_WORLD, "IL"},
{CTRY_ITALY, ETSI1_WORLD, "IT"}, {CTRY_ITALY, ETSI1_WORLD, "IT"},
{CTRY_JAMAICA, ETSI1_WORLD, "JM"}, {CTRY_JAMAICA, FCC3_WORLD, "JM"},
{CTRY_JAPAN, MKK1_MKKA, "JP"}, {CTRY_JAPAN, MKK1_MKKA, "JP"},
{CTRY_JAPAN1, MKK1_MKKB, "JP"}, {CTRY_JAPAN1, MKK1_MKKB, "JP"},
@ -402,7 +410,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_KOREA_ROC, APL9_WORLD, "KR"}, {CTRY_KOREA_ROC, APL9_WORLD, "KR"},
{CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, {CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
{CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, {CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
{CTRY_KUWAIT, NULL1_WORLD, "KW"}, {CTRY_KUWAIT, ETSI3_WORLD, "KW"},
{CTRY_LATVIA, ETSI1_WORLD, "LV"}, {CTRY_LATVIA, ETSI1_WORLD, "LV"},
{CTRY_LEBANON, NULL1_WORLD, "LB"}, {CTRY_LEBANON, NULL1_WORLD, "LB"},
{CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"},
@ -414,13 +422,13 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_MALTA, ETSI1_WORLD, "MT"}, {CTRY_MALTA, ETSI1_WORLD, "MT"},
{CTRY_MEXICO, FCC1_FCCA, "MX"}, {CTRY_MEXICO, FCC1_FCCA, "MX"},
{CTRY_MONACO, ETSI4_WORLD, "MC"}, {CTRY_MONACO, ETSI4_WORLD, "MC"},
{CTRY_MOROCCO, NULL1_WORLD, "MA"}, {CTRY_MOROCCO, APL4_WORLD, "MA"},
{CTRY_NEPAL, APL1_WORLD, "NP"}, {CTRY_NEPAL, APL1_WORLD, "NP"},
{CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"},
{CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"},
{CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"},
{CTRY_NORWAY, ETSI1_WORLD, "NO"}, {CTRY_NORWAY, ETSI1_WORLD, "NO"},
{CTRY_OMAN, APL6_WORLD, "OM"}, {CTRY_OMAN, FCC3_WORLD, "OM"},
{CTRY_PAKISTAN, NULL1_WORLD, "PK"}, {CTRY_PAKISTAN, NULL1_WORLD, "PK"},
{CTRY_PANAMA, FCC1_FCCA, "PA"}, {CTRY_PANAMA, FCC1_FCCA, "PA"},
{CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"},
@ -429,7 +437,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_POLAND, ETSI1_WORLD, "PL"}, {CTRY_POLAND, ETSI1_WORLD, "PL"},
{CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, {CTRY_PORTUGAL, ETSI1_WORLD, "PT"},
{CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"},
{CTRY_QATAR, NULL1_WORLD, "QA"}, {CTRY_QATAR, APL1_WORLD, "QA"},
{CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_ROMANIA, NULL1_WORLD, "RO"},
{CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"},
{CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"},
@ -445,7 +453,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"}, {CTRY_TAIWAN, APL3_FCCA, "TW"},
{CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_THAILAND, FCC3_WORLD, "TH"},
{CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"},
{CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"},
@ -456,7 +464,7 @@ static struct country_code_to_enum_rd allCountries[] = {
* would need to assign new special alpha2 to CRDA db as with the world * would need to assign new special alpha2 to CRDA db as with the world
* regdomain and use another alpha2 */ * regdomain and use another alpha2 */
{CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"},
{CTRY_URUGUAY, APL2_WORLD, "UY"}, {CTRY_URUGUAY, FCC3_WORLD, "UY"},
{CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"},
{CTRY_VENEZUELA, APL2_ETSIC, "VE"}, {CTRY_VENEZUELA, APL2_ETSIC, "VE"},
{CTRY_VIET_NAM, NULL1_WORLD, "VN"}, {CTRY_VIET_NAM, NULL1_WORLD, "VN"},

View File

@ -749,12 +749,6 @@ struct b43_wldev {
#endif #endif
}; };
/*
* Include goes here to avoid a dependency problem.
* A better fix would be to integrate xmit.h into b43.h.
*/
#include "xmit.h"
/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
struct b43_wl { struct b43_wl {
/* Pointer to the active wireless device on this chip */ /* Pointer to the active wireless device on this chip */
@ -830,13 +824,9 @@ struct b43_wl {
struct b43_leds leds; struct b43_leds leds;
#ifdef CONFIG_B43_PIO #ifdef CONFIG_B43_PIO
/* /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
* RX/TX header/tail buffers used by the frame transmit functions. u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
*/ u8 pio_tailspace[4] __attribute__((__aligned__(8)));
struct b43_rxhdr_fw4 rxhdr;
struct b43_txhdr txhdr;
u8 rx_tail[4];
u8 tx_tail[4];
#endif /* CONFIG_B43_PIO */ #endif /* CONFIG_B43_PIO */
}; };

View File

@ -4671,7 +4671,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
{ {
struct b43_wl *wl = dev->wl; struct b43_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus; struct ssb_bus *bus = dev->dev->bus;
struct pci_dev *pdev = bus->host_pci; struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err; int err;
bool have_2ghz_phy = 0, have_5ghz_phy = 0; bool have_2ghz_phy = 0, have_5ghz_phy = 0;
u32 tmp; u32 tmp;
@ -4804,7 +4804,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
if (!list_empty(&wl->devlist)) { if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */ /* We are not the first core on this chip. */
pdev = dev->bus->host_pci; pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless /* Only special chips support more than one wireless
* core, although some of the other chips have more than * core, although some of the other chips have more than
* one wireless core as well. Check for this and * one wireless core as well. Check for this and

View File

@ -341,12 +341,15 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO_TXDATA, q->mmio_base + B43_PIO_TXDATA,
sizeof(u16)); sizeof(u16));
if (data_len & 1) { if (data_len & 1) {
u8 *tail = wl->pio_tailspace;
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
/* Write the last byte. */ /* Write the last byte. */
ctl &= ~B43_PIO_TXCTL_WRITEHI; ctl &= ~B43_PIO_TXCTL_WRITEHI;
b43_piotx_write16(q, B43_PIO_TXCTL, ctl); b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
wl->tx_tail[0] = data[data_len - 1]; tail[0] = data[data_len - 1];
wl->tx_tail[1] = 0; tail[1] = 0;
ssb_block_write(dev->dev, wl->tx_tail, 2, ssb_block_write(dev->dev, tail, 2,
q->mmio_base + B43_PIO_TXDATA, q->mmio_base + B43_PIO_TXDATA,
sizeof(u16)); sizeof(u16));
} }
@ -392,31 +395,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO8_TXDATA, q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32)); sizeof(u32));
if (data_len & 3) { if (data_len & 3) {
wl->tx_tail[3] = 0; u8 *tail = wl->pio_tailspace;
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
memset(tail, 0, 4);
/* Write the last few bytes. */ /* Write the last few bytes. */
ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 | ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
B43_PIO8_TXCTL_24_31); B43_PIO8_TXCTL_24_31);
switch (data_len & 3) { switch (data_len & 3) {
case 3: case 3:
ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15; ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15;
wl->tx_tail[0] = data[data_len - 3]; tail[0] = data[data_len - 3];
wl->tx_tail[1] = data[data_len - 2]; tail[1] = data[data_len - 2];
wl->tx_tail[2] = data[data_len - 1]; tail[2] = data[data_len - 1];
break; break;
case 2: case 2:
ctl |= B43_PIO8_TXCTL_8_15; ctl |= B43_PIO8_TXCTL_8_15;
wl->tx_tail[0] = data[data_len - 2]; tail[0] = data[data_len - 2];
wl->tx_tail[1] = data[data_len - 1]; tail[1] = data[data_len - 1];
wl->tx_tail[2] = 0;
break; break;
case 1: case 1:
wl->tx_tail[0] = data[data_len - 1]; tail[0] = data[data_len - 1];
wl->tx_tail[1] = 0;
wl->tx_tail[2] = 0;
break; break;
} }
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
ssb_block_write(dev->dev, wl->tx_tail, 4, ssb_block_write(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_TXDATA, q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32)); sizeof(u32));
} }
@ -455,6 +458,7 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
int err; int err;
unsigned int hdrlen; unsigned int hdrlen;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace;
B43_WARN_ON(list_empty(&q->packets_list)); B43_WARN_ON(list_empty(&q->packets_list));
pack = list_entry(q->packets_list.next, pack = list_entry(q->packets_list.next,
@ -462,7 +466,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
cookie = generate_cookie(q, pack); cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(dev); hdrlen = b43_txhdr_size(dev);
err = b43_generate_txhdr(dev, (u8 *)&wl->txhdr, skb, BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr));
B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen);
err = b43_generate_txhdr(dev, (u8 *)txhdr, skb,
info, cookie); info, cookie);
if (err) if (err)
return err; return err;
@ -476,9 +482,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
pack->skb = skb; pack->skb = skb;
if (q->rev >= 8) if (q->rev >= 8)
pio_tx_frame_4byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen); pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen);
else else
pio_tx_frame_2byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen); pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen);
/* Remove it from the list of available packet slots. /* Remove it from the list of available packet slots.
* It will be put back when we receive the status report. */ * It will be put back when we receive the status report. */
@ -624,8 +630,11 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
unsigned int i, padding; unsigned int i, padding;
struct sk_buff *skb; struct sk_buff *skb;
const char *err_msg = NULL; const char *err_msg = NULL;
struct b43_rxhdr_fw4 *rxhdr =
(struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
memset(&wl->rxhdr, 0, sizeof(wl->rxhdr)); BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
memset(rxhdr, 0, sizeof(*rxhdr));
/* Check if we have data and wait for it to get ready. */ /* Check if we have data and wait for it to get ready. */
if (q->rev >= 8) { if (q->rev >= 8) {
@ -663,16 +672,16 @@ data_ready:
/* Get the preamble (RX header) */ /* Get the preamble (RX header) */
if (q->rev >= 8) { if (q->rev >= 8) {
ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr), ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO8_RXDATA, q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32)); sizeof(u32));
} else { } else {
ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr), ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO_RXDATA, q->mmio_base + B43_PIO_RXDATA,
sizeof(u16)); sizeof(u16));
} }
/* Sanity checks. */ /* Sanity checks. */
len = le16_to_cpu(wl->rxhdr.frame_len); len = le16_to_cpu(rxhdr->frame_len);
if (unlikely(len > 0x700)) { if (unlikely(len > 0x700)) {
err_msg = "len > 0x700"; err_msg = "len > 0x700";
goto rx_error; goto rx_error;
@ -682,7 +691,7 @@ data_ready:
goto rx_error; goto rx_error;
} }
macstat = le32_to_cpu(wl->rxhdr.mac_status); macstat = le32_to_cpu(rxhdr->mac_status);
if (macstat & B43_RX_MAC_FCSERR) { if (macstat & B43_RX_MAC_FCSERR) {
if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) { if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
/* Drop frames with failed FCS. */ /* Drop frames with failed FCS. */
@ -707,22 +716,25 @@ data_ready:
q->mmio_base + B43_PIO8_RXDATA, q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32)); sizeof(u32));
if (len & 3) { if (len & 3) {
u8 *tail = wl->pio_tailspace;
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
/* Read the last few bytes. */ /* Read the last few bytes. */
ssb_block_read(dev->dev, wl->rx_tail, 4, ssb_block_read(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_RXDATA, q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32)); sizeof(u32));
switch (len & 3) { switch (len & 3) {
case 3: case 3:
skb->data[len + padding - 3] = wl->rx_tail[0]; skb->data[len + padding - 3] = tail[0];
skb->data[len + padding - 2] = wl->rx_tail[1]; skb->data[len + padding - 2] = tail[1];
skb->data[len + padding - 1] = wl->rx_tail[2]; skb->data[len + padding - 1] = tail[2];
break; break;
case 2: case 2:
skb->data[len + padding - 2] = wl->rx_tail[0]; skb->data[len + padding - 2] = tail[0];
skb->data[len + padding - 1] = wl->rx_tail[1]; skb->data[len + padding - 1] = tail[1];
break; break;
case 1: case 1:
skb->data[len + padding - 1] = wl->rx_tail[0]; skb->data[len + padding - 1] = tail[0];
break; break;
} }
} }
@ -731,15 +743,18 @@ data_ready:
q->mmio_base + B43_PIO_RXDATA, q->mmio_base + B43_PIO_RXDATA,
sizeof(u16)); sizeof(u16));
if (len & 1) { if (len & 1) {
u8 *tail = wl->pio_tailspace;
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
/* Read the last byte. */ /* Read the last byte. */
ssb_block_read(dev->dev, wl->rx_tail, 2, ssb_block_read(dev->dev, tail, 2,
q->mmio_base + B43_PIO_RXDATA, q->mmio_base + B43_PIO_RXDATA,
sizeof(u16)); sizeof(u16));
skb->data[len + padding - 1] = wl->rx_tail[0]; skb->data[len + padding - 1] = tail[0];
} }
} }
b43_rx(q->dev, skb, &wl->rxhdr); b43_rx(q->dev, skb, rxhdr);
return 1; return 1;

View File

@ -27,7 +27,7 @@
*/ */
#include "b43.h" #include "xmit.h"
#include "phy_common.h" #include "phy_common.h"
#include "dma.h" #include "dma.h"
#include "pio.h" #include "pio.h"
@ -690,10 +690,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
} }
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
ieee80211_rx_ni(dev->wl->hw, skb);
local_bh_disable();
ieee80211_rx(dev->wl->hw, skb);
local_bh_enable();
#if B43_DEBUG #if B43_DEBUG
dev->rx_count++; dev->rx_count++;

View File

@ -3592,7 +3592,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
{ {
struct b43legacy_wl *wl = dev->wl; struct b43legacy_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus; struct ssb_bus *bus = dev->dev->bus;
struct pci_dev *pdev = bus->host_pci; struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err; int err;
int have_bphy = 0; int have_bphy = 0;
int have_gphy = 0; int have_gphy = 0;
@ -3706,7 +3706,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev,
if (!list_empty(&wl->devlist)) { if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */ /* We are not the first core on this chip. */
pdev = dev->bus->host_pci; pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless /* Only special chips support more than one wireless
* core, although some of the other chips have more than * core, although some of the other chips have more than
* one wireless core as well. Check for this and * one wireless core as well. Check for this and

View File

@ -110,8 +110,7 @@ static struct iwl_lib_ops iwl1000_lib = {
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl1000_nic_config, .config = iwl1000_nic_config,
.set_pwr_src = iwl_set_pwr_src, .set_pwr_src = iwl_set_pwr_src,
@ -159,15 +158,20 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A, .valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = false,
.use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000, .max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false, .shadow_ram_support = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl1000_bg_cfg = { struct iwl_cfg iwl1000_bg_cfg = {
@ -180,15 +184,20 @@ struct iwl_cfg iwl1000_bg_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A, .valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = false,
.use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000, .max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false, .shadow_ram_support = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.support_ct_kill_exit = true,
}; };
MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));

View File

@ -71,12 +71,6 @@
#include "iwl-eeprom.h" #include "iwl-eeprom.h"
/*
* uCode queue management definitions ...
* Queue #4 is the command queue for 3945 and 4965.
*/
#define IWL_CMD_QUEUE_NUM 4
/* Time constants */ /* Time constants */
#define SHORT_SLOT_TIME 9 #define SHORT_SLOT_TIME 9
#define LONG_SLOT_TIME 20 #define LONG_SLOT_TIME 20
@ -254,12 +248,6 @@ struct iwl3945_eeprom {
#define TFD_CTL_PAD_SET(n) (n << 28) #define TFD_CTL_PAD_SET(n) (n << 28)
#define TFD_CTL_PAD_GET(ctl) (ctl >> 28) #define TFD_CTL_PAD_GET(ctl) (ctl >> 28)
/*
* RX related structures and functions
*/
#define RX_FREE_BUFFERS 64
#define RX_LOW_WATERMARK 8
/* Sizes and addresses for instruction and data memory (SRAM) in /* Sizes and addresses for instruction and data memory (SRAM) in
* 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ * 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */
#define IWL39_RTC_INST_LOWER_BOUND (0x000000) #define IWL39_RTC_INST_LOWER_BOUND (0x000000)

View File

@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
static void iwl3945_rx_reply_tx(struct iwl_priv *priv, static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence); u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence); int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
@ -353,16 +353,12 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
void iwl3945_hw_rx_statistics(struct iwl_priv *priv, void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics), (int)sizeof(struct iwl3945_notif_statistics),
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
iwl_leds_background(priv);
priv->last_statistics_time = jiffies;
} }
/****************************************************************************** /******************************************************************************
@ -545,14 +541,18 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb, struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats) struct ieee80211_rx_status *stats)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
short len = le16_to_cpu(rx_hdr->len); u16 len = le16_to_cpu(rx_hdr->len);
struct sk_buff *skb;
int ret;
__le16 fc = hdr->frame_control;
/* We received data from the HW, so stop the watchdog */ /* We received data from the HW, so stop the watchdog */
if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { if (unlikely(len + IWL39_RX_FRAME_SIZE >
PAGE_SIZE << priv->hw_params.rx_page_order)) {
IWL_DEBUG_DROP(priv, "Corruption detected!\n"); IWL_DEBUG_DROP(priv, "Corruption detected!\n");
return; return;
} }
@ -564,20 +564,49 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
return; return;
} }
skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
/* Set the size of the skb to the size of the frame */ if (!skb) {
skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); IWL_ERR(priv, "alloc_skb failed\n");
return;
}
if (!iwl3945_mod_params.sw_crypto) if (!iwl3945_mod_params.sw_crypto)
iwl_set_decrypted_flag(priv, iwl_set_decrypted_flag(priv,
(struct ieee80211_hdr *)rxb->skb->data, (struct ieee80211_hdr *)rxb_addr(rxb),
le32_to_cpu(rx_end->status), stats); le32_to_cpu(rx_end->status), stats);
iwl_update_stats(priv, false, hdr->frame_control, len); skb_add_rx_frag(skb, 0, rxb->page,
(void *)rx_hdr->payload - (void *)pkt, len);
memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); /* mac80211 currently doesn't support paged SKB. Convert it to
ieee80211_rx_irqsafe(priv->hw, rxb->skb); * linear SKB for management frame and data frame requires
rxb->skb = NULL; * software decryption or software defragementation. */
if (ieee80211_is_mgmt(fc) ||
ieee80211_has_protected(fc) ||
ieee80211_has_morefrags(fc) ||
le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
ret = skb_linearize(skb);
else
ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
0 : -ENOMEM;
if (ret) {
kfree_skb(skb);
goto out;
}
/*
* XXX: We cannot touch the page and its virtual memory (pkt) after
* here. It might have already been freed by the above skb change.
*/
iwl_update_stats(priv, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
ieee80211_rx(priv->hw, skb);
out:
priv->alloc_rxb_page--;
rxb->page = NULL;
} }
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
@ -587,7 +616,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
{ {
struct ieee80211_hdr *header; struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status; struct ieee80211_rx_status rx_status;
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
@ -787,29 +816,31 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
u8 data_retry_limit; u8 data_retry_limit;
__le32 tx_flags; __le32 tx_flags;
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
rate = iwl3945_rates[rate_index].plcp; rate = iwl3945_rates[rate_index].plcp;
tx_flags = tx->tx_flags; tx_flags = tx_cmd->tx_flags;
/* We need to figure out how to get the sta->supp_rates while /* We need to figure out how to get the sta->supp_rates while
* in this running context */ * in this running context */
rate_mask = IWL_RATES_MASK; rate_mask = IWL_RATES_MASK;
/* Set retry limit on DATA packets and Probe Responses*/
if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3;
else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
tx_cmd->data_retry_limit = data_retry_limit;
if (tx_id >= IWL_CMD_QUEUE_NUM) if (tx_id >= IWL_CMD_QUEUE_NUM)
rts_retry_limit = 3; rts_retry_limit = 3;
else else
rts_retry_limit = 7; rts_retry_limit = 7;
if (ieee80211_is_probe_resp(fc)) { if (data_retry_limit < rts_retry_limit)
data_retry_limit = 3; rts_retry_limit = data_retry_limit;
if (data_retry_limit < rts_retry_limit) tx_cmd->rts_retry_limit = rts_retry_limit;
rts_retry_limit = data_retry_limit;
} else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
if (priv->data_retry_limit != -1)
data_retry_limit = priv->data_retry_limit;
if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_mgmt(fc)) {
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
@ -827,22 +858,20 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
} }
} }
tx->rts_retry_limit = rts_retry_limit; tx_cmd->rate = rate;
tx->data_retry_limit = data_retry_limit; tx_cmd->tx_flags = tx_flags;
tx->rate = rate;
tx->tx_flags = tx_flags;
/* OFDM */ /* OFDM */
tx->supp_rates[0] = tx_cmd->supp_rates[0] =
((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF; ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
/* CCK */ /* CCK */
tx->supp_rates[1] = (rate_mask & 0xF); tx_cmd->supp_rates[1] = (rate_mask & 0xF);
IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
"cck/ofdm mask: 0x%x/0x%x\n", sta_id, "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
tx->rate, le32_to_cpu(tx->tx_flags), tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
tx->supp_rates[1], tx->supp_rates[0]); tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
} }
u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
@ -958,6 +987,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv); iwl3945_hw_txq_ctx_free(priv);
/* allocate tx queue structure */
rc = iwl_alloc_txq_mem(priv);
if (rc)
return rc;
/* Tx CMD queue */ /* Tx CMD queue */
rc = iwl3945_tx_reset(priv); rc = iwl3945_tx_reset(priv);
if (rc) if (rc)
@ -982,42 +1016,25 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
return rc; return rc;
} }
/*
* Start up 3945's basic functionality after it has been reset
* (e.g. after platform boot, or shutdown via iwl_apm_stop())
* NOTE: This does not load uCode nor start the embedded processor
*/
static int iwl3945_apm_init(struct iwl_priv *priv) static int iwl3945_apm_init(struct iwl_priv *priv)
{ {
int ret; int ret = iwl_apm_init(priv);
iwl_power_initialize(priv); /* Clear APMG (NIC's internal power management) interrupts */
iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, /* Reset radio chip */
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
/* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* set "initialization complete" bit to move adapter
* D0U* --> D0A* state */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(priv, "Failed to init the card\n");
goto out;
}
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
out:
return ret; return ret;
} }
@ -1142,12 +1159,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id; int txq_id;
/* Tx queues */ /* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) if (priv->txq)
if (txq_id == IWL_CMD_QUEUE_NUM) for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
iwl_cmd_queue_free(priv); txq_id++)
else if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_tx_queue_free(priv, txq_id); iwl_cmd_queue_free(priv);
else
iwl_tx_queue_free(priv, txq_id);
/* free tx queue structure */
iwl_free_txq_mem(priv);
} }
void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
@ -1156,6 +1177,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
/* stop SCD */ /* stop SCD */
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
/* reset TFD queues */ /* reset TFD queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
@ -1168,47 +1190,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv); iwl3945_hw_txq_ctx_free(priv);
} }
static int iwl3945_apm_reset(struct iwl_priv *priv)
{
iwl_apm_stop_master(priv);
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
iwl_write_prph(priv, APMG_CLK_CTRL_REG,
APMG_CLK_VAL_BSM_CLK_RQT);
iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
iwl_write_prph(priv, APMG_RTC_INT_STT_REG,
0xFFFFFFFF);
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
udelay(10);
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
/* Clear the 'host command active' bit... */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
return 0;
}
/** /**
* iwl3945_hw_reg_adjust_power_by_temp * iwl3945_hw_reg_adjust_power_by_temp
* return index delta into power gain settings table * return index delta into power gain settings table
@ -1817,7 +1798,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
{ {
int rc = 0; int rc = 0;
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *pkt;
struct iwl3945_rxon_assoc_cmd rxon_assoc; struct iwl3945_rxon_assoc_cmd rxon_assoc;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC, .id = REPLY_RXON_ASSOC,
@ -1846,14 +1827,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc) if (rc)
return rc; return rc;
res = (struct iwl_rx_packet *)cmd.reply_skb->data; pkt = (struct iwl_rx_packet *)cmd.reply_page;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
rc = -EIO; rc = -EIO;
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_page--;
dev_kfree_skb_any(cmd.reply_skb); free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc; return rc;
} }
@ -2001,12 +1982,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
return 0; return 0;
} }
/* will add 3945 channel switch cmd handling later */
int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
return 0;
}
/** /**
* iwl3945_reg_txpower_periodic - called when time to check our temperature. * iwl3945_reg_txpower_periodic - called when time to check our temperature.
* *
@ -2516,11 +2491,10 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
} }
/* Assign number of Usable TX queues */ /* Assign number of Usable TX queues */
priv->hw_params.max_txq_num = IWL39_NUM_QUEUES; priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K);
priv->hw_params.max_pkt_size = 2342;
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
priv->hw_params.max_stations = IWL3945_STATION_COUNT; priv->hw_params.max_stations = IWL3945_STATION_COUNT;
@ -2803,7 +2777,6 @@ static struct iwl_lib_ops iwl3945_lib = {
.dump_nic_error_log = iwl3945_dump_nic_error_log, .dump_nic_error_log = iwl3945_dump_nic_error_log,
.apm_ops = { .apm_ops = {
.init = iwl3945_apm_init, .init = iwl3945_apm_init,
.reset = iwl3945_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl3945_nic_config, .config = iwl3945_nic_config,
.set_pwr_src = iwl3945_set_pwr_src, .set_pwr_src = iwl3945_set_pwr_src,
@ -2833,6 +2806,7 @@ static struct iwl_lib_ops iwl3945_lib = {
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.get_hcmd_size = iwl3945_get_hcmd_size, .get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd, .build_addsta_hcmd = iwl3945_build_addsta_hcmd,
.rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
}; };
static struct iwl_ops iwl3945_ops = { static struct iwl_ops iwl3945_ops = {
@ -2852,7 +2826,11 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION, .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops, .ops = &iwl3945_ops,
.num_of_queues = IWL39_NUM_QUEUES,
.mod_params = &iwl3945_mod_params, .mod_params = &iwl3945_mod_params,
.pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
.set_l0s = false,
.use_bsm = true,
.use_isr_legacy = true, .use_isr_legacy = true,
.ht_greenfield_support = false, .ht_greenfield_support = false,
.led_compensation = 64, .led_compensation = 64,
@ -2867,6 +2845,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION, .eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops, .ops = &iwl3945_ops,
.num_of_queues = IWL39_NUM_QUEUES,
.mod_params = &iwl3945_mod_params, .mod_params = &iwl3945_mod_params,
.use_isr_legacy = true, .use_isr_legacy = true,
.ht_greenfield_support = false, .ht_greenfield_support = false,

View File

@ -130,12 +130,6 @@ struct iwl3945_frame {
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
/*
* RX related structures and functions
*/
#define RX_FREE_BUFFERS 64
#define RX_LOW_WATERMARK 8
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@ -280,8 +274,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv);
*/ */
extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel);
/* /*
* Forward declare iwl-3945.c functions for iwl-base.c * Forward declare iwl-3945.c functions for iwl-base.c
*/ */

View File

@ -76,12 +76,9 @@
/* /*
* uCode queue management definitions ... * uCode queue management definitions ...
* Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
* The first queue used for block-ack aggregation is #7 (4965 only). * The first queue used for block-ack aggregation is #7 (4965 only).
* All block-ack aggregation queues should map to Tx DMA/FIFO channel 7. * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7.
*/ */
#define IWL_CMD_QUEUE_NUM 4
#define IWL_CMD_FIFO_NUM 4
#define IWL49_FIRST_AMPDU_QUEUE 7 #define IWL49_FIRST_AMPDU_QUEUE 7
/* Time constants */ /* Time constants */

View File

@ -62,8 +62,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
/* module parameters */ /* module parameters */
static struct iwl_mod_params iwl4965_mod_params = { static struct iwl_mod_params iwl4965_mod_params = {
.num_of_queues = IWL49_NUM_QUEUES,
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1, .amsdu_size_8K = 1,
.restart_fw = 1, .restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
@ -319,64 +317,13 @@ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); iwl_write_prph(priv, IWL49_SCD_TXFACT, mask);
} }
static int iwl4965_apm_init(struct iwl_priv *priv)
{
int ret = 0;
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* set "initialization complete" bit to move adapter
* D0U* --> D0A* state */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(priv, "Failed to init the card\n");
goto out;
}
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
out:
return ret;
}
static void iwl4965_nic_config(struct iwl_priv *priv) static void iwl4965_nic_config(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
u16 radio_cfg; u16 radio_cfg;
u16 lctl;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
lctl = iwl_pcie_link_ctl(priv);
/* HW bug W/A - negligible power consumption */
/* L1-ASPM is enabled by BIOS */
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
/* L1-ASPM enabled: disable L0S */
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
else
/* L1-ASPM disabled: enable L0S */
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */ /* write radio config values to register */
@ -397,46 +344,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
static int iwl4965_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
iwl_apm_stop_master(priv);
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
/* FIXME: put here L1A -L0S w/a */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0)
goto out;
udelay(10);
/* Enable DMA and BSM Clock */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
udelay(10);
/* disable L1A */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
out:
return ret;
}
/* Reset differential Rx gains in NIC to prepare for chain noise calibration. /* Reset differential Rx gains in NIC to prepare for chain noise calibration.
* Called after every association, but this runs only once! * Called after every association, but this runs only once!
* ... once chain noise is calibrated the first time, it's good forever. */ * ... once chain noise is calibrated the first time, it's good forever. */
@ -526,18 +433,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
data->beacon_count = 0; data->beacon_count = 0;
} }
static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags)
{
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
*tx_flags |= TX_CMD_FLG_RTS_MSK;
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
*tx_flags |= TX_CMD_FLG_CTS_MSK;
}
}
static void iwl4965_bg_txpower_work(struct work_struct *work) static void iwl4965_bg_txpower_work(struct work_struct *work)
{ {
struct iwl_priv *priv = container_of(work, struct iwl_priv, struct iwl_priv *priv = container_of(work, struct iwl_priv,
@ -718,6 +613,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.nrg_th_cck = 100, .nrg_th_cck = 100,
.nrg_th_ofdm = 100, .nrg_th_ofdm = 100,
.barker_corr_th_min = 190,
.barker_corr_th_min_mrc = 390,
.nrg_th_cca = 62,
}; };
static void iwl4965_set_ct_threshold(struct iwl_priv *priv) static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
@ -734,19 +633,16 @@ static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
*/ */
static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
{ {
if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES)
priv->cfg->num_of_queues =
priv->cfg->mod_params->num_of_queues;
if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) || priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
IWL_ERR(priv,
"invalid queues_num, should be between %d and %d\n",
IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES);
return -EINVAL;
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size = priv->hw_params.scd_bc_tbls_size =
IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); priv->cfg->num_of_queues *
sizeof(struct iwl4965_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.max_stations = IWL4965_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
@ -757,10 +653,10 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
priv->hw_params.tx_chains_num = 2; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
priv->hw_params.rx_chains_num = 2; priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
priv->hw_params.valid_tx_ant = ANT_A | ANT_B; priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = ANT_A | ANT_B; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
if (priv->cfg->ops->lib->temp_ops.set_ct_kill) if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
@ -1537,14 +1433,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return ret; return ret;
} }
#ifdef IEEE80211_CONF_CHANNEL_SWITCH
static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{ {
int rc; int rc;
u8 band = 0; u8 band = 0;
bool is_ht40 = false; bool is_ht40 = false;
u8 ctrl_chan_high = 0; u8 ctrl_chan_high = 0;
struct iwl4965_channel_switch_cmd cmd = { 0 }; struct iwl4965_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info; const struct iwl_channel_info *ch_info;
band = priv->band == IEEE80211_BAND_2GHZ; band = priv->band == IEEE80211_BAND_2GHZ;
@ -1565,8 +1460,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
if (ch_info) if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info); cmd.expect_beacon = is_channel_radar(ch_info);
else else {
cmd.expect_beacon = 1; IWL_ERR(priv, "invalid channel switch from %u to %u\n",
priv->active_rxon.channel, channel);
return -EFAULT;
}
rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
ctrl_chan_high, &cmd.tx_power); ctrl_chan_high, &cmd.tx_power);
@ -1578,7 +1476,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
return rc; return rc;
} }
#endif
/** /**
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
@ -1775,11 +1672,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo) u16 ssn_idx, u8 tx_fifo)
{ {
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
<= txq_id)) {
IWL_WARN(priv, IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n", "queue number out of range: %d, must be %d to %d\n",
txq_id, IWL49_FIRST_AMPDU_QUEUE, txq_id, IWL49_FIRST_AMPDU_QUEUE,
IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); IWL49_FIRST_AMPDU_QUEUE +
priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL; return -EINVAL;
} }
@ -1840,11 +1739,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid; u16 ra_tid;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
<= txq_id)) {
IWL_WARN(priv, IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n", "queue number out of range: %d, must be %d to %d\n",
txq_id, IWL49_FIRST_AMPDU_QUEUE, txq_id, IWL49_FIRST_AMPDU_QUEUE,
IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); IWL49_FIRST_AMPDU_QUEUE +
priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL; return -EINVAL;
} }
@ -2048,7 +1949,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl4965_rx_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence); u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence); int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
@ -2249,7 +2150,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.build_addsta_hcmd = iwl4965_build_addsta_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset, .chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation, .gain_computation = iwl4965_gain_computation,
.rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
.calc_rssi = iwl4965_calc_rssi, .calc_rssi = iwl4965_calc_rssi,
}; };
@ -2271,9 +2172,9 @@ static struct iwl_lib_ops iwl4965_lib = {
.load_ucode = iwl4965_load_bsm, .load_ucode = iwl4965_load_bsm,
.dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log, .dump_nic_error_log = iwl_dump_nic_error_log,
.set_channel_switch = iwl4965_hw_channel_switch,
.apm_ops = { .apm_ops = {
.init = iwl4965_apm_init, .init = iwl_apm_init,
.reset = iwl4965_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl4965_nic_config, .config = iwl4965_nic_config,
.set_pwr_src = iwl_set_pwr_src, .set_pwr_src = iwl_set_pwr_src,
@ -2323,7 +2224,14 @@ struct iwl_cfg iwl4965_agn_cfg = {
.eeprom_ver = EEPROM_4965_EEPROM_VERSION, .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
.ops = &iwl4965_ops, .ops = &iwl4965_ops,
.num_of_queues = IWL49_NUM_QUEUES,
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.mod_params = &iwl4965_mod_params, .mod_params = &iwl4965_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = true,
.use_isr_legacy = true, .use_isr_legacy = true,
.ht_greenfield_support = false, .ht_greenfield_support = false,
.broken_powersave = true, .broken_powersave = true,

View File

@ -72,115 +72,14 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_HCCA_2 IWL_TX_FIFO_HCCA_2
}; };
int iwl5000_apm_init(struct iwl_priv *priv)
{
int ret = 0;
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* Set FH wait threshold to maximum (HW error during stress W/A) */
iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
/* enable HAP INTA to move device L1a -> L0s */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
if (priv->cfg->need_pll_cfg)
iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
/* set "initialization complete" bit to move adapter
* D0U* --> D0A* state */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(priv, "Failed to init the card\n");
return ret;
}
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
return ret;
}
int iwl5000_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
iwl_apm_stop_master(priv);
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
/* FIXME: put here L1A -L0S w/a */
if (priv->cfg->need_pll_cfg)
iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
/* set "initialization complete" bit to move adapter
* D0U* --> D0A* state */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(priv, "Failed to init the card\n");
goto out;
}
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
out:
return ret;
}
/* NIC configuration for 5000 series */ /* NIC configuration for 5000 series */
void iwl5000_nic_config(struct iwl_priv *priv) void iwl5000_nic_config(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
u16 radio_cfg; u16 radio_cfg;
u16 lctl;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
lctl = iwl_pcie_link_ctl(priv);
/* HW bug W/A */
/* L1-ASPM is enabled by BIOS */
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
/* L1-APSM enabled: disable L0S */
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
else
/* L1-ASPM disabled: enable L0S */
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */ /* write radio config values to register */
@ -279,7 +178,7 @@ static void iwl5000_gain_computation(struct iwl_priv *priv,
data->delta_gain_code[i] = 0; data->delta_gain_code[i] = 0;
continue; continue;
} }
delta_g = (1000 * ((s32)average_noise[0] - delta_g = (1000 * ((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500; (s32)average_noise[i])) / 1500;
/* bound gain by 2 bits value max, 3rd bit is sign */ /* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] = data->delta_gain_code[i] =
@ -372,6 +271,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.auto_corr_max_cck_mrc = 400, .auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95, .nrg_th_cck = 95,
.nrg_th_ofdm = 95, .nrg_th_ofdm = 95,
.barker_corr_th_min = 190,
.barker_corr_th_min_mrc = 390,
.nrg_th_cca = 62,
}; };
static struct iwl_sensitivity_ranges iwl5150_sensitivity = { static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
@ -394,6 +297,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.auto_corr_max_cck_mrc = 400, .auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95, .nrg_th_cck = 95,
.nrg_th_ofdm = 95, .nrg_th_ofdm = 95,
.barker_corr_th_min = 190,
.barker_corr_th_min_mrc = 390,
.nrg_th_cca = 62,
}; };
const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@ -458,7 +365,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
static void iwl5000_rx_calib_result(struct iwl_priv *priv, static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
int index; int index;
@ -784,18 +691,16 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
int iwl5000_hw_set_hw_params(struct iwl_priv *priv) int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{ {
if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
IWL_ERR(priv, priv->cfg->num_of_queues =
"invalid queues_num, should be between %d and %d\n", priv->cfg->mod_params->num_of_queues;
IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
return -EINVAL;
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size = priv->hw_params.scd_bc_tbls_size =
IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->cfg->num_of_queues *
sizeof(struct iwl5000_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
@ -947,11 +852,13 @@ int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid; u16 ra_tid;
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
<= txq_id)) {
IWL_WARN(priv, IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n", "queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE, txq_id, IWL50_FIRST_AMPDU_QUEUE,
IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); IWL50_FIRST_AMPDU_QUEUE +
priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL; return -EINVAL;
} }
@ -1005,11 +912,13 @@ int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo) u16 ssn_idx, u8 tx_fifo)
{ {
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
<= txq_id)) {
IWL_ERR(priv, IWL_ERR(priv,
"queue number out of range: %d, must be %d to %d\n", "queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE, txq_id, IWL50_FIRST_AMPDU_QUEUE,
IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); IWL50_FIRST_AMPDU_QUEUE +
priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL; return -EINVAL;
} }
@ -1176,7 +1085,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl5000_rx_reply_tx(struct iwl_priv *priv, static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence); u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence); int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
@ -1473,6 +1382,36 @@ IWL5000_UCODE_GET(init_size);
IWL5000_UCODE_GET(init_data_size); IWL5000_UCODE_GET(init_data_size);
IWL5000_UCODE_GET(boot_size); IWL5000_UCODE_GET(boot_size);
static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
struct iwl5000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
.flags = CMD_SIZE_HUGE,
.data = &cmd,
};
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
cmd.rxon_flags = priv->active_rxon.flags;
cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
priv->active_rxon.channel, channel);
return -EFAULT;
}
return iwl_send_cmd_sync(priv, &hcmd);
}
struct iwl_hcmd_ops iwl5000_hcmd = { struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc, .rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon, .commit_rxon = iwl_commit_rxon,
@ -1520,9 +1459,9 @@ struct iwl_lib_ops iwl5000_lib = {
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl5000_nic_config, .config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src, .set_pwr_src = iwl_set_pwr_src,
@ -1572,9 +1511,9 @@ static struct iwl_lib_ops iwl5150_lib = {
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl5000_nic_config, .config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src, .set_pwr_src = iwl_set_pwr_src,
@ -1621,8 +1560,6 @@ static struct iwl_ops iwl5150_ops = {
}; };
struct iwl_mod_params iwl50_mod_params = { struct iwl_mod_params iwl50_mod_params = {
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1, .amsdu_size_8K = 1,
.restart_fw = 1, .restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
@ -1639,10 +1576,14 @@ struct iwl_cfg iwl5300_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC, .valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@ -1658,10 +1599,14 @@ struct iwl_cfg iwl5100_bg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B, .valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@ -1677,10 +1622,14 @@ struct iwl_cfg iwl5100_abg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B, .valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@ -1696,10 +1645,14 @@ struct iwl_cfg iwl5100_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B, .valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@ -1715,10 +1668,14 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC, .valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
@ -1734,10 +1691,14 @@ struct iwl_cfg iwl5150_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A, .valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = true, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.set_l0s = true,
.use_bsm = false,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,

View File

@ -52,8 +52,8 @@
#define IWL6050_UCODE_API_MAX 4 #define IWL6050_UCODE_API_MAX 4
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1 #define IWL6000_UCODE_API_MIN 4
#define IWL6050_UCODE_API_MIN 1 #define IWL6050_UCODE_API_MIN 4
#define IWL6000_FW_PRE "iwlwifi-6000-" #define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@ -121,22 +121,24 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
.auto_corr_max_cck_mrc = 310, .auto_corr_max_cck_mrc = 310,
.nrg_th_cck = 97, .nrg_th_cck = 97,
.nrg_th_ofdm = 100, .nrg_th_ofdm = 100,
.barker_corr_th_min = 190,
.barker_corr_th_min_mrc = 390,
.nrg_th_cca = 62,
}; };
static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
{ {
if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
IWL_ERR(priv, priv->cfg->num_of_queues =
"invalid queues_num, should be between %d and %d\n", priv->cfg->mod_params->num_of_queues;
IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
return -EINVAL;
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size = priv->hw_params.scd_bc_tbls_size =
IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->cfg->num_of_queues *
sizeof(struct iwl5000_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
@ -170,6 +172,37 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
return 0; return 0;
} }
static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
struct iwl6000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
.flags = CMD_SIZE_HUGE,
.data = &cmd,
};
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
cmd.rxon_flags = priv->active_rxon.flags;
cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
priv->active_rxon.channel, channel);
return -EFAULT;
}
return iwl_send_cmd_sync(priv, &hcmd);
}
static struct iwl_lib_ops iwl6000_lib = { static struct iwl_lib_ops iwl6000_lib = {
.set_hw_params = iwl6000_hw_set_hw_params, .set_hw_params = iwl6000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@ -190,9 +223,9 @@ static struct iwl_lib_ops iwl6000_lib = {
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags, .update_chain_flags = iwl_update_chain_flags,
.set_channel_switch = iwl6000_hw_channel_switch,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl_apm_stop, .stop = iwl_apm_stop,
.config = iwl6000_nic_config, .config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src, .set_pwr_src = iwl_set_pwr_src,
@ -231,6 +264,21 @@ static struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops, .led = &iwlagn_led_ops,
}; };
static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
.calc_rssi = iwl5000_calc_rssi,
};
static struct iwl_ops iwl6050_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6050_hcmd_utils,
.led = &iwlagn_led_ops,
};
/* /*
* "h": Hybrid configuration, use both internal and external Power Amplifier * "h": Hybrid configuration, use both internal and external Power Amplifier
@ -245,10 +293,14 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB, .valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID, .pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -257,6 +309,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
.use_rts_for_ht = true, /* use rts/cts protection */ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6000h_2abg_cfg = { struct iwl_cfg iwl6000h_2abg_cfg = {
@ -269,10 +323,14 @@ struct iwl_cfg iwl6000h_2abg_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB, .valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID, .pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -280,6 +338,8 @@ struct iwl_cfg iwl6000h_2abg_cfg = {
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6000h_2bg_cfg = { struct iwl_cfg iwl6000h_2bg_cfg = {
@ -292,10 +352,14 @@ struct iwl_cfg iwl6000h_2bg_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB, .valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID, .pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -303,6 +367,8 @@ struct iwl_cfg iwl6000h_2bg_cfg = {
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
/* /*
@ -318,10 +384,14 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC, .valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC, .valid_rx_ant = ANT_BC,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_INTERNAL, .pa_type = IWL_PA_INTERNAL,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -330,6 +400,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.use_rts_for_ht = true, /* use rts/cts protection */ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6000i_2abg_cfg = { struct iwl_cfg iwl6000i_2abg_cfg = {
@ -342,10 +414,14 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC, .valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC, .valid_rx_ant = ANT_BC,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_INTERNAL, .pa_type = IWL_PA_INTERNAL,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -353,6 +429,8 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6000i_2bg_cfg = { struct iwl_cfg iwl6000i_2bg_cfg = {
@ -365,10 +443,14 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC, .valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC, .valid_rx_ant = ANT_BC,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_INTERNAL, .pa_type = IWL_PA_INTERNAL,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -376,6 +458,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6050_2agn_cfg = { struct iwl_cfg iwl6050_2agn_cfg = {
@ -384,22 +468,28 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN, .ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops, .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB, .valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_SYSTEM, .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true, .shadow_ram_support = true,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.use_rts_for_ht = true, /* use rts/cts protection */ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6050_2abg_cfg = { struct iwl_cfg iwl6050_2abg_cfg = {
@ -408,21 +498,27 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN, .ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G, .sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl6000_ops, .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB, .valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB, .valid_rx_ant = ANT_AB,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_SYSTEM, .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true, .shadow_ram_support = true,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6000_3agn_cfg = { struct iwl_cfg iwl6000_3agn_cfg = {
@ -435,10 +531,14 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC, .valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_SYSTEM, .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true, .shadow_ram_support = true,
@ -447,6 +547,8 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.use_rts_for_ht = true, /* use rts/cts protection */ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
struct iwl_cfg iwl6050_3agn_cfg = { struct iwl_cfg iwl6050_3agn_cfg = {
@ -455,22 +557,28 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN, .ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops, .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params, .mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC, .valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC,
.need_pll_cfg = false, .pll_cfg_val = 0,
.set_l0s = false,
.use_bsm = false,
.pa_type = IWL_PA_SYSTEM, .pa_type = IWL_PA_SYSTEM,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00, .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true, .shadow_ram_support = true,
.ht_greenfield_support = true, .ht_greenfield_support = true,
.led_compensation = 51, .led_compensation = 51,
.use_rts_for_ht = true, /* use rts/cts protection */ .use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true, .supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
}; };
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));

View File

@ -75,106 +75,6 @@ static const u8 ant_toggle_lookup[] = {
/*ANT_ABC -> */ ANT_ABC, /*ANT_ABC -> */ ANT_ABC,
}; };
/**
* struct iwl_rate_scale_data -- tx success history for one rate
*/
struct iwl_rate_scale_data {
u64 data; /* bitmap of successful frames */
s32 success_counter; /* number of frames successful */
s32 success_ratio; /* per-cent * 128 */
s32 counter; /* number of frames attempted */
s32 average_tpt; /* success ratio * expected throughput */
unsigned long stamp;
};
/**
* struct iwl_scale_tbl_info -- tx params and success history for all rates
*
* There are two of these in struct iwl_lq_sta,
* one for "active", and one for "search".
*/
struct iwl_scale_tbl_info {
enum iwl_table_type lq_type;
u8 ant_type;
u8 is_SGI; /* 1 = short guard interval */
u8 is_ht40; /* 1 = 40 MHz channel width */
u8 is_dup; /* 1 = duplicated data streams */
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8 max_search; /* maximun number of tables we can search */
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
struct iwl_traffic_load {
unsigned long time_stamp; /* age of the oldest statistics */
u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
* slice */
u32 total; /* total num of packets during the
* last TID_MAX_TIME_DIFF */
u8 queue_count; /* number of queues that has
* been used since the last cleanup */
u8 head; /* start of the circular buffer */
};
/**
* struct iwl_lq_sta -- driver's rate scaling private structure
*
* Pointer to this gets passed back and forth between driver and mac80211.
*/
struct iwl_lq_sta {
u8 active_tbl; /* index of active table, range 0-1 */
u8 enable_counter; /* indicates HT mode */
u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
u8 search_better_tbl; /* 1: currently trying alternate mode */
s32 last_tpt;
/* The following determine when to search for a new mode */
u32 table_count_limit;
u32 max_failure_limit; /* # failed frames before new search */
u32 max_success_limit; /* # successful frames before new search */
u32 table_count;
u32 total_failed; /* total failed frames, any/all rates */
u32 total_success; /* total successful frames, any/all rates */
u64 flush_timer; /* time staying in mode before new search */
u8 action_counter; /* # mode-switch actions tried */
u8 is_green;
u8 is_dup;
enum ieee80211_band band;
u8 ibss_sta_added;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
u32 supp_rates;
u16 active_legacy_rate;
u16 active_siso_rate;
u16 active_mimo2_rate;
u16 active_mimo3_rate;
u16 active_rate_basic;
s8 max_rate_idx; /* Max rate set by user */
u8 missed_rate_counter;
struct iwl_link_quality_cmd lq;
struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
u8 tx_agg_tid_en;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *rs_sta_dbgfs_scale_table_file;
struct dentry *rs_sta_dbgfs_stats_table_file;
struct dentry *rs_sta_dbgfs_rate_scale_data_file;
struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
u32 dbg_fixed_rate;
#endif
struct iwl_priv *drv;
/* used to be in sta_info */
int last_txrate_idx;
/* last tx rate_n_flags */
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
u8 is_agg;
};
static void rs_rate_scale_perform(struct iwl_priv *priv, static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb, struct sk_buff *skb,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
@ -2575,19 +2475,17 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
gfp_t gfp) gfp_t gfp)
{ {
struct iwl_lq_sta *lq_sta; struct iwl_lq_sta *lq_sta;
struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
struct iwl_priv *priv; struct iwl_priv *priv;
int i, j; int i, j;
priv = (struct iwl_priv *)priv_rate; priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE(priv, "create station rate scale window\n"); IWL_DEBUG_RATE(priv, "create station rate scale window\n");
lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp); lq_sta = &sta_priv->lq_sta;
if (lq_sta == NULL)
return NULL;
lq_sta->lq.sta_id = 0xff; lq_sta->lq.sta_id = 0xff;
for (j = 0; j < LQ_SIZE; j++) for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++) for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
@ -2819,11 +2717,9 @@ static void rs_free(void *priv_rate)
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
void *priv_sta) void *priv_sta)
{ {
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv __maybe_unused = priv_r; struct iwl_priv *priv __maybe_unused = priv_r;
IWL_DEBUG_RATE(priv, "enter\n"); IWL_DEBUG_RATE(priv, "enter\n");
kfree(lq_sta);
IWL_DEBUG_RATE(priv, "leave\n"); IWL_DEBUG_RATE(priv, "leave\n");
} }

View File

@ -54,6 +54,7 @@ struct iwl3945_rate_info {
u8 prev_table_rs; /* prev in rate table cmd */ u8 prev_table_rs; /* prev in rate table cmd */
}; };
/* /*
* These serve as indexes into * These serve as indexes into
* struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
@ -335,6 +336,106 @@ struct iwl_rate_mcs_info {
char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
}; };
/**
* struct iwl_rate_scale_data -- tx success history for one rate
*/
struct iwl_rate_scale_data {
u64 data; /* bitmap of successful frames */
s32 success_counter; /* number of frames successful */
s32 success_ratio; /* per-cent * 128 */
s32 counter; /* number of frames attempted */
s32 average_tpt; /* success ratio * expected throughput */
unsigned long stamp;
};
/**
* struct iwl_scale_tbl_info -- tx params and success history for all rates
*
* There are two of these in struct iwl_lq_sta,
* one for "active", and one for "search".
*/
struct iwl_scale_tbl_info {
enum iwl_table_type lq_type;
u8 ant_type;
u8 is_SGI; /* 1 = short guard interval */
u8 is_ht40; /* 1 = 40 MHz channel width */
u8 is_dup; /* 1 = duplicated data streams */
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8 max_search; /* maximun number of tables we can search */
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
struct iwl_traffic_load {
unsigned long time_stamp; /* age of the oldest statistics */
u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
* slice */
u32 total; /* total num of packets during the
* last TID_MAX_TIME_DIFF */
u8 queue_count; /* number of queues that has
* been used since the last cleanup */
u8 head; /* start of the circular buffer */
};
/**
* struct iwl_lq_sta -- driver's rate scaling private structure
*
* Pointer to this gets passed back and forth between driver and mac80211.
*/
struct iwl_lq_sta {
u8 active_tbl; /* index of active table, range 0-1 */
u8 enable_counter; /* indicates HT mode */
u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
u8 search_better_tbl; /* 1: currently trying alternate mode */
s32 last_tpt;
/* The following determine when to search for a new mode */
u32 table_count_limit;
u32 max_failure_limit; /* # failed frames before new search */
u32 max_success_limit; /* # successful frames before new search */
u32 table_count;
u32 total_failed; /* total failed frames, any/all rates */
u32 total_success; /* total successful frames, any/all rates */
u64 flush_timer; /* time staying in mode before new search */
u8 action_counter; /* # mode-switch actions tried */
u8 is_green;
u8 is_dup;
enum ieee80211_band band;
u8 ibss_sta_added;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
u32 supp_rates;
u16 active_legacy_rate;
u16 active_siso_rate;
u16 active_mimo2_rate;
u16 active_mimo3_rate;
u16 active_rate_basic;
s8 max_rate_idx; /* Max rate set by user */
u8 missed_rate_counter;
struct iwl_link_quality_cmd lq;
struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
u8 tx_agg_tid_en;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *rs_sta_dbgfs_scale_table_file;
struct dentry *rs_sta_dbgfs_stats_table_file;
struct dentry *rs_sta_dbgfs_rate_scale_data_file;
struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
u32 dbg_fixed_rate;
#endif
struct iwl_priv *drv;
/* used to be in sta_info */
int last_txrate_idx;
/* last tx rate_n_flags */
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
u8 is_agg;
};
static inline u8 num_of_ant(u8 mask) static inline u8 num_of_ant(u8 mask)
{ {
return !!((mask) & ANT_A) + return !!((mask) & ANT_A) +

View File

@ -524,7 +524,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
static void iwl_rx_reply_alive(struct iwl_priv *priv, static void iwl_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive; struct iwl_alive_resp *palive;
struct delayed_work *pwork; struct delayed_work *pwork;
@ -610,7 +610,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl4965_beacon_notif *beacon = struct iwl4965_beacon_notif *beacon =
(struct iwl4965_beacon_notif *)pkt->u.raw; (struct iwl4965_beacon_notif *)pkt->u.raw;
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
@ -634,7 +634,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
static void iwl_rx_card_state_notif(struct iwl_priv *priv, static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status; unsigned long status = priv->status;
@ -769,7 +769,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
/* calculate total frames need to be restock after handling RX */ /* calculate total frames need to be restock after handling RX */
total_empty = r - priv->rxq.write_actual; total_empty = r - rxq->write_actual;
if (total_empty < 0) if (total_empty < 0)
total_empty += RX_QUEUE_SIZE; total_empty += RX_QUEUE_SIZE;
@ -786,10 +786,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL; rxq->queue[i] = NULL;
pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, pci_unmap_page(priv->pci_dev, rxb->page_dma,
priv->hw_params.rx_buf_size + 256, PAGE_SIZE << priv->hw_params.rx_page_order,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
pkt = (struct iwl_rx_packet *)rxb->skb->data; pkt = rxb_addr(rxb);
trace_iwlwifi_dev_rx(priv, pkt, trace_iwlwifi_dev_rx(priv, pkt,
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
@ -814,8 +814,8 @@ void iwl_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) { if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r,
i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else { } else {
/* No handling needed */ /* No handling needed */
IWL_DEBUG_RX(priv, IWL_DEBUG_RX(priv,
@ -824,35 +824,45 @@ void iwl_rx_handle(struct iwl_priv *priv)
pkt->hdr.cmd); pkt->hdr.cmd);
} }
/*
* XXX: After here, we should always check rxb->page
* against NULL before touching it or its virtual
* memory (pkt). Because some rx_handler might have
* already taken or freed the pages.
*/
if (reclaim) { if (reclaim) {
/* Invoke any callbacks, transfer the skb to caller, and /* Invoke any callbacks, transfer the buffer to caller,
* fire off the (possibly) blocking iwl_send_cmd() * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */ * as we reclaim the driver command queue */
if (rxb && rxb->skb) if (rxb->page)
iwl_tx_cmd_complete(priv, rxb); iwl_tx_cmd_complete(priv, rxb);
else else
IWL_WARN(priv, "Claim null rxb?\n"); IWL_WARN(priv, "Claim null rxb?\n");
} }
/* For now we just don't re-use anything. We can tweak this /* Reuse the page if possible. For notification packets and
* later to try and re-use notification packets and SKBs that * SKBs that fail to Rx correctly, add them back into the
* fail to Rx correctly */ * rx_free list for reuse later. */
if (rxb->skb != NULL) {
priv->alloc_rxb_skb--;
dev_kfree_skb_any(rxb->skb);
rxb->skb = NULL;
}
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &priv->rxq.rx_used); if (rxb->page != NULL) {
rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
0, PAGE_SIZE << priv->hw_params.rx_page_order,
PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
} else
list_add_tail(&rxb->list, &rxq->rx_used);
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
i = (i + 1) & RX_QUEUE_MASK; i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames, /* If there are a lot of unused frames,
* restock the Rx queue so ucode wont assert. */ * restock the Rx queue so ucode wont assert. */
if (fill_rx) { if (fill_rx) {
count++; count++;
if (count >= 8) { if (count >= 8) {
priv->rxq.read = i; rxq->read = i;
iwl_rx_replenish_now(priv); iwl_rx_replenish_now(priv);
count = 0; count = 0;
} }
@ -860,7 +870,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
} }
/* Backtrack one entry */ /* Backtrack one entry */
priv->rxq.read = i; rxq->read = i;
if (fill_rx) if (fill_rx)
iwl_rx_replenish_now(priv); iwl_rx_replenish_now(priv);
else else
@ -907,6 +917,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that * atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after * we've discovered, even if FH interrupt came in just after
@ -928,8 +940,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR; handled |= CSR_INT_BIT_HW_ERR;
spin_unlock_irqrestore(&priv->lock, flags);
return; return;
} }
@ -1019,6 +1029,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
iwl_rx_handle(priv); iwl_rx_handle(priv);
priv->isr_stats.rx++; priv->isr_stats.rx++;
iwl_leds_background(priv);
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
} }
@ -1056,7 +1067,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
} }
/* tasklet for iwlagn interrupt */ /* tasklet for iwlagn interrupt */
@ -1086,6 +1096,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta, inta_mask); inta, inta_mask);
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
/* saved interrupt in inta variable now we can reset priv->inta */ /* saved interrupt in inta variable now we can reset priv->inta */
priv->inta = 0; priv->inta = 0;
@ -1101,8 +1114,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR; handled |= CSR_INT_BIT_HW_ERR;
spin_unlock_irqrestore(&priv->lock, flags);
return; return;
} }
@ -1220,6 +1231,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_INT_PERIODIC_ENA); CSR_INT_PERIODIC_ENA);
priv->isr_stats.rx++; priv->isr_stats.rx++;
iwl_leds_background(priv);
} }
if (inta & CSR_INT_BIT_FH_TX) { if (inta & CSR_INT_BIT_FH_TX) {
@ -1242,14 +1254,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta & ~priv->inta_mask); inta & ~priv->inta_mask);
} }
/* Re-enable all interrupts */ /* Re-enable all interrupts */
/* only Re-enable if diabled by irq */ /* only Re-enable if diabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status)) if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_enable_interrupts(priv); iwl_enable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
} }
@ -1899,11 +1907,9 @@ static void __iwl_down(struct iwl_priv *priv)
udelay(5); udelay(5);
/* FIXME: apm_ops.suspend(priv) */ /* Stop the device, and put it in low power state */
if (exit_pending) priv->cfg->ops->lib->apm_ops.stop(priv);
priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv);
exit: exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@ -2290,6 +2296,69 @@ void iwl_post_associate(struct iwl_priv *priv)
#define UCODE_READY_TIMEOUT (4 * HZ) #define UCODE_READY_TIMEOUT (4 * HZ)
/*
* Not a mac80211 entry point function, but it fits in with all the
* other mac80211 functions grouped here.
*/
static int iwl_setup_mac(struct iwl_priv *priv)
{
int ret;
struct ieee80211_hw *hw = priv->hw;
hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_SPECTRUM_MGMT;
if (!priv->cfg->broken_powersave)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->custom_regulatory = true;
/* Firmware does not support this */
hw->wiphy->disable_beacon_hints = true;
/*
* For now, disable PS by default because it affects
* RX performance significantly.
*/
hw->wiphy->ps_default = false;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->bands[IEEE80211_BAND_2GHZ];
if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&priv->bands[IEEE80211_BAND_5GHZ];
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
return ret;
}
priv->mac80211_registered = 1;
return 0;
}
static int iwl_mac_start(struct ieee80211_hw *hw) static int iwl_mac_start(struct ieee80211_hw *hw)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
@ -3187,6 +3256,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv); iwl_down(priv);
} }
/*
* Make sure device is reset to low power before unloading driver.
* This may be redundant with iwl_down(), but there are paths to
* run iwl_down() without calling apm_ops.stop(), and there are
* paths to avoid running iwl_down() at all before leaving driver.
* This (inexpensive) call *makes sure* device is reset.
*/
priv->cfg->ops->lib->apm_ops.stop(priv);
iwl_tt_exit(priv); iwl_tt_exit(priv);
/* make sure we flush any pending irq or /* make sure we flush any pending irq or

View File

@ -447,11 +447,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
cpu_to_le16((u16)data->nrg_th_ofdm); cpu_to_le16((u16)data->nrg_th_ofdm);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
cpu_to_le16(190); cpu_to_le16(data->barker_corr_th_min);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16(390); cpu_to_le16(data->barker_corr_th_min_mrc);
cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
cpu_to_le16(62); cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
@ -524,6 +524,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc; data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
data->nrg_th_cck = ranges->nrg_th_cck; data->nrg_th_cck = ranges->nrg_th_cck;
data->nrg_th_ofdm = ranges->nrg_th_ofdm; data->nrg_th_ofdm = ranges->nrg_th_ofdm;
data->barker_corr_th_min = ranges->barker_corr_th_min;
data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
data->nrg_th_cca = ranges->nrg_th_cca;
data->last_bad_plcp_cnt_ofdm = 0; data->last_bad_plcp_cnt_ofdm = 0;
data->last_fa_cnt_ofdm = 0; data->last_fa_cnt_ofdm = 0;

View File

@ -109,11 +109,12 @@ enum {
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
/* WiMAX coexistence */ /* WiMAX coexistence */
COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */
COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_MEDIUM_NOTIFICATION = 0x5b,
COEX_EVENT_CMD = 0x5c, COEX_EVENT_CMD = 0x5c,
/* Calibration */ /* Calibration */
TEMPERATURE_NOTIFICATION = 0x62,
CALIBRATION_CFG_CMD = 0x65, CALIBRATION_CFG_CMD = 0x65,
CALIBRATION_RES_NOTIFICATION = 0x66, CALIBRATION_RES_NOTIFICATION = 0x66,
CALIBRATION_COMPLETE_NOTIFICATION = 0x67, CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
@ -353,6 +354,9 @@ struct iwl3945_power_per_rate {
#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
#define POWER_TABLE_CCK_ENTRY 32 #define POWER_TABLE_CCK_ENTRY 32
#define IWL_PWR_NUM_HT_OFDM_ENTRIES 24
#define IWL_PWR_CCK_ENTRIES 2
/** /**
* union iwl4965_tx_power_dual_stream * union iwl4965_tx_power_dual_stream
* *
@ -803,7 +807,7 @@ struct iwl3945_channel_switch_cmd {
struct iwl3945_power_per_rate power[IWL_MAX_RATES]; struct iwl3945_power_per_rate power[IWL_MAX_RATES];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct iwl_channel_switch_cmd { struct iwl4965_channel_switch_cmd {
u8 band; u8 band;
u8 expect_beacon; u8 expect_beacon;
__le16 channel; __le16 channel;
@ -813,6 +817,48 @@ struct iwl_channel_switch_cmd {
struct iwl4965_tx_power_db tx_power; struct iwl4965_tx_power_db tx_power;
} __attribute__ ((packed)); } __attribute__ ((packed));
/**
* struct iwl5000_channel_switch_cmd
* @band: 0- 5.2GHz, 1- 2.4GHz
* @expect_beacon: 0- resume transmits after channel switch
* 1- wait for beacon to resume transmits
* @channel: new channel number
* @rxon_flags: Rx on flags
* @rxon_filter_flags: filtering parameters
* @switch_time: switch time in extended beacon format
* @reserved: reserved bytes
*/
struct iwl5000_channel_switch_cmd {
u8 band;
u8 expect_beacon;
__le16 channel;
__le32 rxon_flags;
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
} __attribute__ ((packed));
/**
* struct iwl6000_channel_switch_cmd
* @band: 0- 5.2GHz, 1- 2.4GHz
* @expect_beacon: 0- resume transmits after channel switch
* 1- wait for beacon to resume transmits
* @channel: new channel number
* @rxon_flags: Rx on flags
* @rxon_filter_flags: filtering parameters
* @switch_time: switch time in extended beacon format
* @reserved: reserved bytes
*/
struct iwl6000_channel_switch_cmd {
u8 band;
u8 expect_beacon;
__le16 channel;
__le32 rxon_flags;
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
} __attribute__ ((packed));
/* /*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
*/ */
@ -2172,6 +2218,19 @@ struct iwl_link_quality_cmd {
__le32 reserved2; __le32 reserved2;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define BT_COEX_DISABLE (0x0)
#define BT_COEX_MODE_2W (0x1)
#define BT_COEX_MODE_3W (0x2)
#define BT_COEX_MODE_4W (0x3)
#define BT_LEAD_TIME_MIN (0x0)
#define BT_LEAD_TIME_DEF (0x1E)
#define BT_LEAD_TIME_MAX (0xFF)
#define BT_MAX_KILL_MIN (0x1)
#define BT_MAX_KILL_DEF (0x5)
#define BT_MAX_KILL_MAX (0xFF)
/* /*
* REPLY_BT_CONFIG = 0x9b (command, has simple generic response) * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
* *
@ -3247,12 +3306,6 @@ struct iwl_missed_beacon_notif {
* Lower values mean higher energy; this means making sure that the value * Lower values mean higher energy; this means making sure that the value
* in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
* *
* Driver should set the following entries to fixed values:
*
* HD_MIN_ENERGY_OFDM_DET_INDEX 100
* HD_BARKER_CORR_TH_ADD_MIN_INDEX 190
* HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390
* HD_OFDM_ENERGY_TH_IN_INDEX 62
*/ */
/* /*
@ -3505,6 +3558,16 @@ struct iwl_wimax_coex_cmd {
*****************************************************************************/ *****************************************************************************/
struct iwl_rx_packet { struct iwl_rx_packet {
/*
* The first 4 bytes of the RX frame header contain both the RX frame
* size and some flags.
* Bit fields:
* 31: flag flush RB request
* 30: flag ignore TC (terminal counter) request
* 29: flag fast IRQ request
* 28-14: Reserved
* 13-00: RX frame size
*/
__le32 len_n_flags; __le32 len_n_flags;
struct iwl_cmd_header hdr; struct iwl_cmd_header hdr;
union { union {

View File

@ -604,6 +604,23 @@ void iwlcore_free_geos(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwlcore_free_geos); EXPORT_SYMBOL(iwlcore_free_geos);
/*
* iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
* function.
*/
void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags)
{
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
*tx_flags |= TX_CMD_FLG_RTS_MSK;
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
} else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
*tx_flags |= TX_CMD_FLG_CTS_MSK;
}
}
EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
static bool is_single_rx_stream(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv)
{ {
return !priv->current_ht_config.is_ht || return !priv->current_ht_config.is_ht ||
@ -1264,13 +1281,18 @@ static void iwl_set_rate(struct iwl_priv *priv)
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl_csa_notification *csa = &(pkt->u.csa_notif); struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n",
le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); if (!le32_to_cpu(csa->status)) {
rxon->channel = csa->channel; rxon->channel = csa->channel;
priv->staging_rxon.channel = csa->channel; priv->staging_rxon.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
} else
IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
le16_to_cpu(csa->channel));
} }
EXPORT_SYMBOL(iwl_rx_csa); EXPORT_SYMBOL(iwl_rx_csa);
@ -1352,6 +1374,8 @@ void iwl_apm_stop(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
iwl_apm_stop_master(priv); iwl_apm_stop_master(priv);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
@ -1365,6 +1389,118 @@ void iwl_apm_stop(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwl_apm_stop); EXPORT_SYMBOL(iwl_apm_stop);
/*
* Start up NIC's basic functionality after it has been reset
* (e.g. after platform boot, or shutdown via iwl_apm_stop())
* NOTE: This does not load uCode nor start the embedded processor
*/
int iwl_apm_init(struct iwl_priv *priv)
{
int ret = 0;
u16 lctl;
IWL_DEBUG_INFO(priv, "Init card's basic functions\n");
/*
* Use "set_bit" below rather than "write", to preserve any hardware
* bits already set by default after reset.
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/*
* Disable L0s without affecting L1;
* don't wait for ICH L0s (ICH bug W/A)
*/
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* Set FH wait threshold to maximum (HW error during stress W/A) */
iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
/*
* Enable HAP INTA (interrupt from management bus) to
* wake device's PCI Express link L1a -> L0s
* NOTE: This is no-op for 3945 (non-existant bit)
*/
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
/*
* HW bug W/A - costs negligible power consumption ...
* Check if BIOS (or OS) enabled L1-ASPM on this device
*/
if (priv->cfg->set_l0s) {
lctl = iwl_pcie_link_ctl(priv);
if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
PCI_CFG_LINK_CTRL_VAL_L1_EN) {
/* L1-ASPM enabled; disable(!) L0S */
iwl_set_bit(priv, CSR_GIO_REG,
CSR_GIO_REG_VAL_L0S_ENABLED);
IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
} else {
/* L1-ASPM disabled; enable(!) L0S */
iwl_clear_bit(priv, CSR_GIO_REG,
CSR_GIO_REG_VAL_L0S_ENABLED);
IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
}
}
/* Configure analog phase-lock-loop before activating to D0A */
if (priv->cfg->pll_cfg_val)
iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val);
/*
* Set "initialization complete" bit to move adapter from
* D0U* --> D0A* (powered-up active) state.
*/
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/*
* Wait for clock stabilization; once stabilized, access to
* device-internal resources is supported, e.g. iwl_write_prph()
* and accesses to uCode SRAM.
*/
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(priv, "Failed to init the card\n");
goto out;
}
/*
* Enable DMA and BSM (if used) clocks, wait for them to stabilize.
* BSM (Boostrap State Machine) is only in 3945 and 4965;
* later devices (i.e. 5000 and later) have non-volatile SRAM,
* and don't need BSM to restore data after power-saving sleep.
*
* Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
* do not disable clocks. This preserves any hardware bits already
* set by default in "CLK_CTRL_REG" after reset.
*/
if (priv->cfg->use_bsm)
iwl_write_prph(priv, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
else
iwl_write_prph(priv, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* Disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
out:
return ret;
}
EXPORT_SYMBOL(iwl_apm_init);
void iwl_configure_filter(struct ieee80211_hw *hw, void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags, unsigned int changed_flags,
unsigned int *total_flags, unsigned int *total_flags,
@ -1412,73 +1548,14 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL(iwl_configure_filter); EXPORT_SYMBOL(iwl_configure_filter);
int iwl_setup_mac(struct iwl_priv *priv)
{
int ret;
struct ieee80211_hw *hw = priv->hw;
hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_SPECTRUM_MGMT;
if (!priv->cfg->broken_powersave)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->custom_regulatory = true;
/* Firmware does not support this */
hw->wiphy->disable_beacon_hints = true;
/*
* For now, disable PS by default because it affects
* RX performance significantly.
*/
hw->wiphy->ps_default = false;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->bands[IEEE80211_BAND_2GHZ];
if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&priv->bands[IEEE80211_BAND_5GHZ];
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
return ret;
}
priv->mac80211_registered = 1;
return 0;
}
EXPORT_SYMBOL(iwl_setup_mac);
int iwl_set_hw_params(struct iwl_priv *priv) int iwl_set_hw_params(struct iwl_priv *priv)
{ {
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K) if (priv->cfg->mod_params->amsdu_size_8K)
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
else else
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
@ -1507,7 +1584,6 @@ int iwl_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */ /* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv); iwl_clear_stations_table(priv);
priv->data_retry_limit = -1;
priv->ieee_channels = NULL; priv->ieee_channels = NULL;
priv->ieee_rates = NULL; priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ; priv->band = IEEE80211_BAND_2GHZ;
@ -1932,9 +2008,9 @@ EXPORT_SYMBOL(iwl_isr_legacy);
int iwl_send_bt_config(struct iwl_priv *priv) int iwl_send_bt_config(struct iwl_priv *priv)
{ {
struct iwl_bt_cmd bt_cmd = { struct iwl_bt_cmd bt_cmd = {
.flags = 3, .flags = BT_COEX_MODE_4W,
.lead_time = 0xAA, .lead_time = BT_LEAD_TIME_DEF,
.max_kill = 1, .max_kill = BT_MAX_KILL_DEF,
.kill_ack_mask = 0, .kill_ack_mask = 0,
.kill_cts_mask = 0, .kill_cts_mask = 0,
}; };
@ -2094,10 +2170,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
priv->thermal_throttle.ct_kill_toggle = false; priv->thermal_throttle.ct_kill_toggle = false;
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { if (priv->cfg->support_ct_kill_exit) {
case CSR_HW_REV_TYPE_1000:
case CSR_HW_REV_TYPE_6x00:
case CSR_HW_REV_TYPE_6x50:
adv_cmd.critical_temperature_enter = adv_cmd.critical_temperature_enter =
cpu_to_le32(priv->hw_params.ct_kill_threshold); cpu_to_le32(priv->hw_params.ct_kill_threshold);
adv_cmd.critical_temperature_exit = adv_cmd.critical_temperature_exit =
@ -2114,8 +2187,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"exit is %d\n", "exit is %d\n",
priv->hw_params.ct_kill_threshold, priv->hw_params.ct_kill_threshold,
priv->hw_params.ct_kill_exit_threshold); priv->hw_params.ct_kill_exit_threshold);
break; } else {
default:
cmd.critical_temperature_R = cmd.critical_temperature_R =
cpu_to_le32(priv->hw_params.ct_kill_threshold); cpu_to_le32(priv->hw_params.ct_kill_threshold);
@ -2128,7 +2200,6 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"succeeded, " "succeeded, "
"critical temperature is %d\n", "critical temperature is %d\n",
priv->hw_params.ct_kill_threshold); priv->hw_params.ct_kill_threshold);
break;
} }
} }
EXPORT_SYMBOL(iwl_rf_kill_ct_config); EXPORT_SYMBOL(iwl_rf_kill_ct_config);
@ -2160,7 +2231,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src); sleep->pm_sleep_mode, sleep->pm_wakeup_src);
@ -2171,7 +2242,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n", len, "notification for %s:\n", len,
@ -2183,7 +2254,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
void iwl_rx_reply_error(struct iwl_priv *priv, void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
"seq 0x%04X ser 0x%08X\n", "seq 0x%04X ser 0x%08X\n",
@ -2648,6 +2719,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
goto set_ch_out; goto set_ch_out;
} }
if (iwl_is_associated(priv) &&
(le16_to_cpu(priv->active_rxon.channel) != ch) &&
priv->cfg->ops->lib->set_channel_switch) {
ret = priv->cfg->ops->lib->set_channel_switch(priv,
ch);
goto out;
}
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
/* Configure HT40 channels */ /* Configure HT40 channels */
@ -2826,6 +2905,27 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
} }
EXPORT_SYMBOL(iwl_mac_reset_tsf); EXPORT_SYMBOL(iwl_mac_reset_tsf);
int iwl_alloc_txq_mem(struct iwl_priv *priv)
{
if (!priv->txq)
priv->txq = kzalloc(
sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
GFP_KERNEL);
if (!priv->txq) {
IWL_ERR(priv, "Not enough memory for txq \n");
return -ENOMEM;
}
return 0;
}
EXPORT_SYMBOL(iwl_alloc_txq_mem);
void iwl_free_txq_mem(struct iwl_priv *priv)
{
kfree(priv->txq);
priv->txq = NULL;
}
EXPORT_SYMBOL(iwl_free_txq_mem);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)

View File

@ -109,7 +109,6 @@ struct iwl_hcmd_utils_ops {
struct iwl_apm_ops { struct iwl_apm_ops {
int (*init)(struct iwl_priv *priv); int (*init)(struct iwl_priv *priv);
int (*reset)(struct iwl_priv *priv);
void (*stop)(struct iwl_priv *priv); void (*stop)(struct iwl_priv *priv);
void (*config)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv);
int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
@ -170,6 +169,7 @@ struct iwl_lib_ops {
int (*load_ucode)(struct iwl_priv *priv); int (*load_ucode)(struct iwl_priv *priv);
void (*dump_nic_event_log)(struct iwl_priv *priv); void (*dump_nic_event_log)(struct iwl_priv *priv);
void (*dump_nic_error_log)(struct iwl_priv *priv); void (*dump_nic_error_log)(struct iwl_priv *priv);
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
/* power management */ /* power management */
struct iwl_apm_ops apm_ops; struct iwl_apm_ops apm_ops;
@ -205,7 +205,6 @@ struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */ int sw_crypto; /* def: 0 = using hardware encryption */
int disable_hw_scan; /* def: 0 = use h/w scan */ int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */ int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
int disable_11n; /* def: 0 = 11n capabilities enabled */ int disable_11n; /* def: 0 = 11n capabilities enabled */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */ int antenna; /* def: 0 = both antennas (use diversity) */
@ -227,6 +226,8 @@ struct iwl_mod_params {
* The detail algorithm is described in iwl-led.c * The detail algorithm is described in iwl-led.c
* @use_rts_for_ht: use rts/cts protection for HT traffic * @use_rts_for_ht: use rts/cts protection for HT traffic
* @chain_noise_num_beacons: number of beacons used to compute chain noise * @chain_noise_num_beacons: number of beacons used to compute chain noise
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
* *
* We enable the driver to be backward compatible wrt API version. The * We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the * driver specifies which APIs it supports (with @ucode_api_max being the
@ -258,11 +259,18 @@ struct iwl_cfg {
int eeprom_size; int eeprom_size;
u16 eeprom_ver; u16 eeprom_ver;
u16 eeprom_calib_ver; u16 eeprom_calib_ver;
int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
const struct iwl_ops *ops; const struct iwl_ops *ops;
const struct iwl_mod_params *mod_params; const struct iwl_mod_params *mod_params;
u8 valid_tx_ant; u8 valid_tx_ant;
u8 valid_rx_ant; u8 valid_rx_ant;
bool need_pll_cfg;
/* for iwl_apm_init() */
u32 pll_cfg_val;
bool set_l0s;
bool use_bsm;
bool use_isr_legacy; bool use_isr_legacy;
enum iwl_pa_type pa_type; enum iwl_pa_type pa_type;
const u16 max_ll_items; const u16 max_ll_items;
@ -273,6 +281,8 @@ struct iwl_cfg {
bool use_rts_for_ht; bool use_rts_for_ht;
int chain_noise_num_beacons; int chain_noise_num_beacons;
const bool supports_idle; const bool supports_idle;
bool adv_thermal_throttle;
bool support_ct_kill_exit;
}; };
/*************************** /***************************
@ -305,7 +315,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags, unsigned int changed_flags,
unsigned int *total_flags, u64 multicast); unsigned int *total_flags, u64 multicast);
int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_hw_nic_init(struct iwl_priv *priv);
int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv);
@ -327,6 +336,10 @@ void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats); struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw); void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
int iwl_alloc_txq_mem(struct iwl_priv *priv);
void iwl_free_txq_mem(struct iwl_priv *priv);
void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv); int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv);
@ -527,7 +540,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data, const void *data,
void (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb)); struct iwl_rx_packet *pkt));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
@ -660,6 +673,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb); struct iwl_rx_mem_buffer *rxb);
void iwl_apm_stop(struct iwl_priv *priv); void iwl_apm_stop(struct iwl_priv *priv);
int iwl_apm_stop_master(struct iwl_priv *priv); int iwl_apm_stop_master(struct iwl_priv *priv);
int iwl_apm_init(struct iwl_priv *priv);
void iwl_setup_rxon_timing(struct iwl_priv *priv); void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)

View File

@ -109,8 +109,9 @@
* Bit fields: * Bit fields:
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
*/ */
#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) #define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
/* Bits for CSR_HW_IF_CONFIG_REG */ /* Bits for CSR_HW_IF_CONFIG_REG */
#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
@ -195,6 +196,7 @@
#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
/* GP (general purpose) CONTROL */ /* GP (general purpose) CONTROL */
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
@ -235,6 +237,11 @@
#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
/* EEPROM signature */ /* EEPROM signature */
#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) #define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)

View File

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

View File

@ -801,15 +801,20 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
* valid here. However, let's not confuse them and present * valid here. However, let's not confuse them and present
* IWL_POWER_INDEX_1 as "1", not "0". * IWL_POWER_INDEX_1 as "1", not "0".
*/ */
if (value > 0) if (value == 0)
return -EINVAL;
else if (value > 0)
value -= 1; value -= 1;
if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
return -EINVAL; return -EINVAL;
if (!iwl_is_ready_rf(priv))
return -EAGAIN;
priv->power_data.debug_sleep_level_override = value; priv->power_data.debug_sleep_level_override = value;
iwl_power_update_mode(priv, false); iwl_power_update_mode(priv, true);
return count; return count;
} }
@ -882,10 +887,14 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
struct iwl_rx_queue *rxq = &priv->rxq; struct iwl_rx_queue *rxq = &priv->rxq;
char *buf; char *buf;
int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
(IWL_MAX_NUM_QUEUES * 32 * 8) + 400; (priv->cfg->num_of_queues * 32 * 8) + 400;
const u8 *ptr; const u8 *ptr;
ssize_t ret; ssize_t ret;
if (!priv->txq) {
IWL_ERR(priv, "txq not ready\n");
return -EAGAIN;
}
buf = kzalloc(bufsz, GFP_KERNEL); buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) { if (!buf) {
IWL_ERR(priv, "Can not allocate buffer\n"); IWL_ERR(priv, "Can not allocate buffer\n");
@ -977,8 +986,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
int pos = 0; int pos = 0;
int cnt; int cnt;
int ret; int ret;
const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues;
if (!priv->txq) {
IWL_ERR(priv, "txq not ready\n");
return -EAGAIN;
}
buf = kzalloc(bufsz, GFP_KERNEL); buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -1069,10 +1082,10 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
sizeof(struct statistics_rx_non_phy) * 20 + sizeof(struct statistics_rx_non_phy) * 20 +
sizeof(struct statistics_rx_ht_phy) * 20 + 400; sizeof(struct statistics_rx_ht_phy) * 20 + 400;
ssize_t ret; ssize_t ret;
struct statistics_rx_phy *ofdm; struct statistics_rx_phy *ofdm, *accum_ofdm;
struct statistics_rx_phy *cck; struct statistics_rx_phy *cck, *accum_cck;
struct statistics_rx_non_phy *general; struct statistics_rx_non_phy *general, *accum_general;
struct statistics_rx_ht_phy *ht; struct statistics_rx_ht_phy *ht, *accum_ht;
if (!iwl_is_alive(priv)) if (!iwl_is_alive(priv))
return -EAGAIN; return -EAGAIN;
@ -1101,155 +1114,268 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
cck = &priv->statistics.rx.cck; cck = &priv->statistics.rx.cck;
general = &priv->statistics.rx.general; general = &priv->statistics.rx.general;
ht = &priv->statistics.rx.ofdm_ht; ht = &priv->statistics.rx.ofdm_ht;
accum_ofdm = &priv->accum_statistics.rx.ofdm;
accum_cck = &priv->accum_statistics.rx.cck;
accum_general = &priv->accum_statistics.rx.general;
accum_ht = &priv->accum_statistics.rx.ofdm_ht;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
le32_to_cpu(ofdm->ina_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
le32_to_cpu(ofdm->fina_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
le32_to_cpu(ofdm->plcp_err));
pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
le32_to_cpu(ofdm->crc32_err));
pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
le32_to_cpu(ofdm->overrun_err));
pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
le32_to_cpu(ofdm->early_overrun_err));
pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
le32_to_cpu(ofdm->crc32_good));
pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
le32_to_cpu(ofdm->false_alarm_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
le32_to_cpu(ofdm->fina_sync_err_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
le32_to_cpu(ofdm->sfd_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
le32_to_cpu(ofdm->fina_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
le32_to_cpu(ofdm->unresponded_rts));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"rxe_frame_limit_overrun: %u\n", "\t\t\tcurrent\t\t\taccumulative\n");
le32_to_cpu(ofdm->rxe_frame_limit_overrun)); pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt);
le32_to_cpu(ofdm->sent_ack_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt);
le32_to_cpu(ofdm->sent_cts_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err);
le32_to_cpu(ofdm->sent_ba_rsp_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err);
le32_to_cpu(ofdm->dsp_self_kill)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", "overrun_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->mh_format_err)); le32_to_cpu(ofdm->overrun_err),
pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", accum_ofdm->overrun_err);
le32_to_cpu(ofdm->re_acq_main_rssi_sum)); pos += scnprintf(buf + pos, bufsz - pos,
"early_overrun_err:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->early_overrun_err),
accum_ofdm->early_overrun_err);
pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->crc32_good),
accum_ofdm->crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
"false_alarm_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->false_alarm_cnt),
accum_ofdm->false_alarm_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"fina_sync_err_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->fina_sync_err_cnt),
accum_ofdm->fina_sync_err_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sfd_timeout:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->sfd_timeout),
accum_ofdm->sfd_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
"fina_timeout:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->fina_timeout),
accum_ofdm->fina_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
"unresponded_rts:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->unresponded_rts),
accum_ofdm->unresponded_rts);
pos += scnprintf(buf + pos, bufsz - pos,
"rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->rxe_frame_limit_overrun),
accum_ofdm->rxe_frame_limit_overrun);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_ack_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->sent_ack_cnt),
accum_ofdm->sent_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_cts_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->sent_cts_cnt),
accum_ofdm->sent_cts_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->sent_ba_rsp_cnt),
accum_ofdm->sent_ba_rsp_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"dsp_self_kill:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->dsp_self_kill),
accum_ofdm->dsp_self_kill);
pos += scnprintf(buf + pos, bufsz - pos,
"mh_format_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->mh_format_err),
accum_ofdm->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
"re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
le32_to_cpu(ofdm->re_acq_main_rssi_sum),
accum_ofdm->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
le32_to_cpu(cck->ina_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
le32_to_cpu(cck->fina_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
le32_to_cpu(cck->plcp_err));
pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
le32_to_cpu(cck->crc32_err));
pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
le32_to_cpu(cck->overrun_err));
pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
le32_to_cpu(cck->early_overrun_err));
pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
le32_to_cpu(cck->crc32_good));
pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
le32_to_cpu(cck->false_alarm_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
le32_to_cpu(cck->fina_sync_err_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
le32_to_cpu(cck->sfd_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
le32_to_cpu(cck->fina_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
le32_to_cpu(cck->unresponded_rts));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"rxe_frame_limit_overrun: %u\n", "\t\t\tcurrent\t\t\taccumulative\n");
le32_to_cpu(cck->rxe_frame_limit_overrun)); pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt);
le32_to_cpu(cck->sent_ack_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt);
le32_to_cpu(cck->sent_cts_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", le32_to_cpu(cck->plcp_err), accum_cck->plcp_err);
le32_to_cpu(cck->sent_ba_rsp_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", le32_to_cpu(cck->crc32_err), accum_cck->crc32_err);
le32_to_cpu(cck->dsp_self_kill)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", "overrun_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->mh_format_err)); le32_to_cpu(cck->overrun_err),
pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", accum_cck->overrun_err);
le32_to_cpu(cck->re_acq_main_rssi_sum)); pos += scnprintf(buf + pos, bufsz - pos,
"early_overrun_err:\t%u\t\t\t%u\n",
le32_to_cpu(cck->early_overrun_err),
accum_cck->early_overrun_err);
pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->crc32_good), accum_cck->crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
"false_alarm_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(cck->false_alarm_cnt),
accum_cck->false_alarm_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"fina_sync_err_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(cck->fina_sync_err_cnt),
accum_cck->fina_sync_err_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sfd_timeout:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->sfd_timeout),
accum_cck->sfd_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
"fina_timeout:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->fina_timeout),
accum_cck->fina_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
"unresponded_rts:\t%u\t\t\t%u\n",
le32_to_cpu(cck->unresponded_rts),
accum_cck->unresponded_rts);
pos += scnprintf(buf + pos, bufsz - pos,
"rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
le32_to_cpu(cck->rxe_frame_limit_overrun),
accum_cck->rxe_frame_limit_overrun);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_ack_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->sent_ack_cnt),
accum_cck->sent_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_cts_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->sent_cts_cnt),
accum_cck->sent_cts_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
le32_to_cpu(cck->sent_ba_rsp_cnt),
accum_cck->sent_ba_rsp_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"dsp_self_kill:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->dsp_self_kill),
accum_cck->dsp_self_kill);
pos += scnprintf(buf + pos, bufsz - pos,
"mh_format_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(cck->mh_format_err),
accum_cck->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
"re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
le32_to_cpu(cck->re_acq_main_rssi_sum),
accum_cck->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n",
le32_to_cpu(general->bogus_cts));
pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n",
le32_to_cpu(general->bogus_ack));
pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n",
le32_to_cpu(general->non_bssid_frames));
pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n",
le32_to_cpu(general->filtered_frames));
pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n",
le32_to_cpu(general->non_channel_beacons));
pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n",
le32_to_cpu(general->channel_beacons));
pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n",
le32_to_cpu(general->num_missed_bcon));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"adc_rx_saturation_time: %u\n", "\t\t\tcurrent\t\t\taccumulative\n");
le32_to_cpu(general->adc_rx_saturation_time)); pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->bogus_cts),
accum_general->bogus_cts);
pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->bogus_ack),
accum_general->bogus_ack);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ina_detection_search_time: %u\n", "non_bssid_frames:\t%u\t\t\t%u\n",
le32_to_cpu(general->ina_detection_search_time)); le32_to_cpu(general->non_bssid_frames),
pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", accum_general->non_bssid_frames);
le32_to_cpu(general->beacon_silence_rssi_a));
pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n",
le32_to_cpu(general->beacon_silence_rssi_b));
pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n",
le32_to_cpu(general->beacon_silence_rssi_c));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"interference_data_flag: %u\n", "filtered_frames:\t%u\t\t\t%u\n",
le32_to_cpu(general->interference_data_flag)); le32_to_cpu(general->filtered_frames),
pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", accum_general->filtered_frames);
le32_to_cpu(general->channel_load)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", "non_channel_beacons:\t%u\t\t\t%u\n",
le32_to_cpu(general->dsp_false_alarms)); le32_to_cpu(general->non_channel_beacons),
pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", accum_general->non_channel_beacons);
le32_to_cpu(general->beacon_rssi_a)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", "channel_beacons:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_rssi_b)); le32_to_cpu(general->channel_beacons),
pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", accum_general->channel_beacons);
le32_to_cpu(general->beacon_rssi_c)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", "num_missed_bcon:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_energy_a)); le32_to_cpu(general->num_missed_bcon),
pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", accum_general->num_missed_bcon);
le32_to_cpu(general->beacon_energy_b)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", "adc_rx_saturation_time:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_energy_c)); le32_to_cpu(general->adc_rx_saturation_time),
accum_general->adc_rx_saturation_time);
pos += scnprintf(buf + pos, bufsz - pos,
"ina_detect_search_tm:\t%u\t\t\t%u\n",
le32_to_cpu(general->ina_detection_search_time),
accum_general->ina_detection_search_time);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_silence_rssi_a:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_silence_rssi_a),
accum_general->beacon_silence_rssi_a);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_silence_rssi_b:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_silence_rssi_b),
accum_general->beacon_silence_rssi_b);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_silence_rssi_c:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_silence_rssi_c),
accum_general->beacon_silence_rssi_c);
pos += scnprintf(buf + pos, bufsz - pos,
"interference_data_flag:\t%u\t\t\t%u\n",
le32_to_cpu(general->interference_data_flag),
accum_general->interference_data_flag);
pos += scnprintf(buf + pos, bufsz - pos,
"channel_load:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->channel_load),
accum_general->channel_load);
pos += scnprintf(buf + pos, bufsz - pos,
"dsp_false_alarms:\t%u\t\t\t%u\n",
le32_to_cpu(general->dsp_false_alarms),
accum_general->dsp_false_alarms);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_rssi_a:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_rssi_a),
accum_general->beacon_rssi_a);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_rssi_b:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_rssi_b),
accum_general->beacon_rssi_b);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_rssi_c:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_rssi_c),
accum_general->beacon_rssi_c);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_energy_a:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_energy_a),
accum_general->beacon_energy_a);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_energy_b:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_energy_b),
accum_general->beacon_energy_b);
pos += scnprintf(buf + pos, bufsz - pos,
"beacon_energy_c:\t%u\t\t\t%u\n",
le32_to_cpu(general->beacon_energy_c),
accum_general->beacon_energy_c);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(ht->plcp_err)); "\t\t\tcurrent\t\t\taccumulative\n");
pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(ht->overrun_err)); le32_to_cpu(ht->plcp_err), accum_ht->plcp_err);
pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(ht->early_overrun_err)); "overrun_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", le32_to_cpu(ht->overrun_err), accum_ht->overrun_err);
le32_to_cpu(ht->crc32_good)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", "early_overrun_err:\t%u\t\t\t%u\n",
le32_to_cpu(ht->crc32_err)); le32_to_cpu(ht->early_overrun_err),
pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", accum_ht->early_overrun_err);
le32_to_cpu(ht->mh_format_err)); pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", le32_to_cpu(ht->crc32_good), accum_ht->crc32_good);
le32_to_cpu(ht->agg_crc32_good)); pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", le32_to_cpu(ht->crc32_err), accum_ht->crc32_err);
le32_to_cpu(ht->agg_mpdu_cnt)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", "mh_format_err:\t\t%u\t\t\t%u\n",
le32_to_cpu(ht->agg_cnt)); le32_to_cpu(ht->mh_format_err),
accum_ht->mh_format_err);
pos += scnprintf(buf + pos, bufsz - pos,
"agg_crc32_good:\t\t%u\t\t\t%u\n",
le32_to_cpu(ht->agg_crc32_good),
accum_ht->agg_crc32_good);
pos += scnprintf(buf + pos, bufsz - pos,
"agg_mpdu_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(ht->agg_mpdu_cnt),
accum_ht->agg_mpdu_cnt);
pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);
@ -1265,7 +1391,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
char *buf; char *buf;
int bufsz = (sizeof(struct statistics_tx) * 24) + 250; int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
ssize_t ret; ssize_t ret;
struct statistics_tx *tx; struct statistics_tx *tx, *accum_tx;
if (!iwl_is_alive(priv)) if (!iwl_is_alive(priv))
return -EAGAIN; return -EAGAIN;
@ -1291,62 +1417,107 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
* might not reflect the current uCode activity * might not reflect the current uCode activity
*/ */
tx = &priv->statistics.tx; tx = &priv->statistics.tx;
accum_tx = &priv->accum_statistics.tx;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n",
le32_to_cpu(tx->preamble_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n",
le32_to_cpu(tx->rx_detected_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n",
le32_to_cpu(tx->bt_prio_defer_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n",
le32_to_cpu(tx->bt_prio_kill_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n",
le32_to_cpu(tx->few_bytes_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n",
le32_to_cpu(tx->cts_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n",
le32_to_cpu(tx->ack_timeout));
pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n",
le32_to_cpu(tx->expected_ack_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n",
le32_to_cpu(tx->actual_ack_cnt));
pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n",
le32_to_cpu(tx->dump_msdu_cnt));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"burst_abort_next_frame_mismatch_cnt: %u\n", "\t\t\tcurrent\t\t\taccumulative\n");
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->preamble_cnt),
accum_tx->preamble_cnt);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"burst_abort_missing_next_frame_cnt: %u\n", "rx_detected_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); le32_to_cpu(tx->rx_detected_cnt),
pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", accum_tx->rx_detected_cnt);
le32_to_cpu(tx->cts_timeout_collision));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ack_or_ba_timeout_collision: %u\n", "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->ack_or_ba_timeout_collision)); le32_to_cpu(tx->bt_prio_defer_cnt),
pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", accum_tx->bt_prio_defer_cnt);
le32_to_cpu(tx->agg.ba_timeout));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"agg ba_reschedule_frames: %u\n", "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.ba_reschedule_frames)); le32_to_cpu(tx->bt_prio_kill_cnt),
accum_tx->bt_prio_kill_cnt);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_agg_frame_cnt: %u\n", "few_bytes_cnt:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); le32_to_cpu(tx->few_bytes_cnt),
pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", accum_tx->few_bytes_cnt);
le32_to_cpu(tx->agg.scd_query_no_agg));
pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n",
le32_to_cpu(tx->agg.scd_query_agg));
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_mismatch: %u\n", "cts_timeout:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_mismatch)); le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout);
pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(tx->agg.frame_not_ready)); "ack_timeout:\t\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", le32_to_cpu(tx->ack_timeout),
le32_to_cpu(tx->agg.underrun)); accum_tx->ack_timeout);
pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(tx->agg.bt_prio_kill)); "expected_ack_cnt:\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", le32_to_cpu(tx->expected_ack_cnt),
le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); accum_tx->expected_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"actual_ack_cnt:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->actual_ack_cnt),
accum_tx->actual_ack_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"dump_msdu_cnt:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->dump_msdu_cnt),
accum_tx->dump_msdu_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"abort_nxt_frame_mismatch:"
"\t%u\t\t\t%u\n",
le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
accum_tx->burst_abort_next_frame_mismatch_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"abort_missing_nxt_frame:"
"\t%u\t\t\t%u\n",
le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
accum_tx->burst_abort_missing_next_frame_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"cts_timeout_collision:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->cts_timeout_collision),
accum_tx->cts_timeout_collision);
pos += scnprintf(buf + pos, bufsz - pos,
"ack_ba_timeout_collision:\t%u\t\t\t%u\n",
le32_to_cpu(tx->ack_or_ba_timeout_collision),
accum_tx->ack_or_ba_timeout_collision);
pos += scnprintf(buf + pos, bufsz - pos,
"agg ba_timeout:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.ba_timeout),
accum_tx->agg.ba_timeout);
pos += scnprintf(buf + pos, bufsz - pos,
"agg ba_resched_frames:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.ba_reschedule_frames),
accum_tx->agg.ba_reschedule_frames);
pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_agg_frame:\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
accum_tx->agg.scd_query_agg_frame_cnt);
pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_no_agg:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_no_agg),
accum_tx->agg.scd_query_no_agg);
pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_agg:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_agg),
accum_tx->agg.scd_query_agg);
pos += scnprintf(buf + pos, bufsz - pos,
"agg scd_query_mismatch:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.scd_query_mismatch),
accum_tx->agg.scd_query_mismatch);
pos += scnprintf(buf + pos, bufsz - pos,
"agg frame_not_ready:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.frame_not_ready),
accum_tx->agg.frame_not_ready);
pos += scnprintf(buf + pos, bufsz - pos,
"agg underrun:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.underrun),
accum_tx->agg.underrun);
pos += scnprintf(buf + pos, bufsz - pos,
"agg bt_prio_kill:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.bt_prio_kill),
accum_tx->agg.bt_prio_kill);
pos += scnprintf(buf + pos, bufsz - pos,
"agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n",
le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
accum_tx->agg.rx_ba_rsp_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);
@ -1362,9 +1533,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
char *buf; char *buf;
int bufsz = sizeof(struct statistics_general) * 4 + 250; int bufsz = sizeof(struct statistics_general) * 4 + 250;
ssize_t ret; ssize_t ret;
struct statistics_general *general; struct statistics_general *general, *accum_general;
struct statistics_dbg *dbg; struct statistics_dbg *dbg, *accum_dbg;
struct statistics_div *div; struct statistics_div *div, *accum_div;
if (!iwl_is_alive(priv)) if (!iwl_is_alive(priv))
return -EAGAIN; return -EAGAIN;
@ -1392,34 +1563,53 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
general = &priv->statistics.general; general = &priv->statistics.general;
dbg = &priv->statistics.general.dbg; dbg = &priv->statistics.general.dbg;
div = &priv->statistics.general.div; div = &priv->statistics.general.div;
accum_general = &priv->accum_statistics.general;
accum_dbg = &priv->accum_statistics.general.dbg;
accum_div = &priv->accum_statistics.general.div;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
"\t\t\tcurrent\t\t\taccumulative\n");
pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n",
le32_to_cpu(general->temperature)); le32_to_cpu(general->temperature));
pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n",
le32_to_cpu(general->temperature_m)); le32_to_cpu(general->temperature_m));
pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(dbg->burst_check)); "burst_check:\t\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", le32_to_cpu(dbg->burst_check),
le32_to_cpu(dbg->burst_count)); accum_dbg->burst_check);
pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(general->sleep_time)); "burst_count:\t\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", le32_to_cpu(dbg->burst_count),
le32_to_cpu(general->slots_out)); accum_dbg->burst_count);
pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(general->slots_idle)); "sleep_time:\t\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", le32_to_cpu(general->sleep_time),
accum_general->sleep_time);
pos += scnprintf(buf + pos, bufsz - pos,
"slots_out:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(general->slots_out),
accum_general->slots_out);
pos += scnprintf(buf + pos, bufsz - pos,
"slots_idle:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(general->slots_idle),
accum_general->slots_idle);
pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
le32_to_cpu(general->ttl_timestamp)); le32_to_cpu(general->ttl_timestamp));
pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(div->tx_on_a)); le32_to_cpu(div->tx_on_a), accum_div->tx_on_a);
pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(div->tx_on_b)); le32_to_cpu(div->tx_on_b), accum_div->tx_on_b);
pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", pos += scnprintf(buf + pos, bufsz - pos,
le32_to_cpu(div->exec_time)); "exec_time:\t\t\t%u\t\t\t%u\n",
pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", le32_to_cpu(div->exec_time), accum_div->exec_time);
le32_to_cpu(div->probe_time)); pos += scnprintf(buf + pos, bufsz - pos,
pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", "probe_time:\t\t\t%u\t\t\t%u\n",
le32_to_cpu(general->rx_enable_counter)); le32_to_cpu(div->probe_time), accum_div->probe_time);
pos += scnprintf(buf + pos, bufsz - pos,
"rx_enable_counter:\t\t%u\t\t\t%u\n",
le32_to_cpu(general->rx_enable_counter),
accum_general->rx_enable_counter);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf); kfree(buf);
return ret; return ret;
@ -1615,6 +1805,29 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos); return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
} }
static ssize_t iwl_dbgfs_power_save_status_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[60];
int pos = 0;
const size_t bufsz = sizeof(buf);
u32 pwrsave_status;
pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
CSR_GP_REG_POWER_SAVE_STATUS_MSK;
pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
(pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
(pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
(pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
"error");
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@ -1626,6 +1839,7 @@ DEBUGFS_READ_FILE_OPS(ucode_general_stats);
DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(sensitivity);
DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(tx_power);
DEBUGFS_READ_FILE_OPS(power_save_status);
/* /*
* Create the debugfs files and directories * Create the debugfs files and directories
@ -1673,6 +1887,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(rx_queue, debug);
DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug);
DEBUGFS_ADD_FILE(tx_power, debug); DEBUGFS_ADD_FILE(tx_power, debug);
DEBUGFS_ADD_FILE(power_save_status, debug);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { 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_rx_stats, debug);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
@ -1725,6 +1940,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); 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_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats); file_ucode_rx_stats);

View File

@ -85,8 +85,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags); __le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv, extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp); struct iwl_rx_phy_res *rx_resp);
extern int iwl5000_apm_init(struct iwl_priv *priv);
extern int iwl5000_apm_reset(struct iwl_priv *priv);
extern void iwl5000_nic_config(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv);
extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@ -147,12 +145,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv);
#define DEFAULT_LONG_RETRY_LIMIT 4U #define DEFAULT_LONG_RETRY_LIMIT 4U
struct iwl_rx_mem_buffer { struct iwl_rx_mem_buffer {
dma_addr_t real_dma_addr; dma_addr_t page_dma;
dma_addr_t aligned_dma_addr; struct page *page;
struct sk_buff *skb;
struct list_head list; struct list_head list;
}; };
#define rxb_addr(r) page_address(r->page)
/* defined below */ /* defined below */
struct iwl_device_cmd; struct iwl_device_cmd;
@ -168,7 +167,7 @@ struct iwl_cmd_meta {
*/ */
void (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb); struct iwl_rx_packet *pkt);
/* The CMD_SIZE_HUGE flag bit indicates that the command /* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */ * structure is stored at the end of the shared queue memory. */
@ -324,6 +323,12 @@ struct iwl_channel_info {
* queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
#define IWL_MIN_NUM_QUEUES 10 #define IWL_MIN_NUM_QUEUES 10
/*
* uCode queue management definitions ...
* Queue #4 is the command queue for 3945/4965/5x00/1000/6x00.
*/
#define IWL_CMD_QUEUE_NUM 4
/* Power management (not Tx power) structures */ /* Power management (not Tx power) structures */
enum iwl_pwr_src { enum iwl_pwr_src {
@ -359,7 +364,14 @@ enum {
CMD_WANT_SKB = (1 << 2), CMD_WANT_SKB = (1 << 2),
}; };
#define IWL_CMD_MAX_PAYLOAD 320 #define DEF_CMD_PAYLOAD_SIZE 320
/*
* IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
* SNAP header and alignment. It should also be big enough for 802.11
* control frames.
*/
#define IWL_LINK_HDR_MAX 64
/** /**
* struct iwl_device_cmd * struct iwl_device_cmd
@ -376,7 +388,8 @@ struct iwl_device_cmd {
u16 val16; u16 val16;
u32 val32; u32 val32;
struct iwl_tx_cmd tx; struct iwl_tx_cmd tx;
u8 payload[IWL_CMD_MAX_PAYLOAD]; struct iwl6000_channel_switch_cmd chswitch;
u8 payload[DEF_CMD_PAYLOAD_SIZE];
} __attribute__ ((packed)) cmd; } __attribute__ ((packed)) cmd;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -385,21 +398,15 @@ struct iwl_device_cmd {
struct iwl_host_cmd { struct iwl_host_cmd {
const void *data; const void *data;
struct sk_buff *reply_skb; unsigned long reply_page;
void (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb); struct iwl_rx_packet *pkt);
u32 flags; u32 flags;
u16 len; u16 len;
u8 id; u8 id;
}; };
/*
* RX related structures and functions
*/
#define RX_FREE_BUFFERS 64
#define RX_LOW_WATERMARK 8
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@ -563,6 +570,19 @@ struct iwl_station_entry {
struct iwl_hw_key keyinfo; struct iwl_hw_key keyinfo;
}; };
/*
* iwl_station_priv: Driver's private station information
*
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is places in that
* space.
*
* At the moment use it for the station's rate scaling information.
*/
struct iwl_station_priv {
struct iwl_lq_sta lq_sta;
};
/* one for each uCode image (inst/data, boot/init/runtime) */ /* one for each uCode image (inst/data, boot/init/runtime) */
struct fw_desc { struct fw_desc {
void *v_addr; /* access by driver */ void *v_addr; /* access by driver */
@ -624,6 +644,10 @@ struct iwl_sensitivity_ranges {
u16 auto_corr_max_cck_mrc; u16 auto_corr_max_cck_mrc;
u16 auto_corr_min_cck; u16 auto_corr_min_cck;
u16 auto_corr_min_cck_mrc; u16 auto_corr_min_cck_mrc;
u16 barker_corr_th_min;
u16 barker_corr_th_min_mrc;
u16 nrg_th_cca;
}; };
@ -641,7 +665,7 @@ struct iwl_sensitivity_ranges {
* @valid_tx/rx_ant: usable antennas * @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
* @max_rxq_log: Log-base-2 of max_rxq_size * @max_rxq_log: Log-base-2 of max_rxq_size
* @rx_buf_size: Rx buffer size * @rx_page_order: Rx buffer page order
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
* @max_stations: * @max_stations:
* @bcast_sta_id: * @bcast_sta_id:
@ -664,9 +688,8 @@ struct iwl_hw_params {
u8 valid_rx_ant; u8 valid_rx_ant;
u16 max_rxq_size; u16 max_rxq_size;
u16 max_rxq_log; u16 max_rxq_log;
u32 rx_buf_size; u32 rx_page_order;
u32 rx_wrt_ptr_reg; u32 rx_wrt_ptr_reg;
u32 max_pkt_size;
u8 max_stations; u8 max_stations;
u8 bcast_sta_id; u8 bcast_sta_id;
u8 ht40_channel; u8 ht40_channel;
@ -713,7 +736,11 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
{ {
/* This is for scan command, the big buffer at end of command array */ /*
* This is for init calibration result and scan command which
* required buffer > TFD_MAX_PAYLOAD_SIZE,
* the big buffer at end of command array
*/
if (is_huge) if (is_huge)
return q->n_window; /* must be power of 2 */ return q->n_window; /* must be power of 2 */
@ -845,6 +872,10 @@ struct iwl_sensitivity_data {
s32 nrg_auto_corr_silence_diff; s32 nrg_auto_corr_silence_diff;
u32 num_in_cck_no_fa; u32 num_in_cck_no_fa;
u32 nrg_th_ofdm; u32 nrg_th_ofdm;
u16 barker_corr_th_min;
u16 barker_corr_th_min_mrc;
u16 nrg_th_cca;
}; };
/* Chain noise (differential Rx gain) calib data */ /* Chain noise (differential Rx gain) calib data */
@ -961,8 +992,6 @@ struct traffic_stats {
}; };
#endif #endif
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
struct iwl_priv { struct iwl_priv {
/* ieee device used by generic ieee processing code */ /* ieee device used by generic ieee processing code */
@ -976,7 +1005,7 @@ struct iwl_priv {
int frames_count; int frames_count;
enum ieee80211_band band; enum ieee80211_band band;
int alloc_rxb_skb; int alloc_rxb_page;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb); struct iwl_rx_mem_buffer *rxb);
@ -1081,7 +1110,6 @@ struct iwl_priv {
u8 last_phy_res[100]; u8 last_phy_res[100];
/* Rate scaling data */ /* Rate scaling data */
s8 data_retry_limit;
u8 retry_rate; u8 retry_rate;
wait_queue_head_t wait_command_queue; wait_queue_head_t wait_command_queue;
@ -1090,7 +1118,7 @@ struct iwl_priv {
/* Rx and Tx DMA processing queues */ /* Rx and Tx DMA processing queues */
struct iwl_rx_queue rxq; struct iwl_rx_queue rxq;
struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; struct iwl_tx_queue *txq;
unsigned long txq_ctx_active_msk; unsigned long txq_ctx_active_msk;
struct iwl_dma_ptr kw; /* keep warm address */ struct iwl_dma_ptr kw; /* keep warm address */
struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr scd_bc_tbls;
@ -1113,7 +1141,9 @@ struct iwl_priv {
struct iwl_tt_mgmt thermal_throttle; struct iwl_tt_mgmt thermal_throttle;
struct iwl_notif_statistics statistics; struct iwl_notif_statistics statistics;
unsigned long last_statistics_time; #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_notif_statistics accum_statistics;
#endif
/* context information */ /* context information */
u16 rates_mask; u16 rates_mask;

View File

@ -358,6 +358,14 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
udelay(5); udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ); APMG_PS_CTRL_VAL_RESET_REQ);
/*
* CSR auto clock gate disable bit -
* this is only applicable for HW with OTP shadow RAM
*/
if (priv->cfg->shadow_ram_support)
iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
CSR_RESET_LINK_PWR_MGMT_DISABLED);
} }
return ret; return ret;
} }

View File

@ -261,9 +261,12 @@ struct iwl_eeprom_enhanced_txpwr {
/* 1000 Specific */ /* 1000 Specific */
#define EEPROM_1000_EEPROM_VERSION (0x15C) #define EEPROM_1000_EEPROM_VERSION (0x15C)
/* 60x0 Specific */ /* 6x00 Specific */
#define EEPROM_6000_EEPROM_VERSION (0x434) #define EEPROM_6000_EEPROM_VERSION (0x434)
/* 6x50 Specific */
#define EEPROM_6050_EEPROM_VERSION (0x532)
/* OTP */ /* OTP */
/* lower blocks contain EEPROM image and calibration data */ /* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */

View File

@ -92,6 +92,8 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(CALIBRATION_RES_NOTIFICATION); IWL_CMD(CALIBRATION_RES_NOTIFICATION);
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
IWL_CMD(REPLY_TX_POWER_DBM_CMD); IWL_CMD(REPLY_TX_POWER_DBM_CMD);
IWL_CMD(TEMPERATURE_NOTIFICATION);
IWL_CMD(TX_ANT_CONFIGURATION_CMD);
default: default:
return "UNKNOWN"; return "UNKNOWN";
@ -103,17 +105,8 @@ EXPORT_SYMBOL(get_cmd_string);
static void iwl_generic_cmd_callback(struct iwl_priv *priv, static void iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb) struct iwl_rx_packet *pkt)
{ {
struct iwl_rx_packet *pkt = NULL;
if (!skb) {
IWL_ERR(priv, "Error: Response NULL in %s.\n",
get_cmd_string(cmd->hdr.cmd));
return;
}
pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from %s (0x%08X)\n", IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
@ -215,7 +208,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO; ret = -EIO;
goto fail; goto fail;
} }
if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) { if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n", IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id)); get_cmd_string(cmd->id));
ret = -EIO; ret = -EIO;
@ -237,9 +230,9 @@ cancel:
~CMD_WANT_SKB; ~CMD_WANT_SKB;
} }
fail: fail:
if (cmd->reply_skb) { if (cmd->reply_page) {
dev_kfree_skb_any(cmd->reply_skb); free_pages(cmd->reply_page, priv->hw_params.rx_page_order);
cmd->reply_skb = NULL; cmd->reply_page = 0;
} }
out: out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@ -272,7 +265,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data, u8 id, u16 len, const void *data,
void (*callback)(struct iwl_priv *priv, void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb)) struct iwl_rx_packet *pkt))
{ {
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = id, .id = id,

View File

@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust,
struct iwl_power_vec_entry { struct iwl_power_vec_entry {
struct iwl_powertable_cmd cmd; struct iwl_powertable_cmd cmd;
u8 no_dtim; u8 no_dtim; /* number of skip dtim */
}; };
#define IWL_DTIM_RANGE_0_MAX 2 #define IWL_DTIM_RANGE_0_MAX 2
@ -83,8 +83,9 @@ struct iwl_power_vec_entry {
cpu_to_le32(X4)} cpu_to_le32(X4)}
/* default power management (not Tx power) table values */ /* default power management (not Tx power) table values */
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
/* DTIM 0 - 2 */
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
/* DTIM 3 - 10 */
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
}; };
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */ /* for DTIM period > IWL_DTIM_RANGE_1_MAX */
/* DTIM 11 - */
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
enum iwl_power_level lvl, int period) enum iwl_power_level lvl, int period)
{ {
const struct iwl_power_vec_entry *table; const struct iwl_power_vec_entry *table;
int max_sleep, i; int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
bool skip; int i;
u8 skip;
u32 slp_itrvl;
table = range_2; table = range_2;
if (period < IWL_DTIM_RANGE_1_MAX) if (period <= IWL_DTIM_RANGE_1_MAX)
table = range_1; table = range_1;
if (period < IWL_DTIM_RANGE_0_MAX) if (period <= IWL_DTIM_RANGE_0_MAX)
table = range_0; table = range_0;
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
*cmd = table[lvl].cmd; *cmd = table[lvl].cmd;
if (period == 0) { if (period == 0) {
skip = false; skip = 0;
period = 1; period = 1;
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
max_sleep[i] = 1;
} else { } else {
skip = !!table[lvl].no_dtim; skip = table[lvl].no_dtim;
for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
} }
if (skip) { slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; /* figure out the listen interval based on dtim period and skip */
max_sleep = le32_to_cpu(slp_itrvl); if (slp_itrvl == 0xFF)
if (max_sleep == 0xFF) cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
max_sleep = period * (skip + 1); cpu_to_le32(period * (skip + 1));
else if (max_sleep > period)
max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
if (slp_itrvl > period)
cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
cpu_to_le32((slp_itrvl / period) * period);
if (skip)
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
} else { else
max_sleep = period;
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
}
for (i = 0; i < IWL_POWER_VEC_SIZE; i++) slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
cmd->sleep_interval[i] = cpu_to_le32(max_sleep); cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
/* enforce max sleep interval */
for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
if (le32_to_cpu(cmd->sleep_interval[i]) >
(max_sleep[i] * period))
cmd->sleep_interval[i] =
cpu_to_le32(max_sleep[i] * period);
if (i != (IWL_POWER_VEC_SIZE - 1)) {
if (le32_to_cpu(cmd->sleep_interval[i]) >
le32_to_cpu(cmd->sleep_interval[i+1]))
cmd->sleep_interval[i] =
cmd->sleep_interval[i+1];
}
}
if (priv->power_data.pci_pm) if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK; cmd->flags |= IWL_POWER_PCI_PM_MSK;
else else
cmd->flags &= ~IWL_POWER_PCI_PM_MSK; cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
skip, period);
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
} }
@ -862,9 +893,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { if (priv->cfg->adv_thermal_throttle) {
case CSR_HW_REV_TYPE_6x00:
case CSR_HW_REV_TYPE_6x50:
IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
IWL_TI_STATE_MAX, GFP_KERNEL); IWL_TI_STATE_MAX, GFP_KERNEL);
@ -897,11 +926,9 @@ void iwl_tt_initialize(struct iwl_priv *priv)
&restriction_range[0], size); &restriction_range[0], size);
priv->thermal_throttle.advanced_tt = true; priv->thermal_throttle.advanced_tt = true;
} }
break; } else {
default:
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
priv->thermal_throttle.advanced_tt = false; priv->thermal_throttle.advanced_tt = false;
break;
} }
} }
EXPORT_SYMBOL(iwl_tt_initialize); EXPORT_SYMBOL(iwl_tt_initialize);

View File

@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
list_del(element); list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */ /* Point to Rx buffer via next RBD in circular buffer */
rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr); rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb; rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--; rxq->free_count--;
@ -239,8 +239,9 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq; struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element; struct list_head *element;
struct iwl_rx_mem_buffer *rxb; struct iwl_rx_mem_buffer *rxb;
struct sk_buff *skb; struct page *page;
unsigned long flags; unsigned long flags;
gfp_t gfp_mask = priority;
while (1) { while (1) {
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
@ -251,30 +252,35 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK) if (rxq->free_count > RX_LOW_WATERMARK)
priority |= __GFP_NOWARN; gfp_mask |= __GFP_NOWARN;
/* Alloc a new receive buffer */
skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
priority);
if (!skb) { if (priv->hw_params.rx_page_order > 0)
gfp_mask |= __GFP_COMP;
/* Alloc a new receive buffer */
page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
if (!page) {
if (net_ratelimit()) if (net_ratelimit())
IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); IWL_DEBUG_INFO(priv, "alloc_pages failed, "
"order: %d\n",
priv->hw_params.rx_page_order);
if ((rxq->free_count <= RX_LOW_WATERMARK) && if ((rxq->free_count <= RX_LOW_WATERMARK) &&
net_ratelimit()) net_ratelimit())
IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n", IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL", priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL",
rxq->free_count); rxq->free_count);
/* We don't reschedule replenish work here -- we will /* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs * call the restock method and if it still needs
* more buffers it will schedule replenish */ * more buffers it will schedule replenish */
break; return;
} }
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) { if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
dev_kfree_skb_any(skb); __free_pages(page, priv->hw_params.rx_page_order);
return; return;
} }
element = rxq->rx_used.next; element = rxq->rx_used.next;
@ -283,24 +289,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
rxb->skb = skb; rxb->page = page;
/* Get physical address of RB/SKB */ /* Get physical address of the RB */
rxb->real_dma_addr = pci_map_single( rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
priv->pci_dev, PAGE_SIZE << priv->hw_params.rx_page_order,
rxb->skb->data, PCI_DMA_FROMDEVICE);
priv->hw_params.rx_buf_size + 256,
PCI_DMA_FROMDEVICE);
/* dma address must be no more than 36 bits */ /* dma address must be no more than 36 bits */
BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36)); BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
/* and also 256 byte aligned! */ /* and also 256 byte aligned! */
rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &rxq->rx_free); list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++; rxq->free_count++;
priv->alloc_rxb_skb++; priv->alloc_rxb_page++;
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
} }
@ -336,12 +339,14 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{ {
int i; int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
if (rxq->pool[i].skb != NULL) { if (rxq->pool[i].page != NULL) {
pci_unmap_single(priv->pci_dev, pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
rxq->pool[i].real_dma_addr, PAGE_SIZE << priv->hw_params.rx_page_order,
priv->hw_params.rx_buf_size + 256, PCI_DMA_FROMDEVICE);
PCI_DMA_FROMDEVICE); __free_pages(rxq->pool[i].page,
dev_kfree_skb(rxq->pool[i].skb); priv->hw_params.rx_page_order);
rxq->pool[i].page = NULL;
priv->alloc_rxb_page--;
} }
} }
@ -405,14 +410,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated /* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */ * to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].skb != NULL) { if (rxq->pool[i].page != NULL) {
pci_unmap_single(priv->pci_dev, pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
rxq->pool[i].real_dma_addr, PAGE_SIZE << priv->hw_params.rx_page_order,
priv->hw_params.rx_buf_size + 256, PCI_DMA_FROMDEVICE);
PCI_DMA_FROMDEVICE); priv->alloc_rxb_page--;
priv->alloc_rxb_skb--; __free_pages(rxq->pool[i].page,
dev_kfree_skb(rxq->pool[i].skb); priv->hw_params.rx_page_order);
rxq->pool[i].skb = NULL; rxq->pool[i].page = NULL;
} }
list_add_tail(&rxq->pool[i].list, &rxq->rx_used); list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
} }
@ -491,7 +496,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_missed_beacon_notif *missed_beacon; struct iwl_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon; missed_beacon = &pkt->u.missed_beacon;
@ -548,13 +553,51 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
priv->last_rx_noise); priv->last_rx_noise);
} }
#ifdef CONFIG_IWLWIFI_DEBUG
/*
* based on the assumption of all statistics counter are in DWORD
* FIXME: This function is for debugging, do not deal with
* the case of counters roll-over.
*/
static void iwl_accumulative_statistics(struct iwl_priv *priv,
__le32 *stats)
{
int i;
__le32 *prev_stats;
u32 *accum_stats;
prev_stats = (__le32 *)&priv->statistics;
accum_stats = (u32 *)&priv->accum_statistics;
for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
*accum_stats += (le32_to_cpu(*stats) -
le32_to_cpu(*prev_stats));
/* reset accumulative statistics for "no-counter" type statistics */
priv->accum_statistics.general.temperature =
priv->statistics.general.temperature;
priv->accum_statistics.general.temperature_m =
priv->statistics.general.temperature_m;
priv->accum_statistics.general.ttl_timestamp =
priv->statistics.general.ttl_timestamp;
priv->accum_statistics.tx.tx_power.ant_a =
priv->statistics.tx.tx_power.ant_a;
priv->accum_statistics.tx.tx_power.ant_b =
priv->statistics.tx.tx_power.ant_b;
priv->accum_statistics.tx.tx_power.ant_c =
priv->statistics.tx.tx_power.ant_c;
}
#endif
#define REG_RECALIB_PERIOD (60) #define REG_RECALIB_PERIOD (60)
void iwl_rx_statistics(struct iwl_priv *priv, void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
int change; int change;
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(priv->statistics), (int)sizeof(priv->statistics),
@ -566,6 +609,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
STATISTICS_REPLY_FLG_HT40_MODE_MSK) != STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
#ifdef CONFIG_IWLWIFI_DEBUG
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
#endif
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
set_bit(STATUS_STATISTICS, &priv->status); set_bit(STATUS_STATISTICS, &priv->status);
@ -582,9 +628,6 @@ void iwl_rx_statistics(struct iwl_priv *priv,
iwl_rx_calc_noise(priv); iwl_rx_calc_noise(priv);
queue_work(priv->workqueue, &priv->run_time_calib_work); queue_work(priv->workqueue, &priv->run_time_calib_work);
} }
iwl_leds_background(priv);
if (priv->cfg->ops->lib->temp_ops.temperature && change) if (priv->cfg->ops->lib->temp_ops.temperature && change)
priv->cfg->ops->lib->temp_ops.temperature(priv); priv->cfg->ops->lib->temp_ops.temperature(priv);
} }
@ -878,6 +921,10 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb, struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats) struct ieee80211_rx_status *stats)
{ {
struct sk_buff *skb;
int ret = 0;
__le16 fc = hdr->frame_control;
/* We only process data packets if the interface is open */ /* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) { if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv, IWL_DEBUG_DROP_LIMIT(priv,
@ -890,15 +937,43 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return; return;
/* Resize SKB from mac header to end of packet */ skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); if (!skb) {
skb_put(rxb->skb, len); IWL_ERR(priv, "alloc_skb failed\n");
return;
}
iwl_update_stats(priv, false, hdr->frame_control, len); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
ieee80211_rx_irqsafe(priv->hw, rxb->skb); /* mac80211 currently doesn't support paged SKB. Convert it to
priv->alloc_rxb_skb--; * linear SKB for management frame and data frame requires
rxb->skb = NULL; * software decryption or software defragementation. */
if (ieee80211_is_mgmt(fc) ||
ieee80211_has_protected(fc) ||
ieee80211_has_morefrags(fc) ||
le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
ret = skb_linearize(skb);
else
ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
0 : -ENOMEM;
if (ret) {
kfree_skb(skb);
goto out;
}
/*
* XXX: We cannot touch the page and its virtual memory (hdr) after
* here. It might have already been freed by the above skb change.
*/
iwl_update_stats(priv, false, fc, len);
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
ieee80211_rx(priv->hw, skb);
out:
priv->alloc_rxb_page--;
rxb->page = NULL;
} }
/* This is necessary only for a number of statistics, see the caller. */ /* This is necessary only for a number of statistics, see the caller. */
@ -926,7 +1001,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
{ {
struct ieee80211_hdr *header; struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status; struct ieee80211_rx_status rx_status;
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_phy_res *phy_res; struct iwl_rx_phy_res *phy_res;
__le32 rx_pkt_status; __le32 rx_pkt_status;
struct iwl4965_rx_mpdu_res_start *amsdu; struct iwl4965_rx_mpdu_res_start *amsdu;
@ -1087,7 +1162,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx);
void iwl_rx_reply_rx_phy(struct iwl_priv *priv, void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
priv->last_phy_res[0] = 1; priv->last_phy_res[0] = 1;
memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
sizeof(struct iwl_rx_phy_res)); sizeof(struct iwl_rx_phy_res));

View File

@ -111,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout);
static int iwl_send_scan_abort(struct iwl_priv *priv) static int iwl_send_scan_abort(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
struct iwl_rx_packet *res; struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD, .id = REPLY_SCAN_ABORT_CMD,
.flags = CMD_WANT_SKB, .flags = CMD_WANT_SKB,
@ -131,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
return ret; return ret;
} }
res = (struct iwl_rx_packet *)cmd.reply_skb->data; pkt = (struct iwl_rx_packet *)cmd.reply_page;
if (res->u.status != CAN_ABORT_STATUS) { if (pkt->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or /* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be * 2 for "failure". A failure condition can be
* due to simply not being in an active scan which * due to simply not being in an active scan which
* can occur if we send the scan abort before we * can occur if we send the scan abort before we
* the microcode has notified us that a scan is * the microcode has notified us that a scan is
* completed. */ * completed. */
IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status); IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status);
clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_ABORTING, &priv->status);
clear_bit(STATUS_SCAN_HW, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status);
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_page--;
dev_kfree_skb_any(cmd.reply_skb); free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret; return ret;
} }
@ -155,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanreq_notification *notif = struct iwl_scanreq_notification *notif =
(struct iwl_scanreq_notification *)pkt->u.raw; (struct iwl_scanreq_notification *)pkt->u.raw;
@ -167,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
static void iwl_rx_scan_start_notif(struct iwl_priv *priv, static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanstart_notification *notif = struct iwl_scanstart_notification *notif =
(struct iwl_scanstart_notification *)pkt->u.raw; (struct iwl_scanstart_notification *)pkt->u.raw;
priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
@ -186,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanresults_notification *notif = struct iwl_scanresults_notification *notif =
(struct iwl_scanresults_notification *)pkt->u.raw; (struct iwl_scanresults_notification *)pkt->u.raw;
@ -213,7 +213,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",

View File

@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv,
static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
if (!report->state) { if (!report->state) {

View File

@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
static void iwl_add_sta_callback(struct iwl_priv *priv, static void iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb) struct iwl_rx_packet *pkt)
{ {
struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta = struct iwl_addsta_cmd *addsta =
(struct iwl_addsta_cmd *)cmd->cmd.payload; (struct iwl_addsta_cmd *)cmd->cmd.payload;
u8 sta_id = addsta->sta.sta_id; u8 sta_id = addsta->sta.sta_id;
if (!skb) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags); pkt->hdr.flags);
return; return;
} }
switch (res->u.add_sta.status) { switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK: case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta_id); iwl_sta_ucode_activate(priv, sta_id);
/* fall through */ /* fall through */
default: default:
IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
res->u.add_sta.status); pkt->u.add_sta.status);
break; break;
} }
} }
@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
int iwl_send_add_sta(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags) struct iwl_addsta_cmd *sta, u8 flags)
{ {
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *pkt = NULL;
int ret = 0; int ret = 0;
u8 data[sizeof(*sta)]; u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC)) if (ret || (flags & CMD_ASYNC))
return ret; return ret;
res = (struct iwl_rx_packet *)cmd.reply_skb->data; pkt = (struct iwl_rx_packet *)cmd.reply_page;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags); pkt->hdr.flags);
ret = -EIO; ret = -EIO;
} }
if (ret == 0) { if (ret == 0) {
switch (res->u.add_sta.status) { switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK: case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta->sta.sta_id); iwl_sta_ucode_activate(priv, sta->sta.sta_id);
IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
} }
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_page--;
dev_kfree_skb_any(cmd.reply_skb); free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret; return ret;
} }
@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
static void iwl_remove_sta_callback(struct iwl_priv *priv, static void iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd, struct iwl_device_cmd *cmd,
struct sk_buff *skb) struct iwl_rx_packet *pkt)
{ {
struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta = struct iwl_rem_sta_cmd *rm_sta =
(struct iwl_rem_sta_cmd *)cmd->cmd.payload; (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
const char *addr = rm_sta->addr; const char *addr = rm_sta->addr;
if (!skb) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
return;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags); pkt->hdr.flags);
return; return;
} }
switch (res->u.rem_sta.status) { switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK: case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr); iwl_sta_ucode_deactivate(priv, addr);
break; break;
@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
u8 flags) u8 flags)
{ {
struct iwl_rx_packet *res = NULL; struct iwl_rx_packet *pkt;
int ret; int ret;
struct iwl_rem_sta_cmd rm_sta_cmd; struct iwl_rem_sta_cmd rm_sta_cmd;
@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
if (ret || (flags & CMD_ASYNC)) if (ret || (flags & CMD_ASYNC))
return ret; return ret;
res = (struct iwl_rx_packet *)cmd.reply_skb->data; pkt = (struct iwl_rx_packet *)cmd.reply_page;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags); pkt->hdr.flags);
ret = -EIO; ret = -EIO;
} }
if (!ret) { if (!ret) {
switch (res->u.rem_sta.status) { switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK: case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr); iwl_sta_ucode_deactivate(priv, addr);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
} }
} }
priv->alloc_rxb_skb--; priv->alloc_rxb_page--;
dev_kfree_skb_any(cmd.reply_skb); free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret; return ret;
} }

View File

@ -131,7 +131,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q; struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev; struct pci_dev *dev = priv->pci_dev;
int i, len; int i;
if (q->n_bd == 0) if (q->n_bd == 0)
return; return;
@ -141,8 +141,6 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq); priv->cfg->ops->lib->txq_free_tfd(priv, txq);
len = sizeof(struct iwl_device_cmd) * q->n_window;
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++) for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
kfree(txq->cmd[i]); kfree(txq->cmd[i]);
@ -180,14 +178,11 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q; struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev; struct pci_dev *dev = priv->pci_dev;
int i, len; int i;
if (q->n_bd == 0) if (q->n_bd == 0)
return; return;
len = sizeof(struct iwl_device_cmd) * q->n_window;
len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
for (i = 0; i <= TFD_CMD_SLOTS; i++) for (i = 0; i <= TFD_CMD_SLOTS; i++)
kfree(txq->cmd[i]); kfree(txq->cmd[i]);
@ -405,15 +400,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id; int txq_id;
/* Tx queues */ /* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) if (priv->txq)
if (txq_id == IWL_CMD_QUEUE_NUM) for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
iwl_cmd_queue_free(priv); txq_id++)
else if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_tx_queue_free(priv, txq_id); iwl_cmd_queue_free(priv);
else
iwl_tx_queue_free(priv, txq_id);
iwl_free_dma_ptr(priv, &priv->kw); iwl_free_dma_ptr(priv, &priv->kw);
iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
/* free tx queue structure */
iwl_free_txq_mem(priv);
} }
EXPORT_SYMBOL(iwl_hw_txq_ctx_free); EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
@ -445,6 +444,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
IWL_ERR(priv, "Keep Warm allocation failed\n"); IWL_ERR(priv, "Keep Warm allocation failed\n");
goto error_kw; goto error_kw;
} }
/* allocate tx queue structure */
ret = iwl_alloc_txq_mem(priv);
if (ret)
goto error;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
/* Turn off all Tx DMA fifos */ /* Turn off all Tx DMA fifos */
@ -581,9 +586,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
u8 rate_plcp; u8 rate_plcp;
/* Set retry limit on DATA packets and Probe Responses*/ /* Set retry limit on DATA packets and Probe Responses*/
if (priv->data_retry_limit != -1) if (ieee80211_is_probe_resp(fc))
data_retry_limit = priv->data_retry_limit;
else if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3; data_retry_limit = 3;
else else
data_retry_limit = IWL_DEFAULT_TX_RETRY; data_retry_limit = IWL_DEFAULT_TX_RETRY;
@ -1145,7 +1148,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
*/ */
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence); u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence); int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
@ -1172,10 +1175,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
/* Input error checking is done when commands are added to queue. */ /* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) { if (meta->flags & CMD_WANT_SKB) {
meta->source->reply_skb = rxb->skb; meta->source->reply_page = (unsigned long)rxb_addr(rxb);
rxb->skb = NULL; rxb->page = NULL;
} else if (meta->callback) } else if (meta->callback)
meta->callback(priv, cmd, rxb->skb); meta->callback(priv, cmd, pkt);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
@ -1434,7 +1437,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
struct iwl_tx_queue *txq = NULL; struct iwl_tx_queue *txq = NULL;
struct iwl_ht_agg *agg; struct iwl_ht_agg *agg;

View File

@ -88,7 +88,6 @@ MODULE_LICENSE("GPL");
/* module parameters */ /* module parameters */
struct iwl_mod_params iwl3945_mod_params = { struct iwl_mod_params iwl3945_mod_params = {
.num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1, .sw_crypto = 1,
.restart_fw = 1, .restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
@ -366,13 +365,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct sk_buff *skb_frag, struct sk_buff *skb_frag,
int sta_id) int sta_id)
{ {
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
switch (keyinfo->alg) { switch (keyinfo->alg) {
case ALG_CCMP: case ALG_CCMP:
tx->sec_ctl = TX_CMD_SEC_CCM; tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
memcpy(tx->key, keyinfo->key, keyinfo->keylen); memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break; break;
@ -380,13 +379,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break; break;
case ALG_WEP: case ALG_WEP:
tx->sec_ctl = TX_CMD_SEC_WEP | tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
(info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
if (keyinfo->keylen == 13) if (keyinfo->keylen == 13)
tx->sec_ctl |= TX_CMD_SEC_KEY128; tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen); memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
"with key %d\n", info->control.hw_key->hw_key_idx); "with key %d\n", info->control.hw_key->hw_key_idx);
@ -406,12 +405,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id) struct ieee80211_hdr *hdr, u8 std_id)
{ {
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
__le32 tx_flags = tx->tx_flags; __le32 tx_flags = tx_cmd->tx_flags;
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
u8 rc_flags = info->control.rates[0].flags;
tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK; tx_flags |= TX_CMD_FLG_ACK_MSK;
if (ieee80211_is_mgmt(fc)) if (ieee80211_is_mgmt(fc))
@ -424,25 +422,19 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
} }
tx->sta_id = std_id; tx_cmd->sta_id = std_id;
if (ieee80211_has_morefrags(fc)) if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
if (ieee80211_is_data_qos(fc)) { if (ieee80211_is_data_qos(fc)) {
u8 *qc = ieee80211_get_qos_ctl(hdr); u8 *qc = ieee80211_get_qos_ctl(hdr);
tx->tid_tspec = qc[0] & 0xf; tx_cmd->tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
} else { } else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
} }
if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
tx_flags |= TX_CMD_FLG_RTS_MSK;
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
} else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
tx_flags |= TX_CMD_FLG_CTS_MSK;
}
if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
@ -450,16 +442,16 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_mgmt(fc)) {
if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
tx->timeout.pm_frame_timeout = cpu_to_le16(3); tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
else else
tx->timeout.pm_frame_timeout = cpu_to_le16(2); tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
} else { } else {
tx->timeout.pm_frame_timeout = 0; tx_cmd->timeout.pm_frame_timeout = 0;
} }
tx->driver_txop = 0; tx_cmd->driver_txop = 0;
tx->tx_flags = tx_flags; tx_cmd->tx_flags = tx_flags;
tx->next_frame_len = 0; tx_cmd->next_frame_len = 0;
} }
/* /*
@ -469,7 +461,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl3945_tx_cmd *tx; struct iwl3945_tx_cmd *tx_cmd;
struct iwl_tx_queue *txq = NULL; struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL; struct iwl_queue *q = NULL;
struct iwl_device_cmd *out_cmd; struct iwl_device_cmd *out_cmd;
@ -568,9 +560,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Init first empty entry in queue's array of Tx/cmd buffers */ /* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx]; out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx]; out_meta = &txq->meta[idx];
tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx, 0, sizeof(*tx)); memset(tx_cmd, 0, sizeof(*tx_cmd));
/* /*
* Set up the Tx-command (not MAC!) header. * Set up the Tx-command (not MAC!) header.
@ -583,7 +575,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
INDEX_TO_SEQ(q->write_ptr))); INDEX_TO_SEQ(q->write_ptr)));
/* Copy MAC header from skb into command buffer */ /* Copy MAC header from skb into command buffer */
memcpy(tx->hdr, hdr, hdr_len); memcpy(tx_cmd->hdr, hdr, hdr_len);
if (info->control.hw_key) if (info->control.hw_key)
@ -597,12 +589,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Total # bytes to be transmitted */ /* Total # bytes to be transmitted */
len = (u16)skb->len; len = (u16)skb->len;
tx->len = cpu_to_le16(len); tx_cmd->len = cpu_to_le16(len);
iwl_dbg_log_tx_data_frame(priv, len, hdr); iwl_dbg_log_tx_data_frame(priv, len, hdr);
iwl_update_stats(priv, true, fc, len); iwl_update_stats(priv, true, fc, len);
tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
if (!ieee80211_has_morefrags(hdr->frame_control)) { if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1; txq->need_update = 1;
@ -615,9 +607,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence)); le16_to_cpu(out_cmd->hdr.sequence));
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd));
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr,
ieee80211_hdrlen(fc)); ieee80211_hdrlen(fc));
/* /*
@ -753,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
u8 type) u8 type)
{ {
struct iwl_spectrum_cmd spectrum; struct iwl_spectrum_cmd spectrum;
struct iwl_rx_packet *res; struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD, .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum, .data = (void *)&spectrum,
@ -798,18 +790,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc) if (rc)
return rc; return rc;
res = (struct iwl_rx_packet *)cmd.reply_skb->data; pkt = (struct iwl_rx_packet *)cmd.reply_page;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO; rc = -EIO;
} }
spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status);
switch (spectrum_resp_status) { switch (spectrum_resp_status) {
case 0: /* Command will be handled */ case 0: /* Command will be handled */
if (res->u.spectrum.id != 0xff) { if (pkt->u.spectrum.id != 0xff) {
IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n", IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n",
res->u.spectrum.id); pkt->u.spectrum.id);
priv->measurement_status &= ~MEASUREMENT_READY; priv->measurement_status &= ~MEASUREMENT_READY;
} }
priv->measurement_status |= MEASUREMENT_ACTIVE; priv->measurement_status |= MEASUREMENT_ACTIVE;
@ -821,7 +813,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break; break;
} }
dev_kfree_skb_any(cmd.reply_skb); free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc; return rc;
} }
@ -830,7 +822,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
static void iwl3945_rx_reply_alive(struct iwl_priv *priv, static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive; struct iwl_alive_resp *palive;
struct delayed_work *pwork; struct delayed_work *pwork;
@ -867,7 +859,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
#endif #endif
IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
@ -903,7 +895,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
u8 rate = beacon->beacon_notify_hdr.rate; u8 rate = beacon->beacon_notify_hdr.rate;
@ -926,7 +918,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status; unsigned long status = priv->status;
@ -1090,7 +1082,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
list_del(element); list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */ /* Point to Rx buffer via next RBD in circular buffer */
rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr); rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb; rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--; rxq->free_count--;
@ -1130,8 +1122,9 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq; struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element; struct list_head *element;
struct iwl_rx_mem_buffer *rxb; struct iwl_rx_mem_buffer *rxb;
struct sk_buff *skb; struct page *page;
unsigned long flags; unsigned long flags;
gfp_t gfp_mask = priority;
while (1) { while (1) {
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
@ -1143,10 +1136,14 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK) if (rxq->free_count > RX_LOW_WATERMARK)
priority |= __GFP_NOWARN; gfp_mask |= __GFP_NOWARN;
if (priv->hw_params.rx_page_order > 0)
gfp_mask |= __GFP_COMP;
/* Alloc a new receive buffer */ /* Alloc a new receive buffer */
skb = alloc_skb(priv->hw_params.rx_buf_size, priority); page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
if (!skb) { if (!page) {
if (net_ratelimit()) if (net_ratelimit())
IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
if ((rxq->free_count <= RX_LOW_WATERMARK) && if ((rxq->free_count <= RX_LOW_WATERMARK) &&
@ -1163,7 +1160,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) { if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
dev_kfree_skb_any(skb); __free_pages(page, priv->hw_params.rx_page_order);
return; return;
} }
element = rxq->rx_used.next; element = rxq->rx_used.next;
@ -1171,26 +1168,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
list_del(element); list_del(element);
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
rxb->skb = skb; rxb->page = page;
/* If radiotap head is required, reserve some headroom here.
* The physical head count is a variable rx_stats->phy_count.
* We reserve 4 bytes here. Plus these extra bytes, the
* headroom of the physical head should be enough for the
* radiotap head that iwl3945 supported. See iwl3945_rt.
*/
skb_reserve(rxb->skb, 4);
/* Get physical address of RB/SKB */ /* Get physical address of RB/SKB */
rxb->real_dma_addr = pci_map_single(priv->pci_dev, rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
rxb->skb->data, PAGE_SIZE << priv->hw_params.rx_page_order,
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
PCI_DMA_FROMDEVICE);
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &rxq->rx_free); list_add_tail(&rxb->list, &rxq->rx_free);
priv->alloc_rxb_skb++;
rxq->free_count++; rxq->free_count++;
priv->alloc_rxb_page++;
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
} }
} }
@ -1206,14 +1195,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated /* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */ * to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].skb != NULL) { if (rxq->pool[i].page != NULL) {
pci_unmap_single(priv->pci_dev, pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
rxq->pool[i].real_dma_addr, PAGE_SIZE << priv->hw_params.rx_page_order,
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
PCI_DMA_FROMDEVICE); priv->alloc_rxb_page--;
priv->alloc_rxb_skb--; __free_pages(rxq->pool[i].page,
dev_kfree_skb(rxq->pool[i].skb); priv->hw_params.rx_page_order);
rxq->pool[i].skb = NULL; rxq->pool[i].page = NULL;
} }
list_add_tail(&rxq->pool[i].list, &rxq->rx_used); list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
} }
@ -1221,8 +1210,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* Set us so that we have processed and used all buffers, but have /* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */ * not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0; rxq->read = rxq->write = 0;
rxq->free_count = 0;
rxq->write_actual = 0; rxq->write_actual = 0;
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
} }
@ -1255,12 +1244,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
{ {
int i; int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
if (rxq->pool[i].skb != NULL) { if (rxq->pool[i].page != NULL) {
pci_unmap_single(priv->pci_dev, pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
rxq->pool[i].real_dma_addr, PAGE_SIZE << priv->hw_params.rx_page_order,
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
PCI_DMA_FROMDEVICE); __free_pages(rxq->pool[i].page,
dev_kfree_skb(rxq->pool[i].skb); priv->hw_params.rx_page_order);
rxq->pool[i].page = NULL;
priv->alloc_rxb_page--;
} }
} }
@ -1376,7 +1367,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
i = rxq->read; i = rxq->read;
/* calculate total frames need to be restock after handling RX */ /* calculate total frames need to be restock after handling RX */
total_empty = r - priv->rxq.write_actual; total_empty = r - rxq->write_actual;
if (total_empty < 0) if (total_empty < 0)
total_empty += RX_QUEUE_SIZE; total_empty += RX_QUEUE_SIZE;
@ -1396,10 +1387,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL; rxq->queue[i] = NULL;
pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, pci_unmap_page(priv->pci_dev, rxb->page_dma,
priv->hw_params.rx_buf_size, PAGE_SIZE << priv->hw_params.rx_page_order,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
pkt = (struct iwl_rx_packet *)rxb->skb->data; pkt = rxb_addr(rxb);
trace_iwlwifi_dev_rx(priv, pkt, trace_iwlwifi_dev_rx(priv, pkt,
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
@ -1420,44 +1411,55 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) { if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i,
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else { } else {
/* No handling needed */ /* No handling needed */
IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n", IWL_DEBUG_RX(priv,
"r %d i %d No handler needed for %s, 0x%02x\n",
r, i, get_cmd_string(pkt->hdr.cmd), r, i, get_cmd_string(pkt->hdr.cmd),
pkt->hdr.cmd); pkt->hdr.cmd);
} }
/*
* XXX: After here, we should always check rxb->page
* against NULL before touching it or its virtual
* memory (pkt). Because some rx_handler might have
* already taken or freed the pages.
*/
if (reclaim) { if (reclaim) {
/* Invoke any callbacks, transfer the skb to caller, and /* Invoke any callbacks, transfer the buffer to caller,
* fire off the (possibly) blocking iwl_send_cmd() * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */ * as we reclaim the driver command queue */
if (rxb && rxb->skb) if (rxb->page)
iwl_tx_cmd_complete(priv, rxb); iwl_tx_cmd_complete(priv, rxb);
else else
IWL_WARN(priv, "Claim null rxb?\n"); IWL_WARN(priv, "Claim null rxb?\n");
} }
/* For now we just don't re-use anything. We can tweak this /* Reuse the page if possible. For notification packets and
* later to try and re-use notification packets and SKBs that * SKBs that fail to Rx correctly, add them back into the
* fail to Rx correctly */ * rx_free list for reuse later. */
if (rxb->skb != NULL) {
priv->alloc_rxb_skb--;
dev_kfree_skb_any(rxb->skb);
rxb->skb = NULL;
}
spin_lock_irqsave(&rxq->lock, flags); spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &priv->rxq.rx_used); if (rxb->page != NULL) {
rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
0, PAGE_SIZE << priv->hw_params.rx_page_order,
PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
} else
list_add_tail(&rxb->list, &rxq->rx_used);
spin_unlock_irqrestore(&rxq->lock, flags); spin_unlock_irqrestore(&rxq->lock, flags);
i = (i + 1) & RX_QUEUE_MASK; i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames, /* If there are a lot of unused frames,
* restock the Rx queue so ucode won't assert. */ * restock the Rx queue so ucode won't assert. */
if (fill_rx) { if (fill_rx) {
count++; count++;
if (count >= 8) { if (count >= 8) {
priv->rxq.read = i; rxq->read = i;
iwl3945_rx_replenish_now(priv); iwl3945_rx_replenish_now(priv);
count = 0; count = 0;
} }
@ -1465,7 +1467,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
} }
/* Backtrack one entry */ /* Backtrack one entry */
priv->rxq.read = i; rxq->read = i;
if (fill_rx) if (fill_rx)
iwl3945_rx_replenish_now(priv); iwl3945_rx_replenish_now(priv);
else else
@ -1686,6 +1688,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that * atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after * we've discovered, even if FH interrupt came in just after
@ -1707,8 +1711,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR; handled |= CSR_INT_BIT_HW_ERR;
spin_unlock_irqrestore(&priv->lock, flags);
return; return;
} }
@ -1800,7 +1802,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
} }
#endif #endif
spin_unlock_irqrestore(&priv->lock, flags);
} }
static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
@ -2563,11 +2564,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
test_bit(STATUS_EXIT_PENDING, &priv->status) << test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING; STATUS_EXIT_PENDING;
priv->cfg->ops->lib->apm_ops.reset(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock_irqrestore(&priv->lock, flags);
iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_txq_ctx_stop(priv);
iwl3945_hw_rxq_stop(priv); iwl3945_hw_rxq_stop(priv);
@ -2576,10 +2572,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
udelay(5); udelay(5);
if (exit_pending) /* Stop the device, and put it in low power state */
priv->cfg->ops->lib->apm_ops.stop(priv); priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv);
exit: exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@ -2724,19 +2718,34 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
} }
/*
* 3945 cannot interrupt driver when hardware rf kill switch toggles;
* driver must poll CSR_GP_CNTRL_REG register for change. This register
* *is* readable even when device has been SW_RESET into low power mode
* (e.g. during RF KILL).
*/
static void iwl3945_rfkill_poll(struct work_struct *data) static void iwl3945_rfkill_poll(struct work_struct *data)
{ {
struct iwl_priv *priv = struct iwl_priv *priv =
container_of(data, struct iwl_priv, rfkill_poll.work); container_of(data, struct iwl_priv, rfkill_poll.work);
bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status);
bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL)
& CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) if (new_rfkill != old_rfkill) {
clear_bit(STATUS_RF_KILL_HW, &priv->status); if (new_rfkill)
else set_bit(STATUS_RF_KILL_HW, &priv->status);
set_bit(STATUS_RF_KILL_HW, &priv->status); else
clear_bit(STATUS_RF_KILL_HW, &priv->status);
wiphy_rfkill_set_hw_state(priv->hw->wiphy, wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill);
test_bit(STATUS_RF_KILL_HW, &priv->status));
IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
new_rfkill ? "disable radio" : "enable radio");
}
/* Keep this running, even if radio now enabled. This will be
* cancelled in mac_start() if system decides to start again */
queue_delayed_work(priv->workqueue, &priv->rfkill_poll, queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
round_jiffies_relative(2 * HZ)); round_jiffies_relative(2 * HZ));
@ -3797,7 +3806,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */ /* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv); iwl_clear_stations_table(priv);
priv->data_retry_limit = -1;
priv->ieee_channels = NULL; priv->ieee_channels = NULL;
priv->ieee_rates = NULL; priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ; priv->band = IEEE80211_BAND_2GHZ;
@ -4056,6 +4064,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
&priv->bands[IEEE80211_BAND_2GHZ].channels[5]); &priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
iwl3945_setup_deferred_work(priv); iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv); iwl3945_setup_rx_handlers(priv);
iwl_power_initialize(priv);
/********************************* /*********************************
* 8. Setup and Register mac80211 * 8. Setup and Register mac80211
@ -4126,6 +4135,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_down(priv); iwl3945_down(priv);
} }
/*
* Make sure device is reset to low power before unloading driver.
* This may be redundant with iwl_down(), but there are paths to
* run iwl_down() without calling apm_ops.stop(), and there are
* paths to avoid running iwl_down() at all before leaving driver.
* This (inexpensive) call *makes sure* device is reset.
*/
priv->cfg->ops->lib->apm_ops.stop(priv);
/* make sure we flush any pending irq or /* make sure we flush any pending irq or
* tasklet for the driver * tasklet for the driver
*/ */

View File

@ -404,39 +404,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
{ {
struct iwm_priv *iwm = wiphy_to_iwm(wiphy); struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
struct ieee80211_channel *chan = params->channel; struct ieee80211_channel *chan = params->channel;
struct cfg80211_bss *bss;
if (!test_bit(IWM_STATUS_READY, &iwm->status)) if (!test_bit(IWM_STATUS_READY, &iwm->status))
return -EIO; return -EIO;
/* UMAC doesn't support creating IBSS network with specified bssid. /* UMAC doesn't support creating or joining an IBSS network
* This should be removed after we have join only mode supported. */ * with specified bssid. */
if (params->bssid) if (params->bssid)
return -EOPNOTSUPP; return -EOPNOTSUPP;
bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
params->ssid, params->ssid_len);
if (!bss) {
iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
schedule_timeout_interruptible(2 * HZ);
bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
params->ssid, params->ssid_len);
}
/* IBSS join only mode is not supported by UMAC ATM */
if (bss) {
cfg80211_put_bss(bss);
return -EOPNOTSUPP;
}
iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
iwm->umac_profile->ibss.band = chan->band; iwm->umac_profile->ibss.band = chan->band;
iwm->umac_profile->ibss.channel = iwm->channel; iwm->umac_profile->ibss.channel = iwm->channel;
iwm->umac_profile->ssid.ssid_len = params->ssid_len; iwm->umac_profile->ssid.ssid_len = params->ssid_len;
memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
if (params->bssid)
memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
return iwm_send_mlme_profile(iwm); return iwm_send_mlme_profile(iwm);
} }
@ -489,12 +471,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
return 0; return 0;
} }
if (wpa_version & NL80211_WPA_VERSION_1)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
if (wpa_version & NL80211_WPA_VERSION_2) if (wpa_version & NL80211_WPA_VERSION_2)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
if (wpa_version & NL80211_WPA_VERSION_1)
iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
return 0; return 0;
} }
@ -645,6 +627,13 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
iwm->default_key = sme->key_idx; iwm->default_key = sme->key_idx;
} }
/* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
if ((iwm->umac_profile->sec.flags &
(UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
}
ret = iwm_send_mlme_profile(iwm); ret = iwm_send_mlme_profile(iwm);
if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
@ -681,9 +670,19 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
enum tx_power_setting type, int dbm) enum tx_power_setting type, int dbm)
{ {
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
int ret;
switch (type) { switch (type) {
case TX_POWER_AUTOMATIC: case TX_POWER_AUTOMATIC:
return 0; return 0;
case TX_POWER_FIXED:
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_TX_PWR_LIMIT_USR, dbm * 2);
if (ret < 0)
return ret;
return iwm_tx_power_trigger(iwm);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -695,7 +694,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
{ {
struct iwm_priv *iwm = wiphy_to_iwm(wiphy); struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
*dbm = iwm->txpower; *dbm = iwm->txpower >> 1;
return 0; return 0;
} }

View File

@ -76,6 +76,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
int ret; int ret;
u8 oid = hdr->oid; u8 oid = hdr->oid;
if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
IWM_ERR(iwm, "Interface is not ready yet");
return -EAGAIN;
}
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp; umac_cmd.resp = resp;
@ -274,6 +279,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm)
return ret; return ret;
} }
int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
{
struct iwm_ct_kill_cfg_cmd cmd;
cmd.entry_threshold = entry;
cmd.exit_threshold = exit;
return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
sizeof(struct iwm_ct_kill_cfg_cmd), 0);
}
int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
{ {
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
@ -777,11 +793,24 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
return ret; return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue, ret = wait_event_interruptible_timeout(iwm->mlme_queue,
(iwm->umac_profile_active == 0), 2 * HZ); (iwm->umac_profile_active == 0), 5 * HZ);
return ret ? 0 : -EBUSY; return ret ? 0 : -EBUSY;
} }
int iwm_tx_power_trigger(struct iwm_priv *iwm)
{
struct iwm_umac_pwr_trigger pwr_trigger;
pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER;
pwr_trigger.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) -
sizeof(struct iwm_umac_wifi_if));
return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1);
}
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
{ {
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;

View File

@ -102,7 +102,6 @@ enum {
CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
CFG_TLC_SUPPORTED_TX_HT_RATES, CFG_TLC_SUPPORTED_TX_HT_RATES,
CFG_TLC_SUPPORTED_TX_RATES, CFG_TLC_SUPPORTED_TX_RATES,
CFG_TLC_VALID_ANTENNA,
CFG_TLC_SPATIAL_STREAM_SUPPORTED, CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE, CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE, CFG_TLC_RETRY_PER_HT_RATE,
@ -136,6 +135,10 @@ enum {
CFG_TLC_RENEW_ADDBA_DELAY, CFG_TLC_RENEW_ADDBA_DELAY,
CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
CFG_TLC_IS_STABLE_IN_HT, CFG_TLC_IS_STABLE_IN_HT,
CFG_TLC_SR_SIC_1ST_FAIL,
CFG_TLC_SR_SIC_1ST_PASS,
CFG_TLC_SR_SIC_TOTAL_FAIL,
CFG_TLC_SR_SIC_TOTAL_PASS,
CFG_RLC_CHAIN_CTRL, CFG_RLC_CHAIN_CTRL,
CFG_TRK_TABLE_OP_MODE, CFG_TRK_TABLE_OP_MODE,
CFG_TRK_TABLE_RSSI_THRESHOLD, CFG_TRK_TABLE_RSSI_THRESHOLD,
@ -147,6 +150,58 @@ enum {
CFG_MLME_DBG_NOTIF_BLOCK, CFG_MLME_DBG_NOTIF_BLOCK,
CFG_BT_OFF_BECONS_INTERVALS, CFG_BT_OFF_BECONS_INTERVALS,
CFG_BT_FRAG_DURATION, CFG_BT_FRAG_DURATION,
CFG_ACTIVE_CHAINS,
CFG_CALIB_CTRL,
CFG_CAPABILITY_SUPPORTED_HT_RATES,
CFG_HT_MAC_PARAM_INFO,
CFG_MIMO_PS_MODE,
CFG_HT_DEFAULT_CAPABILIES_INFO,
CFG_LED_SC_RESOLUTION_FACTOR,
CFG_PTAM_ENERGY_CCK_DET_DEFAULT,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT,
CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT,
CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT,
CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT,
CFG_PTAM_ENERGY_CCK_DET_MIN_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL,
CFG_PTAM_ENERGY_CCK_DET_MAX_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL,
CFG_PTAM_ENERGY_CCK_DET_STEP_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL,
CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL,
CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL,
CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL,
CFG_PTAM_LINK_SENS_FA_OFDM_MAX,
CFG_PTAM_LINK_SENS_FA_OFDM_MIN,
CFG_PTAM_LINK_SENS_FA_CCK_MAX,
CFG_PTAM_LINK_SENS_FA_CCK_MIN,
CFG_PTAM_LINK_SENS_NRG_DIFF,
CFG_PTAM_LINK_SENS_NRG_MARGIN,
CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA,
CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK,
CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD,
CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD,
CFG_AGG_MGG_ADDBA_BUF_SIZE,
CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT,
CFG_AGG_MGG_ADDBA_DEBUG_FLAGS,
CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD,
CFG_SCAN_PERIODIC_COEF_RSSI_HIGH,
CFG_11D_ENABLED,
CFG_11H_FEATURE_FLAGS,
/* <-- LAST --> */ /* <-- LAST --> */
CFG_TBL_FIX_LAST CFG_TBL_FIX_LAST
@ -155,7 +210,8 @@ enum {
/* variable size table */ /* variable size table */
enum { enum {
CFG_NET_ADDR = 0, CFG_NET_ADDR = 0,
CFG_PROFILE, CFG_LED_PATTERN_TABLE,
/* <-- LAST --> */ /* <-- LAST --> */
CFG_TBL_VAR_LAST CFG_TBL_VAR_LAST
}; };
@ -288,6 +344,9 @@ struct iwm_umac_cmd_scan_request {
/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ /* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
#define UMAC_SEC_FLG_WSC_ON_POS 2 #define UMAC_SEC_FLG_WSC_ON_POS 2
#define UMAC_SEC_FLG_WSC_ON_SEED 1 #define UMAC_SEC_FLG_WSC_ON_SEED 1
#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \
UMAC_SEC_FLG_WSC_ON_POS)
/* Legacy profile can use only WEP40 and WEP104 for encryption and /* Legacy profile can use only WEP40 and WEP104 for encryption and
* OPEN or PSK for authentication */ * OPEN or PSK for authentication */
@ -382,6 +441,11 @@ struct iwm_umac_tx_key_id {
u8 reserved[3]; u8 reserved[3];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct iwm_umac_pwr_trigger {
struct iwm_umac_wifi_if hdr;
__le32 reseved;
} __attribute__ ((packed));
struct iwm_umac_cmd_stats_req { struct iwm_umac_cmd_stats_req {
__le32 flags; __le32 flags;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -393,6 +457,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_calib_results(struct iwm_priv *iwm); int iwm_send_calib_results(struct iwm_priv *iwm);
int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
/* UMAC commands */ /* UMAC commands */
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
@ -407,6 +472,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_tx_power_trigger(struct iwm_priv *iwm);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,

View File

@ -217,6 +217,13 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
IWM_BUILD_DAY(build_date)); IWM_BUILD_DAY(build_date));
if (!strcmp(img_name, iwm->bus_ops->umac_name))
sprintf(iwm->umac_version, "%02X.%02X",
ver->major, ver->minor);
if (!strcmp(img_name, iwm->bus_ops->lmac_name))
sprintf(iwm->lmac_version, "%02X.%02X",
ver->major, ver->minor);
err_release_fw: err_release_fw:
release_firmware(fw); release_firmware(fw);
@ -398,6 +405,8 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm); iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm); iwm_send_calib_results(iwm);
iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
iwm->conf.ct_kill_exit);
return 0; return 0;

View File

@ -65,6 +65,8 @@ struct iwm_conf {
u32 sdio_ior_timeout; u32 sdio_ior_timeout;
unsigned long calib_map; unsigned long calib_map;
unsigned long expected_calib_map; unsigned long expected_calib_map;
u8 ct_kill_entry;
u8 ct_kill_exit;
bool reset_on_fatal_err; bool reset_on_fatal_err;
bool auto_connect; bool auto_connect;
bool wimax_not_present; bool wimax_not_present;
@ -276,12 +278,14 @@ struct iwm_priv {
struct iw_statistics wstats; struct iw_statistics wstats;
struct delayed_work stats_request; struct delayed_work stats_request;
struct delayed_work disconnect; struct delayed_work disconnect;
struct delayed_work ct_kill_delay;
struct iwm_debugfs dbg; struct iwm_debugfs dbg;
u8 *eeprom; u8 *eeprom;
struct timer_list watchdog; struct timer_list watchdog;
struct work_struct reset_worker; struct work_struct reset_worker;
struct work_struct auth_retry_worker;
struct mutex mutex; struct mutex mutex;
u8 *req_ie; u8 *req_ie;
@ -290,6 +294,8 @@ struct iwm_priv {
int resp_ie_len; int resp_ie_len;
struct iwm_fw_error_hdr *last_fw_err; struct iwm_fw_error_hdr *last_fw_err;
char umac_version[8];
char lmac_version[8];
char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
}; };

View File

@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd {
COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
/* CT kill config command */
struct iwm_ct_kill_cfg_cmd {
u32 exit_threshold;
u32 reserved;
u32 entry_threshold;
} __attribute__ ((packed));
/* LMAC OP CODES */ /* LMAC OP CODES */
#define REPLY_PAD 0x0 #define REPLY_PAD 0x0
#define REPLY_ALIVE 0x1 #define REPLY_ALIVE 0x1

View File

@ -63,6 +63,8 @@ static struct iwm_conf def_iwm_conf = {
BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) |
BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
.ct_kill_entry = 110,
.ct_kill_exit = 110,
.reset_on_fatal_err = 1, .reset_on_fatal_err = 1,
.auto_connect = 1, .auto_connect = 1,
.wimax_not_present = 0, .wimax_not_present = 0,
@ -133,6 +135,17 @@ static void iwm_disconnect_work(struct work_struct *work)
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
} }
static void iwm_ct_kill_work(struct work_struct *work)
{
struct iwm_priv *iwm =
container_of(work, struct iwm_priv, ct_kill_delay.work);
struct wiphy *wiphy = iwm_to_wiphy(iwm);
IWM_INFO(iwm, "CT kill delay timeout\n");
wiphy_rfkill_set_hw_state(wiphy, false);
}
static int __iwm_up(struct iwm_priv *iwm); static int __iwm_up(struct iwm_priv *iwm);
static int __iwm_down(struct iwm_priv *iwm); static int __iwm_down(struct iwm_priv *iwm);
@ -194,6 +207,33 @@ static void iwm_reset_worker(struct work_struct *work)
mutex_unlock(&iwm->mutex); mutex_unlock(&iwm->mutex);
} }
static void iwm_auth_retry_worker(struct work_struct *work)
{
struct iwm_priv *iwm;
int i, ret;
iwm = container_of(work, struct iwm_priv, auth_retry_worker);
if (iwm->umac_profile_active) {
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0)
return;
}
iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
ret = iwm_send_mlme_profile(iwm);
if (ret < 0)
return;
for (i = 0; i < IWM_NUM_KEYS; i++)
if (iwm->keys[i].key_len)
iwm_set_key(iwm, 0, &iwm->keys[i]);
iwm_set_tx_key(iwm, iwm->default_key);
}
static void iwm_watchdog(unsigned long data) static void iwm_watchdog(unsigned long data)
{ {
struct iwm_priv *iwm = (struct iwm_priv *)data; struct iwm_priv *iwm = (struct iwm_priv *)data;
@ -225,7 +265,9 @@ int iwm_priv_init(struct iwm_priv *iwm)
iwm->scan_id = 1; iwm->scan_id = 1;
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
INIT_WORK(&iwm->reset_worker, iwm_reset_worker); INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker);
INIT_LIST_HEAD(&iwm->bss_list); INIT_LIST_HEAD(&iwm->bss_list);
skb_queue_head_init(&iwm->rx_list); skb_queue_head_init(&iwm->rx_list);
@ -586,6 +628,7 @@ static int __iwm_up(struct iwm_priv *iwm)
{ {
int ret; int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL; struct iwm_notif *notif_reboot, *notif_ack = NULL;
struct wiphy *wiphy = iwm_to_wiphy(iwm);
ret = iwm_bus_enable(iwm); ret = iwm_bus_enable(iwm);
if (ret) { if (ret) {
@ -647,6 +690,9 @@ static int __iwm_up(struct iwm_priv *iwm)
goto err_disable; goto err_disable;
} }
snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
iwm->lmac_version, iwm->umac_version);
/* We configure the UMAC and enable the wifi module */ /* We configure the UMAC and enable the wifi module */
ret = iwm_send_umac_config(iwm, ret = iwm_send_umac_config(iwm,
cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |

View File

@ -152,6 +152,7 @@ void iwm_if_free(struct iwm_priv *iwm)
if (!iwm_to_ndev(iwm)) if (!iwm_to_ndev(iwm))
return; return;
cancel_delayed_work_sync(&iwm->ct_kill_delay);
free_netdev(iwm_to_ndev(iwm)); free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm); iwm_priv_deinit(iwm);
kfree(iwm->umac_profile); kfree(iwm->umac_profile);

View File

@ -422,7 +422,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node)) if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node); return PTR_ERR(ticket_node);
IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
ticket->action == IWM_RX_TICKET_RELEASE ?
"RELEASE" : "DROP",
ticket->id); ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets); list_add_tail(&ticket_node->node, &iwm->rx_tickets);
@ -499,6 +501,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
return 0; return 0;
} }
static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
{
if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
(iwm->umac_profile->sec.ucast_cipher ==
iwm->umac_profile->sec.mcast_cipher) &&
(iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
return 1;
return 0;
}
static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, unsigned long buf_size,
struct iwm_wifi_cmd *cmd) struct iwm_wifi_cmd *cmd)
@ -564,11 +578,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
goto ibss; goto ibss;
if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
cfg80211_connect_result(iwm_to_ndev(iwm), if (!iwm_is_open_wep_profile(iwm)) {
complete->bssid, cfg80211_connect_result(iwm_to_ndev(iwm),
NULL, 0, NULL, 0, complete->bssid,
WLAN_STATUS_UNSPECIFIED_FAILURE, NULL, 0, NULL, 0,
GFP_KERNEL); WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
} else {
/* Let's try shared WEP auth */
IWM_ERR(iwm, "Trying WEP shared auth\n");
schedule_work(&iwm->auth_retry_worker);
}
else else
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
GFP_KERNEL); GFP_KERNEL);
@ -712,6 +732,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
return 0; return 0;
} }
static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
wiphy_rfkill_set_hw_state(wiphy, true);
return 0;
}
static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, unsigned long buf_size,
struct iwm_wifi_cmd *cmd) struct iwm_wifi_cmd *cmd)
@ -898,6 +931,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
break; break;
case WIFI_IF_NTFY_RADIO_PREEMPTION:
return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
@ -1055,8 +1090,14 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, unsigned long buf_size,
struct iwm_wifi_cmd *cmd) struct iwm_wifi_cmd *cmd)
{ {
struct iwm_umac_wifi_if *hdr = struct iwm_umac_wifi_if *hdr;
(struct iwm_umac_wifi_if *)cmd->buf.payload;
if (cmd == NULL) {
IWM_ERR(iwm, "Couldn't find expected wifi command\n");
return -EINVAL;
}
hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
"oid is 0x%x\n", hdr->oid); "oid is 0x%x\n", hdr->oid);
@ -1078,6 +1119,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
return 0; return 0;
} }
#define CT_KILL_DELAY (30 * HZ)
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd) unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{ {
@ -1090,7 +1132,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
/*
* We got a CTKILL event: We bring the interface down in
* oder to cool the device down, and try to bring it up
* 30 seconds later. If it's still too hot, we'll go through
* this code path again.
*/
cancel_delayed_work_sync(&iwm->ct_kill_delay);
schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
}
wiphy_rfkill_set_hw_state(wiphy, flags &
(IWM_CARD_STATE_HW_DISABLED |
IWM_CARD_STATE_CTKILL_DISABLED));
return 0; return 0;
} }
@ -1281,6 +1336,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
switch (le32_to_cpu(hdr->cmd)) { switch (le32_to_cpu(hdr->cmd)) {
case UMAC_REBOOT_BARKER: case UMAC_REBOOT_BARKER:
if (test_bit(IWM_STATUS_READY, &iwm->status)) {
IWM_ERR(iwm, "Unexpected BARKER\n");
schedule_work(&iwm->reset_worker);
return 0;
}
return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
IWM_SRC_UDMA, buf, buf_size); IWM_SRC_UDMA, buf, buf_size);
case UMAC_ACK_BARKER: case UMAC_ACK_BARKER:
@ -1443,7 +1506,8 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
} }
break; break;
case IWM_RX_TICKET_DROP: case IWM_RX_TICKET_DROP:
IWM_DBG_RX(iwm, DBG, "DROP packet\n"); IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
le16_to_cpu(ticket_node->ticket->flags));
kfree_skb(packet->skb); kfree_skb(packet->skb);
break; break;
default: default:

View File

@ -224,8 +224,6 @@ static int if_sdio_disable(struct iwm_priv *iwm)
struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
int ret; int ret;
iwm_reset(iwm);
sdio_claim_host(hw->func); sdio_claim_host(hw->func);
sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
if (ret < 0) if (ret < 0)
@ -237,6 +235,8 @@ static int if_sdio_disable(struct iwm_priv *iwm)
iwm_sdio_rx_free(hw); iwm_sdio_rx_free(hw);
iwm_reset(iwm);
IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
return 0; return 0;
@ -493,8 +493,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
} }
static const struct sdio_device_id iwm_sdio_ids[] = { static const struct sdio_device_id iwm_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, /* Global/AGN SKU */
SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) },
/* BGN SKU */
{ SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) },
{ /* end: all zeroes */ }, { /* end: all zeroes */ },
}; };
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);

View File

@ -687,6 +687,9 @@ struct iwm_umac_notif_rx_ticket {
/* Tx/Rx rates window (number of max of last update window per second) */ /* Tx/Rx rates window (number of max of last update window per second) */
#define UMAC_NTF_RATE_SAMPLE_NR 4 #define UMAC_NTF_RATE_SAMPLE_NR 4
/* Max numbers of bits required to go through all antennae in bitmasks */
#define UMAC_PHY_NUM_CHAINS 3
#define IWM_UMAC_MGMT_TID 8 #define IWM_UMAC_MGMT_TID 8
#define IWM_UMAC_TID_NR 8 #define IWM_UMAC_TID_NR 8
@ -697,9 +700,11 @@ struct iwm_umac_notif_stats {
__le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */
__le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le32 chain_energy[UMAC_PHY_NUM_CHAINS];
s32 rssi_dbm; s32 rssi_dbm;
s32 noise_dbm; s32 noise_dbm;
__le32 supp_rates; __le32 supp_rates;
__le32 supp_ht_rates;
__le32 missed_beacons; __le32 missed_beacons;
__le32 rx_beacons; __le32 rx_beacons;
__le32 rx_dir_pkts; __le32 rx_dir_pkts;

View File

@ -1,696 +0,0 @@
/**
* This file contains functions for 802.11D.
*/
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/wireless.h>
#include "host.h"
#include "decl.h"
#include "11d.h"
#include "dev.h"
#include "wext.h"
#define TX_PWR_DEFAULT 10
static struct region_code_mapping region_code_mapping[] = {
{"US ", 0x10}, /* US FCC */
{"CA ", 0x10}, /* IC Canada */
{"SG ", 0x10}, /* Singapore */
{"EU ", 0x30}, /* ETSI */
{"AU ", 0x30}, /* Australia */
{"KR ", 0x30}, /* Republic Of Korea */
{"ES ", 0x31}, /* Spain */
{"FR ", 0x32}, /* France */
{"JP ", 0x40}, /* Japan */
};
/* Following 2 structure defines the supported channels */
static struct chan_freq_power channel_freq_power_UN_BG[] = {
{1, 2412, TX_PWR_DEFAULT},
{2, 2417, TX_PWR_DEFAULT},
{3, 2422, TX_PWR_DEFAULT},
{4, 2427, TX_PWR_DEFAULT},
{5, 2432, TX_PWR_DEFAULT},
{6, 2437, TX_PWR_DEFAULT},
{7, 2442, TX_PWR_DEFAULT},
{8, 2447, TX_PWR_DEFAULT},
{9, 2452, TX_PWR_DEFAULT},
{10, 2457, TX_PWR_DEFAULT},
{11, 2462, TX_PWR_DEFAULT},
{12, 2467, TX_PWR_DEFAULT},
{13, 2472, TX_PWR_DEFAULT},
{14, 2484, TX_PWR_DEFAULT}
};
static u8 lbs_region_2_code(u8 *region)
{
u8 i;
for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
region[i] = toupper(region[i]);
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
if (!memcmp(region, region_code_mapping[i].region,
COUNTRY_CODE_LEN))
return (region_code_mapping[i].code);
}
/* default is US */
return (region_code_mapping[0].code);
}
static u8 *lbs_code_2_region(u8 code)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
if (region_code_mapping[i].code == code)
return (region_code_mapping[i].region);
}
/* default is US */
return (region_code_mapping[0].region);
}
/**
* @brief This function finds the nrchan-th chan after the firstchan
* @param band band
* @param firstchan first channel number
* @param nrchan number of channels
* @return the nrchan-th chan number
*/
static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
/*find the nrchan-th chan after the firstchan*/
{
u8 i;
struct chan_freq_power *cfp;
u8 cfp_no;
cfp = channel_freq_power_UN_BG;
cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
for (i = 0; i < cfp_no; i++) {
if ((cfp + i)->channel == firstchan) {
lbs_deb_11d("firstchan found\n");
break;
}
}
if (i < cfp_no) {
/*if beyond the boundary */
if (i + nrchan < cfp_no) {
*chan = (cfp + i + nrchan)->channel;
return 1;
}
}
return 0;
}
/**
* @brief This function Checks if chan txpwr is learned from AP/IBSS
* @param chan chan number
* @param parsed_region_chan pointer to parsed_region_chan_11d
* @return TRUE; FALSE
*/
static u8 lbs_channel_known_11d(u8 chan,
struct parsed_region_chan_11d * parsed_region_chan)
{
struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
u8 nr_chan = parsed_region_chan->nr_chan;
u8 i = 0;
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
sizeof(struct chan_power_11d) * nr_chan);
for (i = 0; i < nr_chan; i++) {
if (chan == chanpwr[i].chan) {
lbs_deb_11d("found chan %d\n", chan);
return 1;
}
}
lbs_deb_11d("chan %d not found\n", chan);
return 0;
}
u32 lbs_chan_2_freq(u8 chan)
{
struct chan_freq_power *cf;
u16 i;
u32 freq = 0;
cf = channel_freq_power_UN_BG;
for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
if (chan == cf[i].channel)
freq = cf[i].freq;
}
return freq;
}
static int generate_domain_info_11d(struct parsed_region_chan_11d
*parsed_region_chan,
struct lbs_802_11d_domain_reg *domaininfo)
{
u8 nr_subband = 0;
u8 nr_chan = parsed_region_chan->nr_chan;
u8 nr_parsedchan = 0;
u8 firstchan = 0, nextchan = 0, maxpwr = 0;
u8 i, flag = 0;
memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
COUNTRY_CODE_LEN);
lbs_deb_11d("nrchan %d\n", nr_chan);
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
sizeof(struct parsed_region_chan_11d));
for (i = 0; i < nr_chan; i++) {
if (!flag) {
flag = 1;
nextchan = firstchan =
parsed_region_chan->chanpwr[i].chan;
maxpwr = parsed_region_chan->chanpwr[i].pwr;
nr_parsedchan = 1;
continue;
}
if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
parsed_region_chan->chanpwr[i].pwr == maxpwr) {
nextchan++;
nr_parsedchan++;
} else {
domaininfo->subband[nr_subband].firstchan = firstchan;
domaininfo->subband[nr_subband].nrchan =
nr_parsedchan;
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
nr_subband++;
nextchan = firstchan =
parsed_region_chan->chanpwr[i].chan;
maxpwr = parsed_region_chan->chanpwr[i].pwr;
}
}
if (flag) {
domaininfo->subband[nr_subband].firstchan = firstchan;
domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
nr_subband++;
}
domaininfo->nr_subband = nr_subband;
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
COUNTRY_CODE_LEN + 1 +
sizeof(struct ieee_subbandset) * nr_subband);
return 0;
}
/**
* @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
* @param region_chan pointer to struct region_channel
* @param *parsed_region_chan pointer to parsed_region_chan_11d
* @return N/A
*/
static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
struct parsed_region_chan_11d *
parsed_region_chan)
{
u8 i;
struct chan_freq_power *cfp;
if (region_chan == NULL) {
lbs_deb_11d("region_chan is NULL\n");
return;
}
cfp = region_chan->CFP;
if (cfp == NULL) {
lbs_deb_11d("cfp is NULL \n");
return;
}
parsed_region_chan->band = region_chan->band;
parsed_region_chan->region = region_chan->region;
memcpy(parsed_region_chan->countrycode,
lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
parsed_region_chan->band);
for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
parsed_region_chan->chanpwr[i].chan = cfp->channel;
parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
lbs_deb_11d("chan %d, pwr %d\n",
parsed_region_chan->chanpwr[i].chan,
parsed_region_chan->chanpwr[i].pwr);
}
parsed_region_chan->nr_chan = region_chan->nrcfp;
lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
return;
}
/**
* @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
* @param region region ID
* @param band band
* @param chan chan
* @return TRUE;FALSE
*/
static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
{
struct chan_freq_power *cfp;
int cfp_no;
u8 idx;
int ret = 0;
lbs_deb_enter(LBS_DEB_11D);
cfp = lbs_get_region_cfp_table(region, &cfp_no);
if (cfp == NULL)
return 0;
for (idx = 0; idx < cfp_no; idx++) {
if (chan == (cfp + idx)->channel) {
/* If Mrvl Chip Supported? */
if ((cfp + idx)->unsupported) {
ret = 0;
} else {
ret = 1;
}
goto done;
}
}
/*chan is not in the region table */
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
* @brief This function checks if chan txpwr is learned from AP/IBSS
* @param chan chan number
* @param parsed_region_chan pointer to parsed_region_chan_11d
* @return 0
*/
static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
u8 band,
struct parsed_region_chan_11d *parsed_region_chan)
{
u8 nr_subband, nrchan;
u8 lastchan, firstchan;
u8 region;
u8 curchan = 0;
u8 idx = 0; /*chan index in parsed_region_chan */
u8 j, i;
lbs_deb_enter(LBS_DEB_11D);
/*validation Rules:
1. valid region Code
2. First Chan increment
3. channel range no overlap
4. channel is valid?
5. channel is supported by region?
6. Others
*/
lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
if ((*(countryinfo->countrycode)) == 0
|| (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
/* No region Info or Wrong region info: treat as No 11D info */
goto done;
}
/*Step1: check region_code */
parsed_region_chan->region = region =
lbs_region_2_code(countryinfo->countrycode);
lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
COUNTRY_CODE_LEN);
parsed_region_chan->band = band;
memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
COUNTRY_CODE_LEN);
nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
sizeof(struct ieee_subbandset);
for (j = 0, lastchan = 0; j < nr_subband; j++) {
if (countryinfo->subband[j].firstchan <= lastchan) {
/*Step2&3. Check First Chan Num increment and no overlap */
lbs_deb_11d("chan %d>%d, overlap\n",
countryinfo->subband[j].firstchan, lastchan);
continue;
}
firstchan = countryinfo->subband[j].firstchan;
nrchan = countryinfo->subband[j].nrchan;
for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
/*step4: channel is supported? */
if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
/* Chan is not found in UN table */
lbs_deb_11d("chan is not supported: %d \n", i);
break;
}
lastchan = curchan;
if (lbs_region_chan_supported_11d(region, curchan)) {
/*step5: Check if curchan is supported by mrvl in region */
parsed_region_chan->chanpwr[idx].chan = curchan;
parsed_region_chan->chanpwr[idx].pwr =
countryinfo->subband[j].maxtxpwr;
idx++;
} else {
/*not supported and ignore the chan */
lbs_deb_11d(
"i %d, chan %d unsupported in region %x, band %d\n",
i, curchan, region, band);
}
}
/*Step6: Add other checking if any */
}
parsed_region_chan->nr_chan = idx;
lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
done:
lbs_deb_enter(LBS_DEB_11D);
return 0;
}
/**
* @brief This function calculates the scan type for channels
* @param chan chan number
* @param parsed_region_chan pointer to parsed_region_chan_11d
* @return PASSIVE if chan is unknown; ACTIVE if chan is known
*/
u8 lbs_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d * parsed_region_chan)
{
u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
lbs_deb_enter(LBS_DEB_11D);
if (lbs_channel_known_11d(chan, parsed_region_chan)) {
lbs_deb_11d("found, do active scan\n");
scan_type = CMD_SCAN_TYPE_ACTIVE;
} else {
lbs_deb_11d("not found, do passive scan\n");
}
lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
return scan_type;
}
void lbs_init_11d(struct lbs_private *priv)
{
priv->enable11d = 0;
memset(&(priv->parsed_region_chan), 0,
sizeof(struct parsed_region_chan_11d));
return;
}
/**
* @brief This function sets DOMAIN INFO to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
static int set_domain_info_11d(struct lbs_private *priv)
{
int ret;
if (!priv->enable11d) {
lbs_deb_11d("dnld domain Info with 11d disabled\n");
return 0;
}
ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
CMD_ACT_SET,
CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
lbs_deb_11d("fail to dnld domain info\n");
return ret;
}
/**
* @brief This function setups scan channels
* @param priv pointer to struct lbs_private
* @param band band
* @return 0
*/
int lbs_set_universaltable(struct lbs_private *priv, u8 band)
{
u16 size = sizeof(struct chan_freq_power);
u16 i = 0;
memset(priv->universal_channel, 0,
sizeof(priv->universal_channel));
priv->universal_channel[i].nrcfp =
sizeof(channel_freq_power_UN_BG) / size;
lbs_deb_11d("BG-band nrcfp %d\n",
priv->universal_channel[i].nrcfp);
priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
priv->universal_channel[i].valid = 1;
priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
priv->universal_channel[i].band = band;
i++;
return 0;
}
/**
* @brief This function implements command CMD_802_11D_DOMAIN_INFO
* @param priv pointer to struct lbs_private
* @param cmd pointer to cmd buffer
* @param cmdno cmd ID
* @param cmdOption cmd action
* @return 0
*/
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
struct cmd_ds_command *cmd, u16 cmdno,
u16 cmdoption)
{
struct cmd_ds_802_11d_domain_info *pdomaininfo =
&cmd->params.domaininfo;
struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
u8 nr_subband = priv->domainreg.nr_subband;
lbs_deb_enter(LBS_DEB_11D);
lbs_deb_11d("nr_subband=%x\n", nr_subband);
cmd->command = cpu_to_le16(cmdno);
pdomaininfo->action = cpu_to_le16(cmdoption);
if (cmdoption == CMD_ACT_GET) {
cmd->size =
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
le16_to_cpu(cmd->size));
goto done;
}
domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
memcpy(domain->countrycode, priv->domainreg.countrycode,
sizeof(domain->countrycode));
domain->header.len =
cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
sizeof(domain->countrycode));
if (nr_subband) {
memcpy(domain->subband, priv->domainreg.subband,
nr_subband * sizeof(struct ieee_subbandset));
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
le16_to_cpu(domain->header.len) +
sizeof(struct mrvl_ie_header) +
S_DS_GEN);
} else {
cmd->size =
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
}
lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
done:
lbs_deb_enter(LBS_DEB_11D);
return 0;
}
/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to struct lbs_private
* @param resp pointer to command response buffer
* @return 0; -1
*/
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
{
struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
u16 action = le16_to_cpu(domaininfo->action);
s16 ret = 0;
u8 nr_subband = 0;
lbs_deb_enter(LBS_DEB_11D);
lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
(int)le16_to_cpu(resp->size));
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
sizeof(struct ieee_subbandset);
lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
return -1;
}
switch (action) {
case CMD_ACT_SET: /*Proc Set action */
break;
case CMD_ACT_GET:
break;
default:
lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
ret = -1;
break;
}
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
struct bss_descriptor * bss)
{
int ret;
lbs_deb_enter(LBS_DEB_11D);
if (priv->enable11d) {
memset(&priv->parsed_region_chan, 0,
sizeof(struct parsed_region_chan_11d));
ret = parse_domain_info_11d(&bss->countryinfo, 0,
&priv->parsed_region_chan);
if (ret == -1) {
lbs_deb_11d("error parsing domain_info from AP\n");
goto done;
}
memset(&priv->domainreg, 0,
sizeof(struct lbs_802_11d_domain_reg));
generate_domain_info_11d(&priv->parsed_region_chan,
&priv->domainreg);
ret = set_domain_info_11d(priv);
if (ret) {
lbs_deb_11d("error setting domain info\n");
goto done;
}
}
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
* @brief This function generates 11D info from user specified regioncode and download to FW
* @param priv pointer to struct lbs_private
* @return 0; -1
*/
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
{
int ret;
struct region_channel *region_chan;
u8 j;
lbs_deb_enter(LBS_DEB_11D);
lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
if (priv->enable11d) {
/* update parsed_region_chan_11; dnld domaininf to FW */
for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
region_chan = &priv->region_channel[j];
lbs_deb_11d("%d region_chan->band %d\n", j,
region_chan->band);
if (!region_chan || !region_chan->valid
|| !region_chan->CFP)
continue;
if (region_chan->band != priv->curbssparams.band)
continue;
break;
}
if (j >= ARRAY_SIZE(priv->region_channel)) {
lbs_deb_11d("region_chan not found, band %d\n",
priv->curbssparams.band);
ret = -1;
goto done;
}
memset(&priv->parsed_region_chan, 0,
sizeof(struct parsed_region_chan_11d));
lbs_generate_parsed_region_chan_11d(region_chan,
&priv->
parsed_region_chan);
memset(&priv->domainreg, 0,
sizeof(struct lbs_802_11d_domain_reg));
generate_domain_info_11d(&priv->parsed_region_chan,
&priv->domainreg);
ret = set_domain_info_11d(priv);
if (ret) {
lbs_deb_11d("error setting domain info\n");
goto done;
}
}
ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}

View File

@ -1,105 +0,0 @@
/**
* This header file contains data structures and
* function declarations of 802.11d
*/
#ifndef _LBS_11D_
#define _LBS_11D_
#include "types.h"
#include "defs.h"
#define UNIVERSAL_REGION_CODE 0xff
/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
*/
#define MRVDRV_MAX_SUBBAND_802_11D 83
#define COUNTRY_CODE_LEN 3
#define MAX_NO_OF_CHAN 40
struct cmd_ds_command;
/** Data structure for Country IE*/
struct ieee_subbandset {
u8 firstchan;
u8 nrchan;
u8 maxtxpwr;
} __attribute__ ((packed));
struct ieee_ie_country_info_set {
struct ieee_ie_header header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieee_subbandset subband[1];
};
struct ieee_ie_country_info_full_set {
struct ieee_ie_header header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
} __attribute__ ((packed));
struct mrvl_ie_domain_param_set {
struct mrvl_ie_header header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieee_subbandset subband[1];
} __attribute__ ((packed));
struct cmd_ds_802_11d_domain_info {
__le16 action;
struct mrvl_ie_domain_param_set domain;
} __attribute__ ((packed));
/** domain regulatory information */
struct lbs_802_11d_domain_reg {
/** country Code*/
u8 countrycode[COUNTRY_CODE_LEN];
/** No. of subband*/
u8 nr_subband;
struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
};
struct chan_power_11d {
u8 chan;
u8 pwr;
} __attribute__ ((packed));
struct parsed_region_chan_11d {
u8 band;
u8 region;
s8 countrycode[COUNTRY_CODE_LEN];
struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
u8 nr_chan;
} __attribute__ ((packed));
struct region_code_mapping {
u8 region[COUNTRY_CODE_LEN];
u8 code;
};
struct lbs_private;
u8 lbs_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d *parsed_region_chan);
u32 lbs_chan_2_freq(u8 chan);
void lbs_init_11d(struct lbs_private *priv);
int lbs_set_universaltable(struct lbs_private *priv, u8 band);
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
struct cmd_ds_command *cmd, u16 cmdno,
u16 cmdOption);
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
struct bss_descriptor;
int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
struct bss_descriptor * bss);
int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
#endif

View File

@ -1,4 +1,3 @@
libertas-y += 11d.o
libertas-y += assoc.o libertas-y += assoc.o
libertas-y += cfg.o libertas-y += cfg.o
libertas-y += cmd.o libertas-y += cmd.o

View File

@ -23,6 +23,13 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*/ */
#define CAPINFO_MASK (~(0xda00)) #define CAPINFO_MASK (~(0xda00))
/**
* 802.11b/g supported bitrates (in 500Kb/s units)
*/
u8 lbs_bg_rates[MAX_RATES] =
{ 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
0x00, 0x00 };
/** /**
* @brief This function finds common rates between rates and card rates. * @brief This function finds common rates between rates and card rates.
@ -147,6 +154,397 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
} }
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_ADD) {
int i;
/* default tx key index */
cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
CMD_WEP_KEY_INDEX_MASK);
/* Copy key types and material to host command structure */
for (i = 0; i < 4; i++) {
struct enc_key *pkey = &assoc->wep_keys[i];
switch (pkey->len) {
case KEY_LEN_WEP_40:
cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
memmove(cmd.keymaterial[i], pkey->key, pkey->len);
lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
break;
case KEY_LEN_WEP_104:
cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
memmove(cmd.keymaterial[i], pkey->key, pkey->len);
lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
break;
case 0:
break;
default:
lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
i, pkey->len);
ret = -1;
goto done;
break;
}
}
} else if (cmd_action == CMD_ACT_REMOVE) {
/* ACT_REMOVE clears _all_ WEP keys */
/* default tx key index */
cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
CMD_WEP_KEY_INDEX_MASK);
lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
}
ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
done:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable)
{
struct cmd_ds_802_11_enable_rsn cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_GET)
cmd.enable = 0;
else {
if (*enable)
cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
else
cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
if (!ret && cmd_action == CMD_ACT_GET)
*enable = le16_to_cpu(cmd.enable);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
struct enc_key *key)
{
lbs_deb_enter(LBS_DEB_CMD);
if (key->flags & KEY_INFO_WPA_ENABLED)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
if (key->flags & KEY_INFO_WPA_UNICAST)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
if (key->flags & KEY_INFO_WPA_MCAST)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
keyparam->keytypeid = cpu_to_le16(key->type);
keyparam->keylen = cpu_to_le16(key->len);
memcpy(keyparam->key, key->key, key->len);
/* Length field doesn't include the {type,length} header */
keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
lbs_deb_leave(LBS_DEB_CMD);
}
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
struct cmd_ds_802_11_key_material cmd;
int ret = 0;
int index = 0;
lbs_deb_enter(LBS_DEB_CMD);
cmd.action = cpu_to_le16(cmd_action);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (cmd_action == CMD_ACT_GET) {
cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
} else {
memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
set_one_wpa_key(&cmd.keyParamSet[index],
&assoc->wpa_unicast_key);
index++;
}
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
set_one_wpa_key(&cmd.keyParamSet[index],
&assoc->wpa_mcast_key);
index++;
}
/* The common header and as many keys as we included */
cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
keyParamSet[index]));
}
ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
/* Copy the returned key to driver private data */
if (!ret && cmd_action == CMD_ACT_GET) {
void *buf_ptr = cmd.keyParamSet;
void *resp_end = &(&cmd)[1];
while (buf_ptr < resp_end) {
struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
struct enc_key *key;
uint16_t param_set_len = le16_to_cpu(keyparam->length);
uint16_t key_len = le16_to_cpu(keyparam->keylen);
uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
void *end;
end = (void *)keyparam + sizeof(keyparam->type)
+ sizeof(keyparam->length) + param_set_len;
/* Make sure we don't access past the end of the IEs */
if (end > resp_end)
break;
if (key_flags & KEY_INFO_WPA_UNICAST)
key = &priv->wpa_unicast_key;
else if (key_flags & KEY_INFO_WPA_MCAST)
key = &priv->wpa_mcast_key;
else
break;
/* Copy returned key into driver */
memset(key, 0, sizeof(struct enc_key));
if (key_len > sizeof(key->key))
break;
key->type = key_type;
key->flags = key_flags;
key->len = key_len;
memcpy(key->key, keyparam->key, key->len);
buf_ptr = end + 1;
}
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
{
/* Bit Rate
* 15:13 Reserved
* 12 54 Mbps
* 11 48 Mbps
* 10 36 Mbps
* 9 24 Mbps
* 8 18 Mbps
* 7 12 Mbps
* 6 9 Mbps
* 5 6 Mbps
* 4 Reserved
* 3 11 Mbps
* 2 5.5 Mbps
* 1 2 Mbps
* 0 1 Mbps
**/
uint16_t ratemask;
int i = lbs_data_rate_to_fw_index(rate);
if (lower_rates_ok)
ratemask = (0x1fef >> (12 - i));
else
ratemask = (1 << i);
return cpu_to_le16(ratemask);
}
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action)
{
struct cmd_ds_802_11_rate_adapt_rateset cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
if (!priv->cur_rate && !priv->enablehwauto)
return -EINVAL;
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
if (!ret && cmd_action == CMD_ACT_GET) {
priv->ratebitmap = le16_to_cpu(cmd.bitmap);
priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
/**
* @brief Set the data rate
*
* @param priv A pointer to struct lbs_private structure
* @param rate The desired data rate, or 0 to clear a locked rate
*
* @return 0 on success, error on failure
*/
int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
{
struct cmd_ds_802_11_data_rate cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (rate > 0) {
cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
if (cmd.rates[0] == 0) {
lbs_deb_cmd("DATA_RATE: invalid requested rate of"
" 0x%02X\n", rate);
ret = 0;
goto out;
}
lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
} else {
cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
lbs_deb_cmd("DATA_RATE: setting auto\n");
}
ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
if (ret)
goto out;
lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
/* FIXME: get actual rates FW can do if this command actually returns
* all data rates supported.
*/
priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
int lbs_cmd_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *cmd)
{
lbs_deb_enter(LBS_DEB_CMD);
cmd->command = cpu_to_le16(CMD_802_11_RSSI);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
sizeof(struct cmd_header));
cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
/* reset Beacon SNR/NF/RSSI values */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
lbs_deb_enter(LBS_DEB_CMD);
/* store the non average value */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
priv->NF[TYPE_BEACON][TYPE_NOAVG] =
get_unaligned_le16(&rssirsp->noisefloor);
priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
priv->NF[TYPE_BEACON][TYPE_AVG] =
get_unaligned_le16(&rssirsp->avgnoisefloor);
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
priv->NF[TYPE_BEACON][TYPE_NOAVG]);
priv->RSSI[TYPE_BEACON][TYPE_AVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
priv->RSSI[TYPE_BEACON][TYPE_AVG]);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
struct cmd_ds_command *cmd,
u16 cmd_action)
{
struct cmd_ds_802_11_beacon_control
*bcn_ctrl = &cmd->params.bcn_ctrl;
lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+ sizeof(struct cmd_header));
cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
bcn_ctrl->action = cpu_to_le16(cmd_action);
bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_beacon_control *bcn_ctrl =
&resp->params.bcn_ctrl;
lbs_deb_enter(LBS_DEB_CMD);
if (bcn_ctrl->action == CMD_ACT_GET) {
priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
}
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static int lbs_assoc_post(struct lbs_private *priv, static int lbs_assoc_post(struct lbs_private *priv,
struct cmd_ds_802_11_associate_response *resp) struct cmd_ds_802_11_associate_response *resp)
{ {
@ -226,7 +624,7 @@ static int lbs_assoc_post(struct lbs_private *priv,
priv->connect_status = LBS_CONNECTED; priv->connect_status = LBS_CONNECTED;
/* Update current SSID and BSSID */ /* Update current SSID and BSSID */
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len; priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
@ -369,12 +767,7 @@ static int lbs_associate(struct lbs_private *priv,
(u16)(pos - (u8 *) &cmd.iebuf)); (u16)(pos - (u8 *) &cmd.iebuf));
/* update curbssparams */ /* update curbssparams */
priv->curbssparams.channel = bss->phy.ds.channel; priv->channel = bss->phy.ds.channel;
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
}
ret = lbs_cmd_with_response(priv, command, &cmd); ret = lbs_cmd_with_response(priv, command, &cmd);
if (ret == 0) { if (ret == 0) {
@ -472,7 +865,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
/* Set the new SSID to current SSID */ /* Set the new SSID to current SSID */
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len; priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev); netif_carrier_on(priv->dev);
@ -487,7 +880,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
print_ssid(ssid, bss->ssid, bss->ssid_len), print_ssid(ssid, bss->ssid, bss->ssid_len),
priv->curbssparams.bssid, priv->curbssparams.bssid,
priv->curbssparams.channel); priv->channel);
done: done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@ -560,7 +953,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0; priv->adhoccreate = 0;
priv->curbssparams.channel = bss->channel; priv->channel = bss->channel;
/* Build the join command */ /* Build the join command */
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
@ -633,11 +1026,6 @@ static int lbs_adhoc_join(struct lbs_private *priv,
} }
} }
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto out;
}
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
if (ret == 0) { if (ret == 0) {
ret = lbs_adhoc_post(priv, ret = lbs_adhoc_post(priv,
@ -737,12 +1125,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
if (lbs_create_dnld_countryinfo_11d(priv)) {
lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
ret = -1;
goto out;
}
lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
assoc_req->channel, assoc_req->band); assoc_req->channel, assoc_req->band);
@ -1099,7 +1481,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
/* else send START command */ /* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n"); lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
IW_ESSID_MAX_SIZE); IEEE80211_MAX_SSID_LEN);
assoc_req->bss.ssid_len = assoc_req->ssid_len; assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_adhoc_start(priv, assoc_req); lbs_adhoc_start(priv, assoc_req);
} }
@ -1185,7 +1567,8 @@ static int assoc_helper_mode(struct lbs_private *priv,
} }
priv->mode = assoc_req->mode; priv->mode = assoc_req->mode;
ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode); ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
done: done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@ -1205,7 +1588,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done; goto done;
} }
if (assoc_req->channel == priv->curbssparams.channel) if (assoc_req->channel == priv->channel)
goto done; goto done;
if (priv->mesh_dev) { if (priv->mesh_dev) {
@ -1217,7 +1600,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
} }
lbs_deb_assoc("ASSOC: channel: %d -> %d\n", lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
priv->curbssparams.channel, assoc_req->channel); priv->channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel); ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0) if (ret < 0)
@ -1232,7 +1615,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done; goto done;
} }
if (assoc_req->channel != priv->curbssparams.channel) { if (assoc_req->channel != priv->channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
assoc_req->channel); assoc_req->channel);
goto restore_mesh; goto restore_mesh;
@ -1253,7 +1636,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh: restore_mesh:
if (priv->mesh_dev) if (priv->mesh_dev)
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel); priv->channel);
done: done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@ -1475,7 +1858,7 @@ static int should_stop_adhoc(struct lbs_private *priv,
} }
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
if (assoc_req->channel != priv->curbssparams.channel) if (assoc_req->channel != priv->channel)
return 1; return 1;
} }
@ -1557,7 +1940,7 @@ static int lbs_find_best_network_ssid(struct lbs_private *priv,
found = lbs_find_best_ssid_in_list(priv, preferred_mode); found = lbs_find_best_ssid_in_list(priv, preferred_mode);
if (found && (found->ssid_len > 0)) { if (found && (found->ssid_len > 0)) {
memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
*out_ssid_len = found->ssid_len; *out_ssid_len = found->ssid_len;
*out_mode = found->mode; *out_mode = found->mode;
ret = 0; ret = 0;
@ -1775,12 +2158,12 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
assoc_req = priv->pending_assoc_req; assoc_req = priv->pending_assoc_req;
if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
IW_ESSID_MAX_SIZE); IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = priv->curbssparams.ssid_len; assoc_req->ssid_len = priv->curbssparams.ssid_len;
} }
if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
assoc_req->channel = priv->curbssparams.channel; assoc_req->channel = priv->channel;
if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
assoc_req->band = priv->curbssparams.band; assoc_req->band = priv->curbssparams.band;

View File

@ -3,7 +3,126 @@
#ifndef _LBS_ASSOC_H_ #ifndef _LBS_ASSOC_H_
#define _LBS_ASSOC_H_ #define _LBS_ASSOC_H_
#include "dev.h"
#include "defs.h"
#include "host.h"
struct lbs_private;
/*
* In theory, the IE is limited to the IE length, 255,
* but in practice 64 bytes are enough.
*/
#define MAX_WPA_IE_LEN 64
struct lbs_802_11_security {
u8 WPAenabled;
u8 WPA2enabled;
u8 wep_enabled;
u8 auth_mode;
u32 key_mgmt;
};
/** Current Basic Service Set State Structure */
struct current_bss_params {
/** bssid */
u8 bssid[ETH_ALEN];
/** ssid */
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
/** band */
u8 band;
/** channel is directly in priv->channel */
/** zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
};
/**
* @brief Structure used to store information for each beacon/probe response
*/
struct bss_descriptor {
u8 bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
u16 capability;
u32 rssi;
u32 channel;
u16 beaconperiod;
__le16 atimwindow;
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
/* zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
unsigned long last_scanned;
union ieee_phy_param_set phy;
union ieee_ss_param_set ss;
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
u8 mesh;
struct list_head list;
};
/** Association request
*
* Encapsulates all the options that describe a specific assocation request
* or configuration of the wireless card's radio, mode, and security settings.
*/
struct assoc_request {
#define ASSOC_FLAG_SSID 1
#define ASSOC_FLAG_CHANNEL 2
#define ASSOC_FLAG_BAND 3
#define ASSOC_FLAG_MODE 4
#define ASSOC_FLAG_BSSID 5
#define ASSOC_FLAG_WEP_KEYS 6
#define ASSOC_FLAG_WEP_TX_KEYIDX 7
#define ASSOC_FLAG_WPA_MCAST_KEY 8
#define ASSOC_FLAG_WPA_UCAST_KEY 9
#define ASSOC_FLAG_SECINFO 10
#define ASSOC_FLAG_WPA_IE 11
unsigned long flags;
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 ssid_len;
u8 channel;
u8 band;
u8 mode;
u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
/** WEP keys */
struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
struct lbs_802_11_security secinfo;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
/* BSS to associate with for infrastructure of Ad-Hoc join */
struct bss_descriptor bss;
};
extern u8 lbs_bg_rates[MAX_RATES];
void lbs_association_worker(struct work_struct *work); void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv); struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
@ -13,4 +132,24 @@ int lbs_adhoc_stop(struct lbs_private *priv);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
u8 bssid[ETH_ALEN], u16 reason); u8 bssid[ETH_ALEN], u16 reason);
int lbs_cmd_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *cmd);
int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
struct cmd_ds_command *cmd,
u16 cmd_action);
int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
struct cmd_ds_command *resp);
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc);
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable);
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc);
#endif /* _LBS_ASSOC_H */ #endif /* _LBS_ASSOC_H */

View File

@ -3,18 +3,20 @@
* It prepares command and sends it to firmware when it is ready. * It prepares command and sends it to firmware when it is ready.
*/ */
#include <net/iw_handler.h>
#include <net/lib80211.h> #include <net/lib80211.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/sched.h>
#include "host.h" #include "host.h"
#include "hostcmd.h"
#include "decl.h" #include "decl.h"
#include "defs.h" #include "defs.h"
#include "dev.h" #include "dev.h"
#include "assoc.h" #include "assoc.h"
#include "wext.h" #include "wext.h"
#include "scan.h"
#include "cmd.h" #include "cmd.h"
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
/** /**
@ -191,11 +193,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
goto out; goto out;
} }
if (lbs_set_universaltable(priv, 0)) {
ret = -1;
goto out;
}
out: out:
lbs_deb_leave(LBS_DEB_CMD); lbs_deb_leave(LBS_DEB_CMD);
return ret; return ret;
@ -244,7 +241,7 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_PS_MODE); cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
S_DS_GEN); sizeof(struct cmd_header));
psm->action = cpu_to_le16(cmd_action); psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0; psm->multipledtim = 0;
switch (cmd_action) { switch (cmd_action) {
@ -273,33 +270,6 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
return 0; return 0;
} }
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
uint16_t cmd_action, uint16_t *timeout)
{
struct cmd_ds_802_11_inactivity_timeout cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_SET)
cmd.timeout = cpu_to_le16(*timeout);
else
cmd.timeout = 0;
ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
if (!ret)
*timeout = le16_to_cpu(cmd.timeout);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return 0;
}
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp) struct sleep_params *sp)
{ {
@ -396,197 +366,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
return ret; return ret;
} }
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_ADD) {
int i;
/* default tx key index */
cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
CMD_WEP_KEY_INDEX_MASK);
/* Copy key types and material to host command structure */
for (i = 0; i < 4; i++) {
struct enc_key *pkey = &assoc->wep_keys[i];
switch (pkey->len) {
case KEY_LEN_WEP_40:
cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
memmove(cmd.keymaterial[i], pkey->key, pkey->len);
lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
break;
case KEY_LEN_WEP_104:
cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
memmove(cmd.keymaterial[i], pkey->key, pkey->len);
lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
break;
case 0:
break;
default:
lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
i, pkey->len);
ret = -1;
goto done;
break;
}
}
} else if (cmd_action == CMD_ACT_REMOVE) {
/* ACT_REMOVE clears _all_ WEP keys */
/* default tx key index */
cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
CMD_WEP_KEY_INDEX_MASK);
lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
}
ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
done:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable)
{
struct cmd_ds_802_11_enable_rsn cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_GET)
cmd.enable = 0;
else {
if (*enable)
cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
else
cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
if (!ret && cmd_action == CMD_ACT_GET)
*enable = le16_to_cpu(cmd.enable);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
struct enc_key *key)
{
lbs_deb_enter(LBS_DEB_CMD);
if (key->flags & KEY_INFO_WPA_ENABLED)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
if (key->flags & KEY_INFO_WPA_UNICAST)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
if (key->flags & KEY_INFO_WPA_MCAST)
keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
keyparam->keytypeid = cpu_to_le16(key->type);
keyparam->keylen = cpu_to_le16(key->len);
memcpy(keyparam->key, key->key, key->len);
/* Length field doesn't include the {type,length} header */
keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
lbs_deb_leave(LBS_DEB_CMD);
}
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
struct cmd_ds_802_11_key_material cmd;
int ret = 0;
int index = 0;
lbs_deb_enter(LBS_DEB_CMD);
cmd.action = cpu_to_le16(cmd_action);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (cmd_action == CMD_ACT_GET) {
cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
} else {
memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
set_one_wpa_key(&cmd.keyParamSet[index],
&assoc->wpa_unicast_key);
index++;
}
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
set_one_wpa_key(&cmd.keyParamSet[index],
&assoc->wpa_mcast_key);
index++;
}
/* The common header and as many keys as we included */
cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
keyParamSet[index]));
}
ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
/* Copy the returned key to driver private data */
if (!ret && cmd_action == CMD_ACT_GET) {
void *buf_ptr = cmd.keyParamSet;
void *resp_end = &(&cmd)[1];
while (buf_ptr < resp_end) {
struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
struct enc_key *key;
uint16_t param_set_len = le16_to_cpu(keyparam->length);
uint16_t key_len = le16_to_cpu(keyparam->keylen);
uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
void *end;
end = (void *)keyparam + sizeof(keyparam->type)
+ sizeof(keyparam->length) + param_set_len;
/* Make sure we don't access past the end of the IEs */
if (end > resp_end)
break;
if (key_flags & KEY_INFO_WPA_UNICAST)
key = &priv->wpa_unicast_key;
else if (key_flags & KEY_INFO_WPA_MCAST)
key = &priv->wpa_mcast_key;
else
break;
/* Copy returned key into driver */
memset(key, 0, sizeof(struct enc_key));
if (key_len > sizeof(key->key))
break;
key->type = key_type;
key->flags = key_flags;
key->len = key_len;
memcpy(key->key, keyparam->key, key->len);
buf_ptr = end + 1;
}
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
/** /**
* @brief Set an SNMP MIB value * @brief Set an SNMP MIB value
* *
@ -611,7 +390,7 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
switch (oid) { switch (oid) {
case SNMP_MIB_OID_BSS_TYPE: case SNMP_MIB_OID_BSS_TYPE:
cmd.bufsize = cpu_to_le16(sizeof(u8)); cmd.bufsize = cpu_to_le16(sizeof(u8));
cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1; cmd.value[0] = val;
break; break;
case SNMP_MIB_OID_11D_ENABLE: case SNMP_MIB_OID_11D_ENABLE:
case SNMP_MIB_OID_FRAG_THRESHOLD: case SNMP_MIB_OID_FRAG_THRESHOLD:
@ -664,13 +443,7 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
switch (le16_to_cpu(cmd.bufsize)) { switch (le16_to_cpu(cmd.bufsize)) {
case sizeof(u8): case sizeof(u8):
if (oid == SNMP_MIB_OID_BSS_TYPE) { *out_val = cmd.value[0];
if (cmd.value[0] == 2)
*out_val = IW_MODE_ADHOC;
else
*out_val = IW_MODE_INFRA;
} else
*out_val = cmd.value[0];
break; break;
case sizeof(u16): case sizeof(u16):
*out_val = le16_to_cpu(*((__le16 *)(&cmd.value))); *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
@ -757,7 +530,7 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE); cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
cmd->size = cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) + cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
S_DS_GEN); sizeof(struct cmd_header));
monitor->action = cpu_to_le16(cmd_action); monitor->action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_SET) { if (cmd_action == CMD_ACT_SET) {
@ -768,111 +541,6 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
return 0; return 0;
} }
static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
{
/* Bit Rate
* 15:13 Reserved
* 12 54 Mbps
* 11 48 Mbps
* 10 36 Mbps
* 9 24 Mbps
* 8 18 Mbps
* 7 12 Mbps
* 6 9 Mbps
* 5 6 Mbps
* 4 Reserved
* 3 11 Mbps
* 2 5.5 Mbps
* 1 2 Mbps
* 0 1 Mbps
**/
uint16_t ratemask;
int i = lbs_data_rate_to_fw_index(rate);
if (lower_rates_ok)
ratemask = (0x1fef >> (12 - i));
else
ratemask = (1 << i);
return cpu_to_le16(ratemask);
}
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action)
{
struct cmd_ds_802_11_rate_adapt_rateset cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD);
if (!priv->cur_rate && !priv->enablehwauto)
return -EINVAL;
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(cmd_action);
cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
if (!ret && cmd_action == CMD_ACT_GET) {
priv->ratebitmap = le16_to_cpu(cmd.bitmap);
priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
/**
* @brief Set the data rate
*
* @param priv A pointer to struct lbs_private structure
* @param rate The desired data rate, or 0 to clear a locked rate
*
* @return 0 on success, error on failure
*/
int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
{
struct cmd_ds_802_11_data_rate cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (rate > 0) {
cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
if (cmd.rates[0] == 0) {
lbs_deb_cmd("DATA_RATE: invalid requested rate of"
" 0x%02X\n", rate);
ret = 0;
goto out;
}
lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
} else {
cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
lbs_deb_cmd("DATA_RATE: setting auto\n");
}
ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
if (ret)
goto out;
lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
/* FIXME: get actual rates FW can do if this command actually returns
* all data rates supported.
*/
priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
/** /**
* @brief Get the radio channel * @brief Get the radio channel
* *
@ -880,7 +548,7 @@ out:
* *
* @return The channel on success, error on failure * @return The channel on success, error on failure
*/ */
int lbs_get_channel(struct lbs_private *priv) static int lbs_get_channel(struct lbs_private *priv)
{ {
struct cmd_ds_802_11_rf_channel cmd; struct cmd_ds_802_11_rf_channel cmd;
int ret = 0; int ret = 0;
@ -912,7 +580,7 @@ int lbs_update_channel(struct lbs_private *priv)
ret = lbs_get_channel(priv); ret = lbs_get_channel(priv);
if (ret > 0) { if (ret > 0) {
priv->curbssparams.channel = ret; priv->channel = ret;
ret = 0; ret = 0;
} }
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@ -931,7 +599,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
{ {
struct cmd_ds_802_11_rf_channel cmd; struct cmd_ds_802_11_rf_channel cmd;
#ifdef DEBUG #ifdef DEBUG
u8 old_channel = priv->curbssparams.channel; u8 old_channel = priv->channel;
#endif #endif
int ret = 0; int ret = 0;
@ -946,36 +614,15 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
if (ret) if (ret)
goto out; goto out;
priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel); priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
lbs_deb_cmd("channel switch from %d to %d\n", old_channel, lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
priv->curbssparams.channel); priv->channel);
out: out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret; return ret;
} }
static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *cmd)
{
lbs_deb_enter(LBS_DEB_CMD);
cmd->command = cpu_to_le16(CMD_802_11_RSSI);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
/* reset Beacon SNR/NF/RSSI values */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
u8 cmd_action, void *pdata_buf) u8 cmd_action, void *pdata_buf)
{ {
@ -992,7 +639,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size = cmdptr->size =
cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access) cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
+ S_DS_GEN); + sizeof(struct cmd_header));
macreg = macreg =
(struct cmd_ds_mac_reg_access *)&cmdptr->params. (struct cmd_ds_mac_reg_access *)&cmdptr->params.
macreg; macreg;
@ -1011,7 +658,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size = cmdptr->size =
cpu_to_le16(sizeof cpu_to_le16(sizeof
(struct cmd_ds_bbp_reg_access) (struct cmd_ds_bbp_reg_access)
+ S_DS_GEN); + sizeof(struct cmd_header));
bbpreg = bbpreg =
(struct cmd_ds_bbp_reg_access *)&cmdptr->params. (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
bbpreg; bbpreg;
@ -1030,7 +677,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size = cmdptr->size =
cpu_to_le16(sizeof cpu_to_le16(sizeof
(struct cmd_ds_rf_reg_access) + (struct cmd_ds_rf_reg_access) +
S_DS_GEN); sizeof(struct cmd_header));
rfreg = rfreg =
(struct cmd_ds_rf_reg_access *)&cmdptr->params. (struct cmd_ds_rf_reg_access *)&cmdptr->params.
rfreg; rfreg;
@ -1057,7 +704,8 @@ static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->command = cpu_to_le16(CMD_BT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
sizeof(struct cmd_header));
cmd->result = 0; cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action); bt_access->action = cpu_to_le16(cmd_action);
@ -1094,7 +742,8 @@ static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_FWT_ACCESS); cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
sizeof(struct cmd_header));
cmd->result = 0; cmd->result = 0;
if (pdata_buf) if (pdata_buf)
@ -1200,7 +849,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
ie->val.mesh_id_len = priv->mesh_ssid_len; ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->len = sizeof(struct mrvl_meshie_val) - ie->len = sizeof(struct mrvl_meshie_val) -
IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break; break;
case CMD_ACT_MESH_CONFIG_STOP: case CMD_ACT_MESH_CONFIG_STOP:
@ -1215,27 +864,6 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
} }
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
struct cmd_ds_command *cmd,
u16 cmd_action)
{
struct cmd_ds_802_11_beacon_control
*bcn_ctrl = &cmd->params.bcn_ctrl;
lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+ S_DS_GEN);
cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
bcn_ctrl->action = cpu_to_le16(cmd_action);
bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static void lbs_queue_cmd(struct lbs_private *priv, static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode) struct cmd_ctrl_node *cmdnode)
{ {
@ -1531,7 +1159,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
cmdptr->command = cpu_to_le16(cmd_no); cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
S_DS_GEN); sizeof(struct cmd_header));
memmove(&cmdptr->params.afc, memmove(&cmdptr->params.afc,
pdata_buf, sizeof(struct cmd_ds_802_11_afc)); pdata_buf, sizeof(struct cmd_ds_802_11_afc));
@ -1539,45 +1167,17 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0; ret = 0;
goto done; goto done;
case CMD_802_11D_DOMAIN_INFO:
ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
cmd_no, cmd_action);
break;
case CMD_802_11_TPC_CFG: case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size = cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
S_DS_GEN); sizeof(struct cmd_header));
memmove(&cmdptr->params.tpccfg, memmove(&cmdptr->params.tpccfg,
pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
ret = 0; ret = 0;
break; break;
case CMD_802_11_LED_GPIO_CTRL:
{
struct mrvl_ie_ledgpio *gpio =
(struct mrvl_ie_ledgpio*)
cmdptr->params.ledgpio.data;
memmove(&cmdptr->params.ledgpio,
pdata_buf,
sizeof(struct cmd_ds_802_11_led_ctrl));
cmdptr->command =
cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
cmdptr->size =
cpu_to_le16(le16_to_cpu(gpio->header.len)
+ S_DS_GEN
+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
gpio->header.len = gpio->header.len;
ret = 0;
break;
}
case CMD_BT_ACCESS: case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf); ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
@ -1587,18 +1187,12 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf); ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break; break;
case CMD_GET_TSF:
cmdptr->command = cpu_to_le16(CMD_GET_TSF);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
S_DS_GEN);
ret = 0;
break;
case CMD_802_11_BEACON_CTRL: case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break; break;
case CMD_802_11_DEEP_SLEEP: case CMD_802_11_DEEP_SLEEP:
cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP); cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
cmdptr->size = cpu_to_le16(S_DS_GEN); cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
break; break;
default: default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
@ -1917,30 +1511,6 @@ done:
return ret; return ret;
} }
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
{
union iwreq_data iwrq;
u8 buf[50];
lbs_deb_enter(LBS_DEB_WEXT);
memset(&iwrq, 0, sizeof(union iwreq_data));
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf) - 1, "%s", str);
iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
/* Send Event to upper layer */
lbs_deb_wext("event indication string %s\n", (char *)buf);
lbs_deb_wext("event indication length %d\n", iwrq.data.length);
lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
lbs_deb_leave(LBS_DEB_WEXT);
}
static void lbs_send_confirmsleep(struct lbs_private *priv) static void lbs_send_confirmsleep(struct lbs_private *priv)
{ {
unsigned long flags; unsigned long flags;
@ -2118,7 +1688,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
} }
static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg) unsigned long callback_arg)
@ -2216,5 +1786,3 @@ done:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(__lbs_cmd); EXPORT_SYMBOL_GPL(__lbs_cmd);

View File

@ -3,11 +3,30 @@
#ifndef _LBS_CMD_H_ #ifndef _LBS_CMD_H_
#define _LBS_CMD_H_ #define _LBS_CMD_H_
#include "hostcmd.h" #include "host.h"
#include "dev.h" #include "dev.h"
/* Command & response transfer between host and card */
struct cmd_ctrl_node {
struct list_head list;
int result;
/* command response */
int (*callback)(struct lbs_private *,
unsigned long,
struct cmd_header *);
unsigned long callback_arg;
/* command data */
struct cmd_header *cmdbuf;
/* wait queue */
u16 cmdwaitqwoken;
wait_queue_head_t cmdwait_q;
};
/* lbs_cmd() infers the size of the buffer to copy data back into, from /* lbs_cmd() infers the size of the buffer to copy data back into, from
the size of the target of the pointer. Since the command to be sent the size of the target of the pointer. Since the command to be sent
may often be smaller, that size is set in cmd->size by the caller.*/ may often be smaller, that size is set in cmd->size by the caller.*/
#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ #define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \
uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \
@ -18,6 +37,11 @@
#define lbs_cmd_with_response(priv, cmdnr, cmd) \ #define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd)) lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
int lbs_prepare_and_send_command(struct lbs_private *priv,
u16 cmd_no,
u16 cmd_action,
u16 wait_option, u32 cmd_oid, void *pdata_buf);
void lbs_cmd_async(struct lbs_private *priv, uint16_t command, void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size); struct cmd_header *in_cmd, int in_cmd_size);
@ -26,62 +50,93 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg); unsigned long callback_arg);
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
int8_t p1, int8_t p2); uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, unsigned long callback_arg);
int8_t p2, int usesnr);
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
int8_t p1, int8_t p2);
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
int8_t p2, int usesnr);
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp); struct cmd_header *resp);
int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_free_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result);
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
/* From cmdresp.c */
void lbs_mac_event_disconnected(struct lbs_private *priv);
/* Events */
int lbs_process_event(struct lbs_private *priv, u32 event);
/* Actual commands */
int lbs_update_hw_spec(struct lbs_private *priv); int lbs_update_hw_spec(struct lbs_private *priv);
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd);
int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel); int lbs_set_channel(struct lbs_private *priv, u8 channel);
int lbs_mesh_config_send(struct lbs_private *priv, int lbs_update_channel(struct lbs_private *priv);
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config); struct wol_config *p_wol_config);
int lbs_suspend(struct lbs_private *priv);
void lbs_resume(struct lbs_private *priv);
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action);
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp); struct sleep_params *sp);
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc); void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
uint16_t *enable); void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc); void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
void lbs_set_mac_control(struct lbs_private *priv);
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel); s16 *maxlevel);
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
/* Mesh related */
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd);
int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
/* Commands only used in wext.c, assoc. and scan.c */
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
int8_t p1, int8_t p2);
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
int8_t p2, int usesnr);
int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action);
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
#endif /* _LBS_CMD_H */ #endif /* _LBS_CMD_H */

View File

@ -11,6 +11,7 @@
#include "host.h" #include "host.h"
#include "decl.h" #include "decl.h"
#include "cmd.h"
#include "defs.h" #include "defs.h"
#include "dev.h" #include "dev.h"
#include "assoc.h" #include "assoc.h"
@ -26,23 +27,17 @@
*/ */
void lbs_mac_event_disconnected(struct lbs_private *priv) void lbs_mac_event_disconnected(struct lbs_private *priv)
{ {
union iwreq_data wrqu;
if (priv->connect_status != LBS_CONNECTED) if (priv->connect_status != LBS_CONNECTED)
return; return;
lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_enter(LBS_DEB_ASSOC);
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
/* /*
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms. * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
* It causes problem in the Supplicant * It causes problem in the Supplicant
*/ */
msleep_interruptible(1000); msleep_interruptible(1000);
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); lbs_send_disconnect_notification(priv);
/* report disconnect to upper layer */ /* report disconnect to upper layer */
netif_stop_queue(priv->dev); netif_stop_queue(priv->dev);
@ -67,7 +62,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
* no longer valid. * no longer valid.
*/ */
memset(&priv->curbssparams.bssid, 0, ETH_ALEN); memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = 0; priv->curbssparams.ssid_len = 0;
if (priv->psstate != PS_STATE_FULL_POWER) { if (priv->psstate != PS_STATE_FULL_POWER) {
@ -78,32 +73,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_ASSOC); lbs_deb_leave(LBS_DEB_ASSOC);
} }
/**
* @brief This function handles MIC failure event.
*
* @param priv A pointer to struct lbs_private structure
* @para event the event id
* @return n/a
*/
static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
{
char buf[50];
lbs_deb_enter(LBS_DEB_CMD);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
strcat(buf, "unicast ");
} else {
strcat(buf, "multicast ");
}
lbs_send_iwevcustom_event(priv, buf);
lbs_deb_leave(LBS_DEB_CMD);
}
static int lbs_ret_reg_access(struct lbs_private *priv, static int lbs_ret_reg_access(struct lbs_private *priv,
u16 type, struct cmd_ds_command *resp) u16 type, struct cmd_ds_command *resp)
{ {
@ -147,53 +116,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret; return ret;
} }
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
lbs_deb_enter(LBS_DEB_CMD);
/* store the non average value */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
priv->NF[TYPE_BEACON][TYPE_NOAVG]);
priv->RSSI[TYPE_BEACON][TYPE_AVG] =
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
priv->RSSI[TYPE_BEACON][TYPE_AVG]);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_beacon_control *bcn_ctrl =
&resp->params.bcn_ctrl;
lbs_deb_enter(LBS_DEB_CMD);
if (bcn_ctrl->action == CMD_ACT_GET) {
priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
}
lbs_deb_enter(LBS_DEB_CMD);
return 0;
}
static inline int handle_cmd_response(struct lbs_private *priv, static inline int handle_cmd_response(struct lbs_private *priv,
struct cmd_header *cmd_response) struct cmd_header *cmd_response)
{ {
@ -227,29 +149,13 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp); ret = lbs_ret_802_11_rssi(priv, resp);
break; break;
case CMD_RET(CMD_802_11D_DOMAIN_INFO):
ret = lbs_ret_802_11d_domain_info(resp);
break;
case CMD_RET(CMD_802_11_TPC_CFG): case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg)); sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
break; break;
case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
sizeof(struct cmd_ds_802_11_led_ctrl));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_GET_TSF):
spin_lock_irqsave(&priv->driver_lock, flags);
memcpy((void *)priv->cur_cmd->callback_arg,
&resp->params.gettsf.tsfvalue, sizeof(u64));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
case CMD_RET(CMD_BT_ACCESS): case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->callback_arg) if (priv->cur_cmd->callback_arg)
@ -545,12 +451,12 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_MIC_ERR_UNICAST: case MACREG_INT_CODE_MIC_ERR_UNICAST:
lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); lbs_send_mic_failureevent(priv, event);
break; break;
case MACREG_INT_CODE_MIC_ERR_MULTICAST: case MACREG_INT_CODE_MIC_ERR_MULTICAST:
lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); lbs_send_mic_failureevent(priv, event);
break; break;
case MACREG_INT_CODE_MIB_CHANGED: case MACREG_INT_CODE_MIB_CHANGED:

View File

@ -451,10 +451,12 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
CMD_MAC_REG_ACCESS, 0, CMD_MAC_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", if (!ret) {
pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
priv->mac_offset, priv->offsetvalue.value); priv->mac_offset, priv->offsetvalue.value);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr); free_page(addr);
return ret; return ret;
} }
@ -514,7 +516,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
res = count; if (!res)
res = count;
out_unlock: out_unlock:
free_page(addr); free_page(addr);
return res; return res;
@ -539,10 +542,12 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
CMD_BBP_REG_ACCESS, 0, CMD_BBP_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", if (!ret) {
pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
priv->bbp_offset, priv->offsetvalue.value); priv->bbp_offset, priv->offsetvalue.value);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr); free_page(addr);
return ret; return ret;
@ -603,7 +608,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
res = count; if (!res)
res = count;
out_unlock: out_unlock:
free_page(addr); free_page(addr);
return res; return res;
@ -628,10 +634,12 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
CMD_RF_REG_ACCESS, 0, CMD_RF_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", if (!ret) {
pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
priv->rf_offset, priv->offsetvalue.value); priv->rf_offset, priv->offsetvalue.value);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr); free_page(addr);
return ret; return ret;
@ -692,7 +700,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval); CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10); mdelay(10);
res = count; if (!res)
res = count;
out_unlock: out_unlock:
free_page(addr); free_page(addr);
return res; return res;

View File

@ -8,74 +8,48 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include "defs.h"
/** Function Prototype Declaration */
struct lbs_private; struct lbs_private;
struct sk_buff; struct sk_buff;
struct net_device; struct net_device;
struct cmd_ctrl_node;
struct cmd_ds_command;
void lbs_set_mac_control(struct lbs_private *priv);
/* ethtool.c */
extern const struct ethtool_ops lbs_ethtool_ops;
/* tx.c */
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count); void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
int lbs_free_cmd_buffer(struct lbs_private *priv);
int lbs_prepare_and_send_command(struct lbs_private *priv,
u16 cmd_no,
u16 cmd_action,
u16 wait_option, u32 cmd_oid, void *pdata_buf);
int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
/** The proc fs interface */
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result);
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
/* rx.c */
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
void lbs_ps_confirm_sleep(struct lbs_private *priv);
void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
struct lbs_private *priv,
u8 band,
u16 channel);
void lbs_mac_event_disconnected(struct lbs_private *priv);
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* persistcfg.c */ /* persistcfg.c */
void lbs_persist_config_init(struct net_device *net); void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net); void lbs_persist_config_remove(struct net_device *net);
/* main.c */ /* main.c */
struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
int *cfp_no);
struct lbs_private *lbs_add_card(void *card, struct device *dmdev); struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
void lbs_remove_card(struct lbs_private *priv); void lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv); int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv); void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv); int lbs_suspend(struct lbs_private *priv);
void lbs_resume(struct lbs_private *priv);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
#endif #endif

View File

@ -322,7 +322,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
extern const char lbs_driver_version[]; extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
extern u8 lbs_bg_rates[MAX_RATES];
/** ENUM definition*/ /** ENUM definition*/
/** SNRNF_TYPE */ /** SNRNF_TYPE */

View File

@ -6,75 +6,10 @@
#ifndef _LBS_DEV_H_ #ifndef _LBS_DEV_H_
#define _LBS_DEV_H_ #define _LBS_DEV_H_
#include <linux/netdevice.h> #include "scan.h"
#include <linux/wireless.h> #include "assoc.h"
#include <linux/ethtool.h>
#include <linux/debugfs.h>
#include "defs.h"
#include "hostcmd.h"
extern const struct ethtool_ops lbs_ethtool_ops;
#define MAX_BSSID_PER_CHANNEL 16
#define NR_TX_QUEUE 3
/* For the extended Scan */
#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
MRVDRV_MAX_CHANNEL_SIZE + 1
#define MAX_REGION_CHANNEL_NUM 2
/** Chan-freq-TxPower mapping table*/
struct chan_freq_power {
/** channel Number */
u16 channel;
/** frequency of this channel */
u32 freq;
/** Max allowed Tx power level */
u16 maxtxpower;
/** TRUE:channel unsupported; FLASE:supported*/
u8 unsupported;
};
/** region-band mapping table*/
struct region_channel {
/** TRUE if this entry is valid */
u8 valid;
/** region code for US, Japan ... */
u8 region;
/** band B/G/A, used for BAND_CONFIG cmd */
u8 band;
/** Actual No. of elements in the array below */
u8 nrcfp;
/** chan-freq-txpower mapping table*/
struct chan_freq_power *CFP;
};
struct lbs_802_11_security {
u8 WPAenabled;
u8 WPA2enabled;
u8 wep_enabled;
u8 auth_mode;
u32 key_mgmt;
};
/** Current Basic Service Set State Structure */
struct current_bss_params {
/** bssid */
u8 bssid[ETH_ALEN];
/** ssid */
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
/** band */
u8 band;
/** channel */
u8 channel;
/** zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
};
/** sleep_params */ /** sleep_params */
struct sleep_params { struct sleep_params {
@ -100,113 +35,96 @@ struct lbs_mesh_stats {
/** Private structure for the MV device */ /** Private structure for the MV device */
struct lbs_private { struct lbs_private {
/* Basic networking */
struct net_device *dev;
u32 connect_status;
int infra_open;
struct work_struct mcast_work;
u32 nr_of_multicastmacaddr;
u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
/* CFG80211 */
struct wireless_dev *wdev; struct wireless_dev *wdev;
/* Mesh */
struct net_device *mesh_dev; /* Virtual device */
u32 mesh_connect_status;
struct lbs_mesh_stats mstats;
int mesh_open; int mesh_open;
int mesh_fw_ver; int mesh_fw_ver;
int infra_open;
int mesh_autostart_enabled; int mesh_autostart_enabled;
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
struct work_struct sync_channel;
char name[DEV_NAME_LEN]; /* Monitor mode */
void *card;
struct net_device *dev;
struct net_device *mesh_dev; /* Virtual device */
struct net_device *rtap_net_dev; struct net_device *rtap_net_dev;
u32 monitormode;
struct iw_statistics wstats; /* Debugfs */
struct lbs_mesh_stats mstats;
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
struct dentry *debugfs_debug; struct dentry *debugfs_debug;
struct dentry *debugfs_files[6]; struct dentry *debugfs_files[6];
struct dentry *events_dir; struct dentry *events_dir;
struct dentry *debugfs_events_files[6]; struct dentry *debugfs_events_files[6];
struct dentry *regs_dir; struct dentry *regs_dir;
struct dentry *debugfs_regs_files[6]; struct dentry *debugfs_regs_files[6];
/* Hardware debugging */
u32 mac_offset; u32 mac_offset;
u32 bbp_offset; u32 bbp_offset;
u32 rf_offset; u32 rf_offset;
struct lbs_offset_value offsetvalue;
/** Deep sleep flag */ /* Power management */
u16 psmode;
u32 psstate;
u8 needtowakeup;
/* Deep sleep */
int is_deep_sleep; int is_deep_sleep;
/** Auto deep sleep enabled flag */
int is_auto_deep_sleep_enabled; int is_auto_deep_sleep_enabled;
/** Device wakeup required flag */
int wakeup_dev_required; int wakeup_dev_required;
/** Auto deep sleep flag*/
int is_activity_detected; int is_activity_detected;
/** Auto deep sleep timeout (in miliseconds) */ int auto_deep_sleep_timeout; /* in ms */
int auto_deep_sleep_timeout; wait_queue_head_t ds_awake_q;
struct timer_list auto_deepsleep_timer;
/** Deep sleep wait queue */ /* Hardware access */
wait_queue_head_t ds_awake_q; void *card;
u8 fw_ready;
/* Download sent: u8 surpriseremoved;
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
all other bits reserved 0 */
u8 dnld_sent;
/** thread to service interrupts */
struct task_struct *main_thread;
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
struct work_struct mcast_work;
/** Scanning */
struct delayed_work scan_work;
struct delayed_work assoc_work;
struct work_struct sync_channel;
/* remember which channel was scanned last, != 0 if currently scanning */
int scan_channel;
u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
u8 scan_ssid_len;
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv); void (*reset_card) (struct lbs_private *priv);
int (*enter_deep_sleep) (struct lbs_private *priv); int (*enter_deep_sleep) (struct lbs_private *priv);
int (*exit_deep_sleep) (struct lbs_private *priv); int (*exit_deep_sleep) (struct lbs_private *priv);
int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
/* Wake On LAN */ /* Adapter info (from EEPROM) */
uint32_t wol_criteria;
uint8_t wol_gpio;
uint8_t wol_gap;
/** Wlan adapter data structure*/
/** STATUS variables */
u32 fwrelease; u32 fwrelease;
u32 fwcapinfo; u32 fwcapinfo;
u16 regioncode;
u8 current_addr[ETH_ALEN];
struct mutex lock; /* Command download */
u8 dnld_sent;
/* TX packet ready to be sent... */ /* bit0 1/0=data_sent/data_tx_done,
int tx_pending_len; /* -1 while building packet */ bit1 1/0=cmd_sent/cmd_tx_done,
all other bits reserved 0 */
u8 tx_pending_buf[LBS_UPLD_SIZE];
/* protected by hard_start_xmit serialization */
/** command-related variables */
u16 seqnum; u16 seqnum;
struct cmd_ctrl_node *cmd_array; struct cmd_ctrl_node *cmd_array;
/** Current command */
struct cmd_ctrl_node *cur_cmd; struct cmd_ctrl_node *cur_cmd;
int cur_cmd_retcode; struct list_head cmdfreeq; /* free command buffers */
/** command Queues */ struct list_head cmdpendingq; /* pending command buffers */
/** Free command buffers */
struct list_head cmdfreeq;
/** Pending command buffers */
struct list_head cmdpendingq;
wait_queue_head_t cmd_pending; wait_queue_head_t cmd_pending;
struct timer_list command_timer;
int nr_retries;
int cmd_timed_out;
/* Command responses sent from the hardware to the driver */ /* Command responses sent from the hardware to the driver */
int cur_cmd_retcode;
u8 resp_idx; u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE]; u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2]; u32 resp_len[2];
@ -214,96 +132,76 @@ struct lbs_private {
/* Events sent from hardware to driver */ /* Events sent from hardware to driver */
struct kfifo *event_fifo; struct kfifo *event_fifo;
/* nickname */ /** thread to service interrupts */
u8 nodename[16]; struct task_struct *main_thread;
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
/** spin locks */ /** Encryption stuff */
spinlock_t driver_lock; struct lbs_802_11_security secinfo;
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
u16 wep_tx_keyidx;
struct enc_key wep_keys[4];
/** Timers */ /* Wake On LAN */
struct timer_list command_timer; uint32_t wol_criteria;
struct timer_list auto_deepsleep_timer; uint8_t wol_gpio;
int nr_retries; uint8_t wol_gap;
int cmd_timed_out;
/** current ssid/bssid related parameters*/
struct current_bss_params curbssparams;
uint16_t mesh_tlv;
u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
u8 mesh_ssid_len;
/* IW_MODE_* */
u8 mode;
/* Scan results list */
struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
u16 beacon_period;
u8 beacon_enable;
u8 adhoccreate;
/** capability Info used in Association, start, join */
u16 capability;
/** MAC address information */
u8 current_addr[ETH_ALEN];
u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
u32 nr_of_multicastmacaddr;
/** 802.11 statistics */
// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
uint16_t enablehwauto;
uint16_t ratebitmap;
/* Transmitting */
int tx_pending_len; /* -1 while building packet */
u8 tx_pending_buf[LBS_UPLD_SIZE];
/* protected by hard_start_xmit serialization */
u8 txretrycount; u8 txretrycount;
/** Tx-related variables (for single packet tx) */
struct sk_buff *currenttxskb; struct sk_buff *currenttxskb;
/** NIC Operation characteristics */ /* Locks */
struct mutex lock;
spinlock_t driver_lock;
/* NIC/link operation characteristics */
u16 mac_control; u16 mac_control;
u32 connect_status; u8 radio_on;
u32 mesh_connect_status; u8 channel;
u16 regioncode;
s16 txpower_cur; s16 txpower_cur;
s16 txpower_min; s16 txpower_min;
s16 txpower_max; s16 txpower_max;
/** POWER MANAGEMENT AND PnP SUPPORT */ /** Scanning */
u8 surpriseremoved; struct delayed_work scan_work;
int scan_channel;
u16 psmode; /* Wlan802_11PowermodeCAM=disable /* remember which channel was scanned last, != 0 if currently scanning */
Wlan802_11PowermodeMAX_PSP=enable */ u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
u32 psstate; u8 scan_ssid_len;
u8 needtowakeup;
/* Associating */
struct delayed_work assoc_work;
struct current_bss_params curbssparams;
u8 mode;
struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
struct assoc_request * pending_assoc_req; struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req; struct assoc_request * in_progress_assoc_req;
u16 capability;
uint16_t enablehwauto;
uint16_t ratebitmap;
/** Encryption parameter */ /* ADHOC */
struct lbs_802_11_security secinfo; u16 beacon_period;
u8 beacon_enable;
u8 adhoccreate;
/** WEP keys */ /* WEXT */
struct enc_key wep_keys[4]; char name[DEV_NAME_LEN];
u16 wep_tx_keyidx; u8 nodename[16];
struct iw_statistics wstats;
/** WPA keys */ u8 cur_rate;
struct enc_key wpa_mcast_key; #define MAX_REGION_CHANNEL_NUM 2
struct enc_key wpa_unicast_key; struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
/*
* In theory, the IE is limited to the IE length, 255,
* but in practice 64 bytes are enough.
*/
#define MAX_WPA_IE_LEN 64
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
/** Requested Signal Strength*/ /** Requested Signal Strength*/
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
@ -313,116 +211,8 @@ struct lbs_private {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF; u16 nextSNRNF;
u16 numSNRNF; u16 numSNRNF;
u8 radio_on;
/** data rate stuff */
u8 cur_rate;
/** RF calibration data */
#define MAX_REGION_CHANNEL_NUM 2
/** region channel data */
struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
/** 11D and Domain Regulatory Data */
struct lbs_802_11d_domain_reg domainreg;
struct parsed_region_chan_11d parsed_region_chan;
/** FSM variable for 11d support */
u32 enable11d;
/** MISCELLANEOUS */
struct lbs_offset_value offsetvalue;
u32 monitormode;
u8 fw_ready;
}; };
extern struct cmd_confirm_sleep confirm_sleep; extern struct cmd_confirm_sleep confirm_sleep;
/**
* @brief Structure used to store information for each beacon/probe response
*/
struct bss_descriptor {
u8 bssid[ETH_ALEN];
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
u16 capability;
u32 rssi;
u32 channel;
u16 beaconperiod;
__le16 atimwindow;
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
/* zero-terminated array of supported data rates */
u8 rates[MAX_RATES + 1];
unsigned long last_scanned;
union ieee_phy_param_set phy;
union ieee_ss_param_set ss;
struct ieee_ie_country_info_full_set countryinfo;
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
u8 mesh;
struct list_head list;
};
/** Association request
*
* Encapsulates all the options that describe a specific assocation request
* or configuration of the wireless card's radio, mode, and security settings.
*/
struct assoc_request {
#define ASSOC_FLAG_SSID 1
#define ASSOC_FLAG_CHANNEL 2
#define ASSOC_FLAG_BAND 3
#define ASSOC_FLAG_MODE 4
#define ASSOC_FLAG_BSSID 5
#define ASSOC_FLAG_WEP_KEYS 6
#define ASSOC_FLAG_WEP_TX_KEYIDX 7
#define ASSOC_FLAG_WPA_MCAST_KEY 8
#define ASSOC_FLAG_WPA_UCAST_KEY 9
#define ASSOC_FLAG_SECINFO 10
#define ASSOC_FLAG_WPA_IE 11
unsigned long flags;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
u8 channel;
u8 band;
u8 mode;
u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
/** WEP keys */
struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
struct lbs_802_11_security secinfo;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
/* BSS to associate with for infrastructure of Ad-Hoc join */
struct bss_descriptor bss;
};
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,800 +0,0 @@
/*
* This file contains the function prototypes, data structure
* and defines for all the host/station commands
*/
#ifndef _LBS_HOSTCMD_H
#define _LBS_HOSTCMD_H
#include <linux/wireless.h>
#include "11d.h"
#include "types.h"
/* 802.11-related definitions */
/* TxPD descriptor */
struct txpd {
/* union to cope up with later FW revisions */
union {
/* Current Tx packet status */
__le32 tx_status;
struct {
/* BSS type: client, AP, etc. */
u8 bss_type;
/* BSS number */
u8 bss_num;
/* Reserved */
__le16 reserved;
} bss;
} u;
/* Tx control */
__le32 tx_control;
__le32 tx_packet_location;
/* Tx packet length */
__le16 tx_packet_length;
/* First 2 byte of destination MAC address */
u8 tx_dest_addr_high[2];
/* Last 4 byte of destination MAC address */
u8 tx_dest_addr_low[4];
/* Pkt Priority */
u8 priority;
/* Pkt Trasnit Power control */
u8 powermgmt;
/* Amount of time the packet has been queued in the driver (units = 2ms) */
u8 pktdelay_2ms;
/* reserved */
u8 reserved1;
} __attribute__ ((packed));
/* RxPD Descriptor */
struct rxpd {
/* union to cope up with later FW revisions */
union {
/* Current Rx packet status */
__le16 status;
struct {
/* BSS type: client, AP, etc. */
u8 bss_type;
/* BSS number */
u8 bss_num;
} __attribute__ ((packed)) bss;
} __attribute__ ((packed)) u;
/* SNR */
u8 snr;
/* Tx control */
u8 rx_control;
/* Pkt length */
__le16 pkt_len;
/* Noise Floor */
u8 nf;
/* Rx Packet Rate */
u8 rx_rate;
/* Pkt addr */
__le32 pkt_ptr;
/* Next Rx RxPD addr */
__le32 next_rxpd_ptr;
/* Pkt Priority */
u8 priority;
u8 reserved[3];
} __attribute__ ((packed));
struct cmd_header {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
} __attribute__ ((packed));
struct cmd_ctrl_node {
struct list_head list;
int result;
/* command response */
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
unsigned long callback_arg;
/* command data */
struct cmd_header *cmdbuf;
/* wait queue */
u16 cmdwaitqwoken;
wait_queue_head_t cmdwait_q;
};
/* Generic structure to hold all key types. */
struct enc_key {
u16 len;
u16 flags; /* KEY_INFO_* from defs.h */
u16 type; /* KEY_TYPE_* from defs.h */
u8 key[32];
};
/* lbs_offset_value */
struct lbs_offset_value {
u32 offset;
u32 value;
} __attribute__ ((packed));
/* Define general data structure */
/* cmd_DS_GEN */
struct cmd_ds_gen {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
void *cmdresp[0];
} __attribute__ ((packed));
#define S_DS_GEN sizeof(struct cmd_ds_gen)
/*
* Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
*/
struct cmd_ds_get_hw_spec {
struct cmd_header hdr;
/* HW Interface version number */
__le16 hwifversion;
/* HW version number */
__le16 version;
/* Max number of TxPD FW can handle */
__le16 nr_txpd;
/* Max no of Multicast address */
__le16 nr_mcast_adr;
/* MAC address */
u8 permanentaddr[6];
/* region Code */
__le16 regioncode;
/* Number of antenna used */
__le16 nr_antenna;
/* FW release number, example 0x01030304 = 2.3.4p1 */
__le32 fwrelease;
/* Base Address of TxPD queue */
__le32 wcb_base;
/* Read Pointer of RxPd queue */
__le32 rxpd_rdptr;
/* Write Pointer of RxPd queue */
__le32 rxpd_wrptr;
/*FW/HW capability */
__le32 fwcapinfo;
} __attribute__ ((packed));
struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
__le16 action;
__le16 events;
/* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
* number of TLVs. From the v5.1 manual, those TLVs would add up to
* 40 bytes. However, future firmware might add additional TLVs, so I
* bump this up a bit.
*/
uint8_t tlv[128];
} __attribute__ ((packed));
/*
* This scan handle Country Information IE(802.11d compliant)
* Define data structure for CMD_802_11_SCAN
*/
struct cmd_ds_802_11_scan {
struct cmd_header hdr;
uint8_t bsstype;
uint8_t bssid[ETH_ALEN];
uint8_t tlvbuffer[0];
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
mrvlietypes_chanlistparamset_t ChanListParamSet;
mrvlietypes_ratesparamset_t OpRateSet;
#endif
} __attribute__ ((packed));
struct cmd_ds_802_11_scan_rsp {
struct cmd_header hdr;
__le16 bssdescriptsize;
uint8_t nr_sets;
uint8_t bssdesc_and_tlvbuffer[0];
} __attribute__ ((packed));
struct cmd_ds_802_11_get_log {
struct cmd_header hdr;
__le32 mcasttxframe;
__le32 failed;
__le32 retry;
__le32 multiretry;
__le32 framedup;
__le32 rtssuccess;
__le32 rtsfailure;
__le32 ackfailure;
__le32 rxfrag;
__le32 mcastrxframe;
__le32 fcserror;
__le32 txframe;
__le32 wepundecryptable;
} __attribute__ ((packed));
struct cmd_ds_mac_control {
struct cmd_header hdr;
__le16 action;
u16 reserved;
} __attribute__ ((packed));
struct cmd_ds_mac_multicast_adr {
struct cmd_header hdr;
__le16 action;
__le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
} __attribute__ ((packed));
struct cmd_ds_gspi_bus_config {
struct cmd_header hdr;
__le16 action;
__le16 bus_delay_mode;
__le16 host_time_delay_to_read_port;
__le16 host_time_delay_to_read_register;
} __attribute__ ((packed));
struct cmd_ds_802_11_authenticate {
struct cmd_header hdr;
u8 bssid[ETH_ALEN];
u8 authtype;
u8 reserved[10];
} __attribute__ ((packed));
struct cmd_ds_802_11_deauthenticate {
struct cmd_header hdr;
u8 macaddr[ETH_ALEN];
__le16 reasoncode;
} __attribute__ ((packed));
struct cmd_ds_802_11_associate {
struct cmd_header hdr;
u8 bssid[6];
__le16 capability;
__le16 listeninterval;
__le16 bcnperiod;
u8 dtimperiod;
u8 iebuf[512]; /* Enough for required and most optional IEs */
} __attribute__ ((packed));
struct cmd_ds_802_11_associate_response {
struct cmd_header hdr;
__le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuf[512];
} __attribute__ ((packed));
struct cmd_ds_802_11_set_wep {
struct cmd_header hdr;
/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
__le16 action;
/* key Index selected for Tx */
__le16 keyindex;
/* 40, 128bit or TXWEP */
uint8_t keytype[4];
uint8_t keymaterial[4][16];
} __attribute__ ((packed));
struct cmd_ds_802_3_get_stat {
__le32 xmitok;
__le32 rcvok;
__le32 xmiterror;
__le32 rcverror;
__le32 rcvnobuffer;
__le32 rcvcrcerror;
} __attribute__ ((packed));
struct cmd_ds_802_11_get_stat {
__le32 txfragmentcnt;
__le32 mcasttxframecnt;
__le32 failedcnt;
__le32 retrycnt;
__le32 Multipleretrycnt;
__le32 rtssuccesscnt;
__le32 rtsfailurecnt;
__le32 ackfailurecnt;
__le32 frameduplicatecnt;
__le32 rxfragmentcnt;
__le32 mcastrxframecnt;
__le32 fcserrorcnt;
__le32 bcasttxframecnt;
__le32 bcastrxframecnt;
__le32 txbeacon;
__le32 rxbeacon;
__le32 wepundecryptable;
} __attribute__ ((packed));
struct cmd_ds_802_11_snmp_mib {
struct cmd_header hdr;
__le16 action;
__le16 oid;
__le16 bufsize;
u8 value[128];
} __attribute__ ((packed));
struct cmd_ds_mac_reg_map {
__le16 buffersize;
u8 regmap[128];
__le16 reserved;
} __attribute__ ((packed));
struct cmd_ds_bbp_reg_map {
__le16 buffersize;
u8 regmap[128];
__le16 reserved;
} __attribute__ ((packed));
struct cmd_ds_rf_reg_map {
__le16 buffersize;
u8 regmap[64];
__le16 reserved;
} __attribute__ ((packed));
struct cmd_ds_mac_reg_access {
__le16 action;
__le16 offset;
__le32 value;
} __attribute__ ((packed));
struct cmd_ds_bbp_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
} __attribute__ ((packed));
struct cmd_ds_rf_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
} __attribute__ ((packed));
struct cmd_ds_802_11_radio_control {
struct cmd_header hdr;
__le16 action;
__le16 control;
} __attribute__ ((packed));
struct cmd_ds_802_11_beacon_control {
__le16 action;
__le16 beacon_enable;
__le16 beacon_period;
} __attribute__ ((packed));
struct cmd_ds_802_11_sleep_params {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */
__le16 action;
/* Sleep clock error in ppm */
__le16 error;
/* Wakeup offset in usec */
__le16 offset;
/* Clock stabilization time in usec */
__le16 stabletime;
/* control periodic calibration */
uint8_t calcontrol;
/* control the use of external sleep clock */
uint8_t externalsleepclk;
/* reserved field, should be set to zero */
__le16 reserved;
} __attribute__ ((packed));
struct cmd_ds_802_11_inactivity_timeout {
struct cmd_header hdr;
/* ACT_GET/ACT_SET */
__le16 action;
/* Inactivity timeout in msec */
__le16 timeout;
} __attribute__ ((packed));
struct cmd_ds_802_11_rf_channel {
struct cmd_header hdr;
__le16 action;
__le16 channel;
__le16 rftype; /* unused */
__le16 reserved; /* unused */
u8 channellist[32]; /* unused */
} __attribute__ ((packed));
struct cmd_ds_802_11_rssi {
/* weighting factor */
__le16 N;
__le16 reserved_0;
__le16 reserved_1;
__le16 reserved_2;
} __attribute__ ((packed));
struct cmd_ds_802_11_rssi_rsp {
__le16 SNR;
__le16 noisefloor;
__le16 avgSNR;
__le16 avgnoisefloor;
} __attribute__ ((packed));
struct cmd_ds_802_11_mac_address {
struct cmd_header hdr;
__le16 action;
u8 macadd[ETH_ALEN];
} __attribute__ ((packed));
struct cmd_ds_802_11_rf_tx_power {
struct cmd_header hdr;
__le16 action;
__le16 curlevel;
s8 maxlevel;
s8 minlevel;
} __attribute__ ((packed));
struct cmd_ds_802_11_rf_antenna {
__le16 action;
/* Number of antennas or 0xffff(diversity) */
__le16 antennamode;
} __attribute__ ((packed));
struct cmd_ds_802_11_monitor_mode {
__le16 action;
__le16 mode;
} __attribute__ ((packed));
struct cmd_ds_set_boot2_ver {
struct cmd_header hdr;
__le16 action;
__le16 version;
} __attribute__ ((packed));
struct cmd_ds_802_11_fw_wake_method {
struct cmd_header hdr;
__le16 action;
__le16 method;
} __attribute__ ((packed));
struct cmd_ds_802_11_sleep_period {
struct cmd_header hdr;
__le16 action;
__le16 period;
} __attribute__ ((packed));
struct cmd_ds_802_11_ps_mode {
__le16 action;
__le16 nullpktinterval;
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
} __attribute__ ((packed));
struct cmd_confirm_sleep {
struct cmd_header hdr;
__le16 action;
__le16 nullpktinterval;
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
} __attribute__ ((packed));
struct cmd_ds_802_11_data_rate {
struct cmd_header hdr;
__le16 action;
__le16 reserved;
u8 rates[MAX_RATES];
} __attribute__ ((packed));
struct cmd_ds_802_11_rate_adapt_rateset {
struct cmd_header hdr;
__le16 action;
__le16 enablehwauto;
__le16 bitmap;
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_start {
struct cmd_header hdr;
u8 ssid[IW_ESSID_MAX_SIZE];
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod; /* Reserved on v9 and later */
struct ieee_ie_ibss_param_set ibss;
u8 reserved1[4];
struct ieee_ie_ds_param_set ds;
u8 reserved2[4];
__le16 probedelay; /* Reserved on v9 and later */
__le16 capability;
u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_result {
struct cmd_header hdr;
u8 pad[3];
u8 bssid[ETH_ALEN];
} __attribute__ ((packed));
struct adhoc_bssdesc {
u8 bssid[ETH_ALEN];
u8 ssid[IW_ESSID_MAX_SIZE];
u8 type;
__le16 beaconperiod;
u8 dtimperiod;
__le64 timestamp;
__le64 localtime;
struct ieee_ie_ds_param_set ds;
u8 reserved1[4];
struct ieee_ie_ibss_param_set ibss;
u8 reserved2[4];
__le16 capability;
u8 rates[MAX_RATES];
/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_join {
struct cmd_header hdr;
struct adhoc_bssdesc bss;
__le16 failtimeout; /* Reserved on v9 and later */
__le16 probedelay; /* Reserved on v9 and later */
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_stop {
struct cmd_header hdr;
} __attribute__ ((packed));
struct cmd_ds_802_11_enable_rsn {
struct cmd_header hdr;
__le16 action;
__le16 enable;
} __attribute__ ((packed));
struct MrvlIEtype_keyParamSet {
/* type ID */
__le16 type;
/* length of Payload */
__le16 length;
/* type of key: WEP=0, TKIP=1, AES=2 */
__le16 keytypeid;
/* key control Info specific to a keytypeid */
__le16 keyinfo;
/* length of key */
__le16 keylen;
/* key material of size keylen */
u8 key[32];
} __attribute__ ((packed));
#define MAX_WOL_RULES 16
struct host_wol_rule {
uint8_t rule_no;
uint8_t rule_ops;
__le16 sig_offset;
__le16 sig_length;
__le16 reserve;
__be32 sig_mask;
__be32 signature;
} __attribute__ ((packed));
struct wol_config {
uint8_t action;
uint8_t pattern;
uint8_t no_rules_in_cmd;
uint8_t result;
struct host_wol_rule rule[MAX_WOL_RULES];
} __attribute__ ((packed));
struct cmd_ds_host_sleep {
struct cmd_header hdr;
__le32 criteria;
uint8_t gpio;
uint16_t gap;
struct wol_config wol_conf;
} __attribute__ ((packed));
struct cmd_ds_802_11_key_material {
struct cmd_header hdr;
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
} __attribute__ ((packed));
struct cmd_ds_802_11_eeprom_access {
struct cmd_header hdr;
__le16 action;
__le16 offset;
__le16 len;
/* firmware says it returns a maximum of 20 bytes */
#define LBS_EEPROM_READ_LEN 20
u8 value[LBS_EEPROM_READ_LEN];
} __attribute__ ((packed));
struct cmd_ds_802_11_tpc_cfg {
struct cmd_header hdr;
__le16 action;
uint8_t enable;
int8_t P0;
int8_t P1;
int8_t P2;
uint8_t usesnr;
} __attribute__ ((packed));
struct cmd_ds_802_11_pa_cfg {
struct cmd_header hdr;
__le16 action;
uint8_t enable;
int8_t P0;
int8_t P1;
int8_t P2;
} __attribute__ ((packed));
struct cmd_ds_802_11_led_ctrl {
__le16 action;
__le16 numled;
u8 data[256];
} __attribute__ ((packed));
struct cmd_ds_802_11_afc {
__le16 afc_auto;
union {
struct {
__le16 threshold;
__le16 period;
};
struct {
__le16 timing_offset; /* signed */
__le16 carrier_offset; /* signed */
};
};
} __attribute__ ((packed));
struct cmd_tx_rate_query {
__le16 txrate;
} __attribute__ ((packed));
struct cmd_ds_get_tsf {
__le64 tsfvalue;
} __attribute__ ((packed));
struct cmd_ds_bt_access {
__le16 action;
__le32 id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
} __attribute__ ((packed));
struct cmd_ds_fwt_access {
__le16 action;
__le32 id;
u8 valid;
u8 da[ETH_ALEN];
u8 dir;
u8 ra[ETH_ALEN];
__le32 ssn;
__le32 dsn;
__le32 metric;
u8 rate;
u8 hopcount;
u8 ttl;
__le32 expiration;
u8 sleepmode;
__le32 snr;
__le32 references;
u8 prec[ETH_ALEN];
} __attribute__ ((packed));
struct cmd_ds_mesh_config {
struct cmd_header hdr;
__le16 action;
__le16 channel;
__le16 type;
__le16 length;
u8 data[128]; /* last position reserved */
} __attribute__ ((packed));
struct cmd_ds_mesh_access {
struct cmd_header hdr;
__le16 action;
__le32 data[32]; /* last position reserved */
} __attribute__ ((packed));
/* Number of stats counters returned by the firmware */
#define MESH_STATS_NUM 8
struct cmd_ds_command {
/* command header */
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
/* command Body */
union {
struct cmd_ds_802_11_ps_mode psmode;
struct cmd_ds_802_11_get_stat gstat;
struct cmd_ds_802_3_get_stat gstat_8023;
struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp;
struct cmd_ds_mac_reg_access macreg;
struct cmd_ds_bbp_reg_access bbpreg;
struct cmd_ds_rf_reg_access rfreg;
struct cmd_ds_802_11d_domain_info domaininfo;
struct cmd_ds_802_11d_domain_info domaininforesp;
struct cmd_ds_802_11_tpc_cfg tpccfg;
struct cmd_ds_802_11_afc afc;
struct cmd_ds_802_11_led_ctrl ledgpio;
struct cmd_tx_rate_query txrate;
struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt;
struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params;
} __attribute__ ((packed));
#endif

View File

@ -45,132 +45,12 @@ module_param_named(libertas_debug, lbs_debug, int, 0644);
struct cmd_confirm_sleep confirm_sleep; struct cmd_confirm_sleep confirm_sleep;
#define LBS_TX_PWR_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
/* Format { channel, frequency (MHz), maxtxpower } */
/* band: 'B/G', region: USA FCC/Canada IC */
static struct chan_freq_power channel_freq_power_US_BG[] = {
{1, 2412, LBS_TX_PWR_US_DEFAULT},
{2, 2417, LBS_TX_PWR_US_DEFAULT},
{3, 2422, LBS_TX_PWR_US_DEFAULT},
{4, 2427, LBS_TX_PWR_US_DEFAULT},
{5, 2432, LBS_TX_PWR_US_DEFAULT},
{6, 2437, LBS_TX_PWR_US_DEFAULT},
{7, 2442, LBS_TX_PWR_US_DEFAULT},
{8, 2447, LBS_TX_PWR_US_DEFAULT},
{9, 2452, LBS_TX_PWR_US_DEFAULT},
{10, 2457, LBS_TX_PWR_US_DEFAULT},
{11, 2462, LBS_TX_PWR_US_DEFAULT}
};
/* band: 'B/G', region: Europe ETSI */
static struct chan_freq_power channel_freq_power_EU_BG[] = {
{1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
{2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
{3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
{4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
{5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
{6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
{7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
{8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
{9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
{10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
{11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
{12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
{13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
};
/* band: 'B/G', region: Spain */
static struct chan_freq_power channel_freq_power_SPN_BG[] = {
{10, 2457, LBS_TX_PWR_DEFAULT},
{11, 2462, LBS_TX_PWR_DEFAULT}
};
/* band: 'B/G', region: France */
static struct chan_freq_power channel_freq_power_FR_BG[] = {
{10, 2457, LBS_TX_PWR_FR_DEFAULT},
{11, 2462, LBS_TX_PWR_FR_DEFAULT},
{12, 2467, LBS_TX_PWR_FR_DEFAULT},
{13, 2472, LBS_TX_PWR_FR_DEFAULT}
};
/* band: 'B/G', region: Japan */
static struct chan_freq_power channel_freq_power_JPN_BG[] = {
{1, 2412, LBS_TX_PWR_JP_DEFAULT},
{2, 2417, LBS_TX_PWR_JP_DEFAULT},
{3, 2422, LBS_TX_PWR_JP_DEFAULT},
{4, 2427, LBS_TX_PWR_JP_DEFAULT},
{5, 2432, LBS_TX_PWR_JP_DEFAULT},
{6, 2437, LBS_TX_PWR_JP_DEFAULT},
{7, 2442, LBS_TX_PWR_JP_DEFAULT},
{8, 2447, LBS_TX_PWR_JP_DEFAULT},
{9, 2452, LBS_TX_PWR_JP_DEFAULT},
{10, 2457, LBS_TX_PWR_JP_DEFAULT},
{11, 2462, LBS_TX_PWR_JP_DEFAULT},
{12, 2467, LBS_TX_PWR_JP_DEFAULT},
{13, 2472, LBS_TX_PWR_JP_DEFAULT},
{14, 2484, LBS_TX_PWR_JP_DEFAULT}
};
/**
* the structure for channel, frequency and power
*/
struct region_cfp_table {
u8 region;
struct chan_freq_power *cfp_BG;
int cfp_no_BG;
};
/**
* the structure for the mapping between region and CFP
*/
static struct region_cfp_table region_cfp_table[] = {
{0x10, /*US FCC */
channel_freq_power_US_BG,
ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x20, /*CANADA IC */
channel_freq_power_US_BG,
ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x30, /*EU*/ channel_freq_power_EU_BG,
ARRAY_SIZE(channel_freq_power_EU_BG),
}
,
{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
ARRAY_SIZE(channel_freq_power_SPN_BG),
}
,
{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
ARRAY_SIZE(channel_freq_power_FR_BG),
}
,
{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
ARRAY_SIZE(channel_freq_power_JPN_BG),
}
,
/*Add new region here */
};
/** /**
* the table to keep region code * the table to keep region code
*/ */
u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
* 802.11b/g supported bitrates (in 500Kb/s units)
*/
u8 lbs_bg_rates[MAX_RATES] =
{ 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
0x00, 0x00 };
/** /**
* FW rate table. FW refers to rates by their index in this table, not by the * FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are * rate value itself. Values of 0x00 are
@ -405,7 +285,7 @@ static ssize_t lbs_mesh_set(struct device *dev,
return count; return count;
if (enable) if (enable)
action = CMD_ACT_MESH_CONFIG_START; action = CMD_ACT_MESH_CONFIG_START;
ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); ret = lbs_mesh_config(priv, action, priv->channel);
if (ret) if (ret)
return ret; return ret;
@ -1089,6 +969,8 @@ static void auto_deepsleep_timer_fn(unsigned long data)
ret = lbs_prepare_and_send_command(priv, ret = lbs_prepare_and_send_command(priv,
CMD_802_11_DEEP_SLEEP, 0, CMD_802_11_DEEP_SLEEP, 0,
0, 0, NULL); 0, 0, NULL);
if (ret)
lbs_pr_err("Enter Deep Sleep command failed\n");
} }
} }
mod_timer(&priv->auto_deepsleep_timer , jiffies + mod_timer(&priv->auto_deepsleep_timer , jiffies +
@ -1164,7 +1046,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mesh_connect_status = LBS_DISCONNECTED; priv->mesh_connect_status = LBS_DISCONNECTED;
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
priv->mode = IW_MODE_INFRA; priv->mode = IW_MODE_INFRA;
priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1; priv->radio_on = 1;
priv->enablehwauto = 1; priv->enablehwauto = 1;
@ -1345,7 +1227,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card);
void lbs_remove_card(struct lbs_private *priv) void lbs_remove_card(struct lbs_private *priv)
{ {
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN); lbs_deb_enter(LBS_DEB_MAIN);
@ -1370,9 +1251,7 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
} }
memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); lbs_send_disconnect_notification(priv);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
if (priv->is_deep_sleep) { if (priv->is_deep_sleep) {
priv->is_deep_sleep = 0; priv->is_deep_sleep = 0;
@ -1406,9 +1285,6 @@ int lbs_start_card(struct lbs_private *priv)
if (ret) if (ret)
goto done; goto done;
/* init 802.11d */
lbs_init_11d(priv);
if (lbs_cfg_register(priv)) { if (lbs_cfg_register(priv)) {
lbs_pr_err("cannot register device\n"); lbs_pr_err("cannot register device\n");
goto done; goto done;
@ -1435,10 +1311,10 @@ int lbs_start_card(struct lbs_private *priv)
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) { priv->channel)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID; priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) priv->channel))
priv->mesh_tlv = 0; priv->mesh_tlv = 0;
} }
} else if (priv->mesh_fw_ver == MESH_FW_NEW) { } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
@ -1447,7 +1323,7 @@ int lbs_start_card(struct lbs_private *priv)
*/ */
priv->mesh_tlv = TLV_TYPE_MESH_ID; priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) priv->channel))
priv->mesh_tlv = 0; priv->mesh_tlv = 0;
} }
if (priv->mesh_tlv) { if (priv->mesh_tlv) {
@ -1618,68 +1494,6 @@ static void lbs_remove_mesh(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_MESH); lbs_deb_leave(LBS_DEB_MESH);
} }
/**
* @brief This function finds the CFP in
* region_cfp_table based on region and band parameter.
*
* @param region The region code
* @param band The band
* @param cfp_no A pointer to CFP number
* @return A pointer to CFP
*/
struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
{
int i, end;
lbs_deb_enter(LBS_DEB_MAIN);
end = ARRAY_SIZE(region_cfp_table);
for (i = 0; i < end ; i++) {
lbs_deb_main("region_cfp_table[i].region=%d\n",
region_cfp_table[i].region);
if (region_cfp_table[i].region == region) {
*cfp_no = region_cfp_table[i].cfp_no_BG;
lbs_deb_leave(LBS_DEB_MAIN);
return region_cfp_table[i].cfp_BG;
}
}
lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
return NULL;
}
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
{
int ret = 0;
int i = 0;
struct chan_freq_power *cfp;
int cfp_no;
lbs_deb_enter(LBS_DEB_MAIN);
memset(priv->region_channel, 0, sizeof(priv->region_channel));
cfp = lbs_get_region_cfp_table(region, &cfp_no);
if (cfp != NULL) {
priv->region_channel[i].nrcfp = cfp_no;
priv->region_channel[i].CFP = cfp;
} else {
lbs_deb_main("wrong region code %#x in band B/G\n",
region);
ret = -1;
goto out;
}
priv->region_channel[i].valid = 1;
priv->region_channel[i].region = region;
priv->region_channel[i].band = band;
i++;
out:
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
return ret;
}
void lbs_queue_event(struct lbs_private *priv, u32 event) void lbs_queue_event(struct lbs_private *priv, u32 event)
{ {
unsigned long flags; unsigned long flags;

View File

@ -187,9 +187,9 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
if (ret) if (ret)
return ret; return ret;
if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
lbs_pr_err("inconsistent mesh ID length"); lbs_pr_err("inconsistent mesh ID length");
defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
} }
/* SSID not null terminated: reserve room for \0 + \n */ /* SSID not null terminated: reserve room for \0 + \n */
@ -214,7 +214,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
int len; int len;
int ret; int ret;
if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
return -EINVAL; return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
/* SSID len */ /* SSID len */
ie->val.mesh_id_len = len; ie->val.mesh_id_len = len;
/* IE len */ /* IE len */
ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE); CMD_TYPE_MESH_SET_MESH_IE);

View File

@ -4,7 +4,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/types.h> #include <linux/types.h>
#include "hostcmd.h" #include "host.h"
#include "radiotap.h" #include "radiotap.h"
#include "decl.h" #include "decl.h"
#include "dev.h" #include "dev.h"

View File

@ -12,18 +12,19 @@
#include <net/lib80211.h> #include <net/lib80211.h>
#include "host.h" #include "host.h"
#include "decl.h"
#include "dev.h" #include "dev.h"
#include "scan.h" #include "scan.h"
#include "assoc.h"
#include "wext.h"
#include "cmd.h" #include "cmd.h"
//! Approximate amount of data needed to pass a scan result back to iwlist //! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ IW_ESSID_MAX_SIZE \ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_UINT_LEN \ + IW_EV_UINT_LEN \
+ IW_EV_FREQ_LEN \ + IW_EV_FREQ_LEN \
+ IW_EV_QUAL_LEN \ + IW_EV_QUAL_LEN \
+ IW_ESSID_MAX_SIZE \ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_PARAM_LEN \ + IW_EV_PARAM_LEN \
+ 40) /* 40 for WPAIE */ + 40) /* 40 for WPAIE */
@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src,
/*********************************************************************/
/* */
/* Region channel support */
/* */
/*********************************************************************/
#define LBS_TX_PWR_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
/* Format { channel, frequency (MHz), maxtxpower } */
/* band: 'B/G', region: USA FCC/Canada IC */
static struct chan_freq_power channel_freq_power_US_BG[] = {
{1, 2412, LBS_TX_PWR_US_DEFAULT},
{2, 2417, LBS_TX_PWR_US_DEFAULT},
{3, 2422, LBS_TX_PWR_US_DEFAULT},
{4, 2427, LBS_TX_PWR_US_DEFAULT},
{5, 2432, LBS_TX_PWR_US_DEFAULT},
{6, 2437, LBS_TX_PWR_US_DEFAULT},
{7, 2442, LBS_TX_PWR_US_DEFAULT},
{8, 2447, LBS_TX_PWR_US_DEFAULT},
{9, 2452, LBS_TX_PWR_US_DEFAULT},
{10, 2457, LBS_TX_PWR_US_DEFAULT},
{11, 2462, LBS_TX_PWR_US_DEFAULT}
};
/* band: 'B/G', region: Europe ETSI */
static struct chan_freq_power channel_freq_power_EU_BG[] = {
{1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
{2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
{3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
{4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
{5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
{6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
{7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
{8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
{9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
{10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
{11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
{12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
{13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
};
/* band: 'B/G', region: Spain */
static struct chan_freq_power channel_freq_power_SPN_BG[] = {
{10, 2457, LBS_TX_PWR_DEFAULT},
{11, 2462, LBS_TX_PWR_DEFAULT}
};
/* band: 'B/G', region: France */
static struct chan_freq_power channel_freq_power_FR_BG[] = {
{10, 2457, LBS_TX_PWR_FR_DEFAULT},
{11, 2462, LBS_TX_PWR_FR_DEFAULT},
{12, 2467, LBS_TX_PWR_FR_DEFAULT},
{13, 2472, LBS_TX_PWR_FR_DEFAULT}
};
/* band: 'B/G', region: Japan */
static struct chan_freq_power channel_freq_power_JPN_BG[] = {
{1, 2412, LBS_TX_PWR_JP_DEFAULT},
{2, 2417, LBS_TX_PWR_JP_DEFAULT},
{3, 2422, LBS_TX_PWR_JP_DEFAULT},
{4, 2427, LBS_TX_PWR_JP_DEFAULT},
{5, 2432, LBS_TX_PWR_JP_DEFAULT},
{6, 2437, LBS_TX_PWR_JP_DEFAULT},
{7, 2442, LBS_TX_PWR_JP_DEFAULT},
{8, 2447, LBS_TX_PWR_JP_DEFAULT},
{9, 2452, LBS_TX_PWR_JP_DEFAULT},
{10, 2457, LBS_TX_PWR_JP_DEFAULT},
{11, 2462, LBS_TX_PWR_JP_DEFAULT},
{12, 2467, LBS_TX_PWR_JP_DEFAULT},
{13, 2472, LBS_TX_PWR_JP_DEFAULT},
{14, 2484, LBS_TX_PWR_JP_DEFAULT}
};
/**
* the structure for channel, frequency and power
*/
struct region_cfp_table {
u8 region;
struct chan_freq_power *cfp_BG;
int cfp_no_BG;
};
/**
* the structure for the mapping between region and CFP
*/
static struct region_cfp_table region_cfp_table[] = {
{0x10, /*US FCC */
channel_freq_power_US_BG,
ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x20, /*CANADA IC */
channel_freq_power_US_BG,
ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x30, /*EU*/ channel_freq_power_EU_BG,
ARRAY_SIZE(channel_freq_power_EU_BG),
}
,
{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
ARRAY_SIZE(channel_freq_power_SPN_BG),
}
,
{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
ARRAY_SIZE(channel_freq_power_FR_BG),
}
,
{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
ARRAY_SIZE(channel_freq_power_JPN_BG),
}
,
/*Add new region here */
};
/**
* @brief This function finds the CFP in
* region_cfp_table based on region and band parameter.
*
* @param region The region code
* @param band The band
* @param cfp_no A pointer to CFP number
* @return A pointer to CFP
*/
static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
{
int i, end;
lbs_deb_enter(LBS_DEB_MAIN);
end = ARRAY_SIZE(region_cfp_table);
for (i = 0; i < end ; i++) {
lbs_deb_main("region_cfp_table[i].region=%d\n",
region_cfp_table[i].region);
if (region_cfp_table[i].region == region) {
*cfp_no = region_cfp_table[i].cfp_no_BG;
lbs_deb_leave(LBS_DEB_MAIN);
return region_cfp_table[i].cfp_BG;
}
}
lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
return NULL;
}
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
{
int ret = 0;
int i = 0;
struct chan_freq_power *cfp;
int cfp_no;
lbs_deb_enter(LBS_DEB_MAIN);
memset(priv->region_channel, 0, sizeof(priv->region_channel));
cfp = lbs_get_region_cfp_table(region, &cfp_no);
if (cfp != NULL) {
priv->region_channel[i].nrcfp = cfp_no;
priv->region_channel[i].CFP = cfp;
} else {
lbs_deb_main("wrong region code %#x in band B/G\n",
region);
ret = -1;
goto out;
}
priv->region_channel[i].valid = 1;
priv->region_channel[i].region = region;
priv->region_channel[i].band = band;
i++;
out:
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
return ret;
}
/*********************************************************************/ /*********************************************************************/
/* */ /* */
@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
scantype = CMD_SCAN_TYPE_ACTIVE; scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) if (!priv->region_channel[rgnidx].valid)
&& (priv->mesh_connect_status != LBS_CONNECTED)) { continue;
/* Scan all the supported chan for the first scan */ scanregion = &priv->region_channel[rgnidx];
if (!priv->universal_channel[rgnidx].valid)
continue;
scanregion = &priv->universal_channel[rgnidx];
/* clear the parsed_region_chan for the first scan */
memset(&priv->parsed_region_chan, 0x00,
sizeof(priv->parsed_region_chan));
} else {
if (!priv->region_channel[rgnidx].valid)
continue;
scanregion = &priv->region_channel[rgnidx];
}
for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
struct chanscanparamset *chan = &scanchanlist[chanidx]; struct chanscanparamset *chan = &scanchanlist[chanidx];
cfp = scanregion->CFP + nextchan; cfp = scanregion->CFP + nextchan;
if (priv->enable11d)
scantype = lbs_get_scan_type_11d(cfp->channel,
&priv->parsed_region_chan);
if (scanregion->band == BAND_B || scanregion->band == BAND_G) if (scanregion->band == BAND_B || scanregion->band == BAND_G)
chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
struct ieee_ie_cf_param_set *cf; struct ieee_ie_cf_param_set *cf;
struct ieee_ie_ibss_param_set *ibss; struct ieee_ie_ibss_param_set *ibss;
DECLARE_SSID_BUF(ssid); DECLARE_SSID_BUF(ssid);
struct ieee_ie_country_info_set *pcountryinfo;
uint8_t *pos, *end, *p; uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
uint16_t beaconsize = 0; uint16_t beaconsize = 0;
@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got IBSS IE\n"); lbs_deb_scan("got IBSS IE\n");
break; break;
case WLAN_EID_COUNTRY:
pcountryinfo = (struct ieee_ie_country_info_set *) pos;
lbs_deb_scan("got COUNTRY IE\n");
if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->header.len > 254) {
lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
__func__,
pcountryinfo->header.len,
sizeof(pcountryinfo->countrycode));
ret = -1;
goto done;
}
memcpy(&bss->countryinfo, pcountryinfo,
pcountryinfo->header.len + 2);
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
(uint8_t *) pcountryinfo,
(int) (pcountryinfo->header.len + 2));
break;
case WLAN_EID_EXT_SUPP_RATES: case WLAN_EID_EXT_SUPP_RATES:
/* only process extended supported rate if data rate is /* only process extended supported rate if data rate is
* already found. Data rate IE should come before * already found. Data rate IE should come before
@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
/* SSID */ /* SSID */
iwe.cmd = SIOCGIWESSID; iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1; iwe.u.data.flags = 1;
iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
/* Mode */ /* Mode */
@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
return -EAGAIN; return -EAGAIN;
/* Update RSSI if current BSS is a locally created ad-hoc BSS */ /* Update RSSI if current BSS is a locally created ad-hoc BSS */
if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
CMD_OPTION_WAITFORRSP, 0, NULL); CMD_OPTION_WAITFORRSP, 0, NULL);
if (err)
goto out;
}
mutex_lock(&priv->lock); mutex_lock(&priv->lock);
list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra); dwrq->length = (ev - extra);
dwrq->flags = 0; dwrq->flags = 0;
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
return err; return err;
} }
@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
/* The size of the TLV buffer is equal to the entire command response /* The size of the TLV buffer is equal to the entire command response
* size (scanrespsize) minus the fixed fields (sizeof()'s), the * size (scanrespsize) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bssdescriptsize as bytesLef) and the command * BSS Descriptions (bssdescriptsize as bytesLef) and the command
* response header (S_DS_GEN) * response header (sizeof(struct cmd_header))
*/ */
tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
+ sizeof(scanresp->nr_sets) + sizeof(scanresp->nr_sets)
+ S_DS_GEN); + sizeof(struct cmd_header));
/* /*
* Process each scan response returned (scanresp->nr_sets). Save * Process each scan response returned (scanresp->nr_sets). Save

View File

@ -9,8 +9,36 @@
#include <net/iw_handler.h> #include <net/iw_handler.h>
struct lbs_private;
#define MAX_NETWORK_COUNT 128 #define MAX_NETWORK_COUNT 128
/** Chan-freq-TxPower mapping table*/
struct chan_freq_power {
/** channel Number */
u16 channel;
/** frequency of this channel */
u32 freq;
/** Max allowed Tx power level */
u16 maxtxpower;
/** TRUE:channel unsupported; FLASE:supported*/
u8 unsupported;
};
/** region-band mapping table*/
struct region_channel {
/** TRUE if this entry is valid */
u8 valid;
/** region code for US, Japan ... */
u8 region;
/** band B/G/A, used for BAND_CONFIG cmd */
u8 band;
/** Actual No. of elements in the array below */
u8 nrcfp;
/** chan-freq-txpower mapping table*/
struct chan_freq_power *CFP;
};
/** /**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl * @brief Maximum number of channels that can be sent in a setuserscan ioctl
*/ */
@ -18,6 +46,8 @@
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
u8 ssid_len); u8 ssid_len);

View File

@ -4,7 +4,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "hostcmd.h" #include "host.h"
#include "radiotap.h" #include "radiotap.h"
#include "decl.h" #include "decl.h"
#include "defs.h" #include "defs.h"

View File

@ -5,8 +5,8 @@
#define _LBS_TYPES_H_ #define _LBS_TYPES_H_
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/ieee80211.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/wireless.h>
struct ieee_ie_header { struct ieee_ie_header {
u8 id; u8 id;
@ -247,7 +247,7 @@ struct mrvl_meshie_val {
uint8_t active_metric_id; uint8_t active_metric_id;
uint8_t mesh_capability; uint8_t mesh_capability;
uint8_t mesh_id_len; uint8_t mesh_id_len;
uint8_t mesh_id[IW_ESSID_MAX_SIZE]; uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct mrvl_meshie { struct mrvl_meshie {

View File

@ -45,6 +45,64 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL; priv->pending_assoc_req = NULL;
} }
void lbs_send_disconnect_notification(struct lbs_private *priv)
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
}
static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
{
union iwreq_data iwrq;
u8 buf[50];
lbs_deb_enter(LBS_DEB_WEXT);
memset(&iwrq, 0, sizeof(union iwreq_data));
memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf) - 1, "%s", str);
iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
/* Send Event to upper layer */
lbs_deb_wext("event indication string %s\n", (char *)buf);
lbs_deb_wext("event indication length %d\n", iwrq.data.length);
lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
lbs_deb_leave(LBS_DEB_WEXT);
}
/**
* @brief This function handles MIC failure event.
*
* @param priv A pointer to struct lbs_private structure
* @para event the event id
* @return n/a
*/
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
{
char buf[50];
lbs_deb_enter(LBS_DEB_CMD);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
strcat(buf, "unicast ");
else
strcat(buf, "multicast ");
lbs_send_iwevcustom_event(priv, buf);
lbs_deb_leave(LBS_DEB_CMD);
}
/** /**
* @brief Find the channel frequency power info with specific channel * @brief Find the channel frequency power info with specific channel
* *
@ -65,8 +123,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j]; rc = &priv->region_channel[j];
if (priv->enable11d)
rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP) if (!rc->valid || !rc->CFP)
continue; continue;
if (rc->band != band) if (rc->band != band)
@ -106,8 +162,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j]; rc = &priv->region_channel[j];
if (priv->enable11d)
rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP) if (!rc->valid || !rc->CFP)
continue; continue;
if (rc->band != band) if (rc->band != band)
@ -168,12 +222,12 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
cfp = lbs_find_cfp_by_band_and_channel(priv, 0, cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
priv->curbssparams.channel); priv->channel);
if (!cfp) { if (!cfp) {
if (priv->curbssparams.channel) if (priv->channel)
lbs_deb_wext("invalid channel %d\n", lbs_deb_wext("invalid channel %d\n",
priv->curbssparams.channel); priv->channel);
return -EINVAL; return -EINVAL;
} }
@ -546,8 +600,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
struct chan_freq_power *cfp; struct chan_freq_power *cfp;
u8 rates[MAX_RATES + 1]; u8 rates[MAX_RATES + 1];
u8 flag = 0;
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
dwrq->length = sizeof(struct iw_range); dwrq->length = sizeof(struct iw_range);
@ -569,52 +621,21 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
range->scan_capa = IW_SCAN_CAPA_ESSID; range->scan_capa = IW_SCAN_CAPA_ESSID;
if (priv->enable11d && for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
(priv->connect_status == LBS_CONNECTED || && (j < ARRAY_SIZE(priv->region_channel)); j++) {
priv->mesh_connect_status == LBS_CONNECTED)) { cfp = priv->region_channel[j].CFP;
u8 chan_no;
u8 band;
struct parsed_region_chan_11d *parsed_region_chan =
&priv->parsed_region_chan;
if (parsed_region_chan == NULL) {
lbs_deb_wext("11d: parsed_region_chan is NULL\n");
goto out;
}
band = parsed_region_chan->band;
lbs_deb_wext("band %d, nr_char %d\n", band,
parsed_region_chan->nr_chan);
for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
&& (i < parsed_region_chan->nr_chan); i++) { && priv->region_channel[j].valid
chan_no = parsed_region_chan->chanpwr[i].chan; && cfp
lbs_deb_wext("chan_no %d\n", chan_no); && (i < priv->region_channel[j].nrcfp); i++) {
range->freq[range->num_frequency].i = (long)chan_no; range->freq[range->num_frequency].i =
(long)cfp->channel;
range->freq[range->num_frequency].m = range->freq[range->num_frequency].m =
(long)lbs_chan_2_freq(chan_no) * 100000; (long)cfp->freq * 100000;
range->freq[range->num_frequency].e = 1; range->freq[range->num_frequency].e = 1;
cfp++;
range->num_frequency++; range->num_frequency++;
} }
flag = 1;
}
if (!flag) {
for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
&& (j < ARRAY_SIZE(priv->region_channel)); j++) {
cfp = priv->region_channel[j].CFP;
for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
&& priv->region_channel[j].valid
&& cfp
&& (i < priv->region_channel[j].nrcfp); i++) {
range->freq[range->num_frequency].i =
(long)cfp->channel;
range->freq[range->num_frequency].m =
(long)cfp->freq * 100000;
range->freq[range->num_frequency].e = 1;
cfp++;
range->num_frequency++;
}
}
} }
lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n", lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
@ -699,7 +720,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
| IW_ENC_CAPA_CIPHER_CCMP; | IW_ENC_CAPA_CIPHER_CCMP;
} }
out:
lbs_deb_leave(LBS_DEB_WEXT); lbs_deb_leave(LBS_DEB_WEXT);
return 0; return 0;
} }
@ -832,7 +852,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
u32 rssi_qual; u32 rssi_qual;
u32 tx_qual; u32 tx_qual;
u32 quality = 0; u32 quality = 0;
int stats_valid = 0; int ret, stats_valid = 0;
u8 rssi; u8 rssi;
u32 tx_retries; u32 tx_retries;
struct cmd_ds_802_11_get_log log; struct cmd_ds_802_11_get_log log;
@ -881,7 +901,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
memset(&log, 0, sizeof(log)); memset(&log, 0, sizeof(log));
log.hdr.size = cpu_to_le16(sizeof(log)); log.hdr.size = cpu_to_le16(sizeof(log));
lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
if (ret)
goto out;
tx_retries = le32_to_cpu(log.retry); tx_retries = le32_to_cpu(log.retry);
@ -909,8 +931,10 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
stats_valid = 1; stats_valid = 1;
/* update stats asynchronously for future calls */ /* update stats asynchronously for future calls */
lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL); 0, 0, NULL);
if (ret)
lbs_pr_err("RSSI command failed\n");
out: out:
if (!stats_valid) { if (!stats_valid) {
priv->wstats.miss.beacon = 0; priv->wstats.miss.beacon = 0;
@ -1020,7 +1044,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
goto out; goto out;
} }
if (fwrq->m != priv->curbssparams.channel) { if (fwrq->m != priv->channel) {
lbs_deb_wext("mesh channel change forces eth disconnect\n"); lbs_deb_wext("mesh channel change forces eth disconnect\n");
if (priv->mode == IW_MODE_INFRA) if (priv->mode == IW_MODE_INFRA)
lbs_cmd_80211_deauthenticate(priv, lbs_cmd_80211_deauthenticate(priv,
@ -2023,7 +2047,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
{ {
struct lbs_private *priv = dev->ml_priv; struct lbs_private *priv = dev->ml_priv;
int ret = 0; int ret = 0;
u8 ssid[IW_ESSID_MAX_SIZE]; u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len = 0; u8 ssid_len = 0;
struct assoc_request * assoc_req; struct assoc_request * assoc_req;
int in_ssid_len = dwrq->length; int in_ssid_len = dwrq->length;
@ -2037,7 +2061,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
} }
/* Check the size of the string */ /* Check the size of the string */
if (in_ssid_len > IW_ESSID_MAX_SIZE) { if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG; ret = -E2BIG;
goto out; goto out;
} }
@ -2068,7 +2092,7 @@ out:
ret = -ENOMEM; ret = -ENOMEM;
} else { } else {
/* Copy the SSID to the association request */ /* Copy the SSID to the association request */
memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE); memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = ssid_len; assoc_req->ssid_len = ssid_len;
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
lbs_postpone_association_work(priv); lbs_postpone_association_work(priv);
@ -2119,7 +2143,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
} }
/* Check the size of the string */ /* Check the size of the string */
if (dwrq->length > IW_ESSID_MAX_SIZE) { if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG; ret = -E2BIG;
goto out; goto out;
} }
@ -2134,7 +2158,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
} }
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel); priv->channel);
out: out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret; return ret;

View File

@ -4,7 +4,15 @@
#ifndef _LBS_WEXT_H_ #ifndef _LBS_WEXT_H_
#define _LBS_WEXT_H_ #define _LBS_WEXT_H_
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def lbs_handler_def;
extern struct iw_handler_def mesh_handler_def; extern struct iw_handler_def mesh_handler_def;
struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
struct lbs_private *priv,
u8 band,
u16 channel);
#endif #endif

View File

@ -60,8 +60,15 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
/* Set priv->firmware type, determine firmware properties /* Set priv->firmware type, determine firmware properties
* This function can be called before we have registerred with netdev, * This function can be called before we have registerred with netdev,
* so all errors go out with dev_* rather than printk * so all errors go out with dev_* rather than printk
*
* If non-NULL stores a firmware description in fw_name.
* If non-NULL stores a HW version in hw_ver
*
* These are output via generic cfg80211 ethtool support.
*/ */
int determine_fw_capabilities(struct orinoco_private *priv) int determine_fw_capabilities(struct orinoco_private *priv,
char *fw_name, size_t fw_name_len,
u32 *hw_ver)
{ {
struct device *dev = priv->dev; struct device *dev = priv->dev;
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
@ -85,6 +92,12 @@ int determine_fw_capabilities(struct orinoco_private *priv)
dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
if (hw_ver)
*hw_ver = (((nic_id.id & 0xff) << 24) |
((nic_id.variant & 0xff) << 16) |
((nic_id.major & 0xff) << 8) |
(nic_id.minor & 0xff));
priv->firmware_type = determine_firmware_type(&nic_id); priv->firmware_type = determine_firmware_type(&nic_id);
/* Get the firmware version */ /* Get the firmware version */
@ -135,8 +148,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
case FIRMWARE_TYPE_AGERE: case FIRMWARE_TYPE_AGERE:
/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, if (fw_name)
"Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
sta_id.major, sta_id.minor);
firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
@ -185,8 +199,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
tmp[SYMBOL_MAX_VER_LEN] = '\0'; tmp[SYMBOL_MAX_VER_LEN] = '\0';
} }
snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, if (fw_name)
"Symbol %s", tmp); snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
priv->has_ibss = (firmver >= 0x20000); priv->has_ibss = (firmver >= 0x20000);
priv->has_wep = (firmver >= 0x15012); priv->has_wep = (firmver >= 0x15012);
@ -224,9 +238,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
* different and less well tested */ * different and less well tested */
/* D-Link MAC : 00:40:05:* */ /* D-Link MAC : 00:40:05:* */
/* Addtron MAC : 00:90:D1:* */ /* Addtron MAC : 00:90:D1:* */
snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, if (fw_name)
"Intersil %d.%d.%d", sta_id.major, sta_id.minor, snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
sta_id.variant); sta_id.major, sta_id.minor, sta_id.variant);
firmver = ((unsigned long)sta_id.major << 16) | firmver = ((unsigned long)sta_id.major << 16) |
((unsigned long)sta_id.minor << 8) | sta_id.variant; ((unsigned long)sta_id.minor << 8) | sta_id.variant;
@ -245,7 +259,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
} }
break; break;
} }
dev_info(dev, "Firmware determined as %s\n", priv->fw_name); if (fw_name)
dev_info(dev, "Firmware determined as %s\n", fw_name);
return 0; return 0;
} }

View File

@ -24,7 +24,8 @@
struct orinoco_private; struct orinoco_private;
struct dev_addr_list; struct dev_addr_list;
int determine_fw_capabilities(struct orinoco_private *priv); int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
size_t fw_name_len, u32 *hw_ver);
int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic); int orinoco_get_bitratemode(int bitrate, int automatic);

View File

@ -83,7 +83,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/wireless.h> #include <linux/wireless.h>
@ -162,8 +161,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
| HERMES_EV_WTERR | HERMES_EV_INFO \ | HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP) | HERMES_EV_INFDROP)
static const struct ethtool_ops orinoco_ethtool_ops;
/********************************************************************/ /********************************************************************/
/* Data types */ /* Data types */
/********************************************************************/ /********************************************************************/
@ -1994,7 +1991,9 @@ int orinoco_init(struct orinoco_private *priv)
goto out; goto out;
} }
err = determine_fw_capabilities(priv); err = determine_fw_capabilities(priv, wiphy->fw_version,
sizeof(wiphy->fw_version),
&wiphy->hw_version);
if (err != 0) { if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n"); dev_err(dev, "Incompatible firmware, aborting\n");
goto out; goto out;
@ -2010,7 +2009,9 @@ int orinoco_init(struct orinoco_private *priv)
priv->do_fw_download = 0; priv->do_fw_download = 0;
/* Check firmware version again */ /* Check firmware version again */
err = determine_fw_capabilities(priv); err = determine_fw_capabilities(priv, wiphy->fw_version,
sizeof(wiphy->fw_version),
&wiphy->hw_version);
if (err != 0) { if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n"); dev_err(dev, "Incompatible firmware, aborting\n");
goto out; goto out;
@ -2212,7 +2213,6 @@ int orinoco_if_add(struct orinoco_private *priv,
dev->ieee80211_ptr = wdev; dev->ieee80211_ptr = wdev;
dev->netdev_ops = &orinoco_netdev_ops; dev->netdev_ops = &orinoco_netdev_ops;
dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->watchdog_timeo = HZ; /* 1 second timeout */
dev->ethtool_ops = &orinoco_ethtool_ops;
dev->wireless_handlers = &orinoco_handler_def; dev->wireless_handlers = &orinoco_handler_def;
#ifdef WIRELESS_SPY #ifdef WIRELESS_SPY
dev->wireless_data = &priv->wireless_data; dev->wireless_data = &priv->wireless_data;
@ -2349,27 +2349,6 @@ void orinoco_down(struct orinoco_private *priv)
} }
EXPORT_SYMBOL(orinoco_down); EXPORT_SYMBOL(orinoco_down);
static void orinoco_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct orinoco_private *priv = ndev_priv(dev);
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
if (dev->dev.parent)
strncpy(info->bus_info, dev_name(dev->dev.parent),
sizeof(info->bus_info) - 1);
else
snprintf(info->bus_info, sizeof(info->bus_info) - 1,
"PCMCIA %p", priv->hw.iobase);
}
static const struct ethtool_ops orinoco_ethtool_ops = {
.get_drvinfo = orinoco_get_drvinfo,
.get_link = ethtool_op_get_link,
};
/********************************************************************/ /********************************************************************/
/* Module initialization */ /* Module initialization */
/********************************************************************/ /********************************************************************/

View File

@ -93,7 +93,6 @@ struct orinoco_private {
/* Capabilities of the hardware/firmware */ /* Capabilities of the hardware/firmware */
fwtype_t firmware_type; fwtype_t firmware_type;
char fw_name[32];
int ibss_port; int ibss_port;
int nicbuf_size; int nicbuf_size;
u16 channel_mask; u16 channel_mask;

View File

@ -53,6 +53,32 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci. When compiled as a module, this driver will be called rt61pci.
config RT2800PCI_PCI
tristate
depends on PCI
default y
config RT2800PCI_SOC
tristate
depends on RALINK_RT288X || RALINK_RT305X
default y
config RT2800PCI
tristate "Ralink rt2800 (PCI/PCMCIA) support"
depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
select RT2X00_LIB_PCI if RT2800PCI_PCI
select RT2X00_LIB_SOC if RT2800PCI_SOC
select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
select EEPROM_93CX6
---help---
This adds support for rt2800 wireless chipset family.
Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
When compiled as a module, this driver will be called "rt2800pci.ko".
config RT2500USB config RT2500USB
tristate "Ralink rt2500 (USB) support" tristate "Ralink rt2500 (USB) support"
depends on USB depends on USB
@ -95,6 +121,10 @@ config RT2X00_LIB_PCI
tristate tristate
select RT2X00_LIB select RT2X00_LIB
config RT2X00_LIB_SOC
tristate
select RT2X00_LIB
config RT2X00_LIB_USB config RT2X00_LIB_USB
tristate tristate
select RT2X00_LIB select RT2X00_LIB

View File

@ -11,10 +11,12 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
obj-$(CONFIG_RT2400PCI) += rt2400pci.o obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o obj-$(CONFIG_RT61PCI) += rt61pci.o
obj-$(CONFIG_RT2800PCI) += rt2800pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o obj-$(CONFIG_RT73USB) += rt73usb.o
obj-$(CONFIG_RT2800USB) += rt2800usb.o obj-$(CONFIG_RT2800USB) += rt2800usb.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -158,6 +158,13 @@ struct rt2x00_chip {
#define RT2561 0x0302 #define RT2561 0x0302
#define RT2661 0x0401 #define RT2661 0x0401
#define RT2571 0x1300 #define RT2571 0x1300
#define RT2860 0x0601 /* 2.4GHz PCI/CB */
#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */
#define RT2890 0x0701 /* 2.4GHz PCIe */
#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */
#define RT2880 0x2880 /* WSOC */
#define RT3052 0x3052 /* WSOC */
#define RT3090 0x3090 /* 2.4GHz PCIe */
#define RT2870 0x1600 #define RT2870 0x1600
u16 rf; u16 rf;

View File

@ -0,0 +1,159 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00soc
Abstract: rt2x00 generic soc device routines.
*/
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "rt2x00.h"
#include "rt2x00soc.h"
static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rf);
rt2x00dev->rf = NULL;
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
}
static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
struct platform_device *pdev = to_platform_device(rt2x00dev->dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start);
if (!rt2x00dev->csr.base)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
goto exit;
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
if (!rt2x00dev->rf)
goto exit;
return 0;
exit:
ERROR_PROBE("Failed to allocate registers.\n");
rt2x00soc_free_reg(rt2x00dev);
return -ENOMEM;
}
int rt2x00soc_probe(struct platform_device *pdev,
const unsigned short chipset,
const struct rt2x00_ops *ops)
{
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
ERROR_PROBE("Failed to allocate hardware.\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &pdev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00dev->irq = platform_get_irq(pdev, 0);
rt2x00dev->name = pdev->dev.driver->name;
rt2x00_set_chip_rt(rt2x00dev, chipset);
retval = rt2x00soc_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_reg;
return 0;
exit_free_reg:
rt2x00soc_free_reg(rt2x00dev);
exit_free_device:
ieee80211_free_hw(hw);
return retval;
}
int rt2x00soc_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
rt2x00soc_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00soc_remove);
#ifdef CONFIG_PM
int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_suspend(rt2x00dev, state);
}
EXPORT_SYMBOL_GPL(rt2x00soc_suspend);
int rt2x00soc_resume(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00soc_resume);
#endif /* CONFIG_PM */
/*
* rt2x00soc module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 soc library");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
Module: rt2x00soc
Abstract: Data structures for the rt2x00soc module.
*/
#ifndef RT2X00SOC_H
#define RT2X00SOC_H
#define KSEG1ADDR(__ptr) __ptr
#define __rt2x00soc_probe(__chipset, __ops) \
static int __rt2x00soc_probe(struct platform_device *pdev) \
{ \
return rt2x00soc_probe(pdev, (__chipset), (__ops)); \
}
/*
* SoC driver handlers.
*/
int rt2x00soc_probe(struct platform_device *pdev,
const unsigned short chipset,
const struct rt2x00_ops *ops);
int rt2x00soc_remove(struct platform_device *pdev);
#ifdef CONFIG_PM
int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);
int rt2x00soc_resume(struct platform_device *pdev);
#else
#define rt2x00soc_suspend NULL
#define rt2x00soc_resume NULL
#endif /* CONFIG_PM */
#endif /* RT2X00SOC_H */

View File

@ -183,8 +183,11 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip_id); wl->chip_id);
break; break;
case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11: case CHIP_ID_1251_PG11:
wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)",
wl->chip_id);
break;
case CHIP_ID_1251_PG10:
default: default:
wl1251_error("unsupported chip id: 0x%x", wl->chip_id); wl1251_error("unsupported chip id: 0x%x", wl->chip_id);
ret = -ENODEV; ret = -ENODEV;
@ -1426,4 +1429,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
MODULE_ALIAS("spi:wl12xx"); MODULE_ALIAS("spi:wl1251");

View File

@ -153,7 +153,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
beacon ? "beacon" : ""); beacon ? "beacon" : "");
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
ieee80211_rx(wl->hw, skb); ieee80211_rx_ni(wl->hw, skb);
} }
static void wl1251_rx_ack(struct wl1251 *wl) static void wl1251_rx_ack(struct wl1251 *wl)

View File

@ -307,7 +307,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
static struct spi_driver wl1251_spi_driver = { static struct spi_driver wl1251_spi_driver = {
.driver = { .driver = {
.name = "wl12xx", .name = "wl1251",
.bus = &spi_bus_type, .bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },

View File

@ -32,6 +32,8 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "wl1271_conf.h"
#define DRIVER_NAME "wl1271" #define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": " #define DRIVER_PREFIX DRIVER_NAME ": "
@ -97,21 +99,42 @@ enum {
} while (0) } while (0)
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ #define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
CFG_BSSID_FILTER_EN) CFG_BSSID_FILTER_EN | \
CFG_MC_FILTER_EN)
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ #define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
#define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin"
#define WL1271_BUSY_WORD_LEN 8 /*
* Enable/disable 802.11a support for WL1273
*/
#undef WL1271_80211A_ENABLED
/*
* FIXME: for the wl1271, a busy word count of 1 here will result in a more
* optimal SPI interface. There is some SPI bug however, causing RXS time outs
* with this mode occasionally on boot, so lets have three for now. A value of
* three should make sure, that the chipset will always be ready, though this
* will impact throughput and latencies slightly.
*/
#define WL1271_BUSY_WORD_CNT 3
#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
#define WL1271_ELP_HW_STATE_ASLEEP 0 #define WL1271_ELP_HW_STATE_ASLEEP 0
#define WL1271_ELP_HW_STATE_IRQ 1 #define WL1271_ELP_HW_STATE_IRQ 1
#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1
#define ACX_TX_DESCRIPTORS 32
enum wl1271_state { enum wl1271_state {
WL1271_STATE_OFF, WL1271_STATE_OFF,
WL1271_STATE_ON, WL1271_STATE_ON,
@ -134,6 +157,8 @@ struct wl1271_partition {
struct wl1271_partition_set { struct wl1271_partition_set {
struct wl1271_partition mem; struct wl1271_partition mem;
struct wl1271_partition reg; struct wl1271_partition reg;
struct wl1271_partition mem2;
struct wl1271_partition mem3;
}; };
struct wl1271; struct wl1271;
@ -258,15 +283,15 @@ struct wl1271_debugfs {
/* FW status registers */ /* FW status registers */
struct wl1271_fw_status { struct wl1271_fw_status {
u32 intr; __le32 intr;
u8 fw_rx_counter; u8 fw_rx_counter;
u8 drv_rx_counter; u8 drv_rx_counter;
u8 reserved; u8 reserved;
u8 tx_results_counter; u8 tx_results_counter;
u32 rx_pkt_descs[NUM_RX_PKT_DESC]; __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
u32 tx_released_blks[NUM_TX_QUEUES]; __le32 tx_released_blks[NUM_TX_QUEUES];
u32 fw_localtime; __le32 fw_localtime;
u32 padding[2]; __le32 padding[2];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct wl1271_rx_mem_pool_addr { struct wl1271_rx_mem_pool_addr {
@ -274,6 +299,15 @@ struct wl1271_rx_mem_pool_addr {
u32 addr_extra; u32 addr_extra;
}; };
struct wl1271_scan {
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
u8 active;
u8 high_prio;
u8 probe_requests;
};
struct wl1271 { struct wl1271 {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
bool mac80211_registered; bool mac80211_registered;
@ -288,10 +322,7 @@ struct wl1271 {
enum wl1271_state state; enum wl1271_state state;
struct mutex mutex; struct mutex mutex;
int physical_mem_addr; struct wl1271_partition_set part;
int physical_reg_addr;
int virtual_mem_addr;
int virtual_reg_addr;
struct wl1271_chip chip; struct wl1271_chip chip;
@ -308,7 +339,6 @@ struct wl1271 {
u8 bss_type; u8 bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len; u8 ssid_len;
u8 listen_int;
int channel; int channel;
struct wl1271_acx_mem_map *target_mem_map; struct wl1271_acx_mem_map *target_mem_map;
@ -332,10 +362,14 @@ struct wl1271 {
bool tx_queue_stopped; bool tx_queue_stopped;
struct work_struct tx_work; struct work_struct tx_work;
struct work_struct filter_work;
/* Pending TX frames */ /* Pending TX frames */
struct sk_buff *tx_frames[16]; struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
/* Security sequence number counters */
u8 tx_security_last_seq;
u16 tx_security_seq_16;
u32 tx_security_seq_32;
/* FW Rx counter */ /* FW Rx counter */
u32 rx_counter; u32 rx_counter;
@ -354,10 +388,17 @@ struct wl1271 {
/* Are we currently scanning */ /* Are we currently scanning */
bool scanning; bool scanning;
struct wl1271_scan scan;
/* Our association ID */ /* Our association ID */
u16 aid; u16 aid;
/* currently configured rate set */
u32 basic_rate_set;
/* The current band */
enum ieee80211_band band;
/* Default key (for WEP) */ /* Default key (for WEP) */
u32 default_key; u32 default_key;
@ -368,6 +409,7 @@ struct wl1271 {
bool elp; bool elp;
struct completion *elp_compl; struct completion *elp_compl;
struct delayed_work elp_work;
/* we can be in psm, but not in elp, we have to differentiate */ /* we can be in psm, but not in elp, we have to differentiate */
bool psm; bool psm;
@ -383,11 +425,20 @@ struct wl1271 {
u32 buffer_32; u32 buffer_32;
u32 buffer_cmd; u32 buffer_cmd;
u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
struct wl1271_rx_descriptor *rx_descriptor;
struct wl1271_fw_status *fw_status; struct wl1271_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if; struct wl1271_tx_hw_res_if *tx_res_if;
struct ieee80211_vif *vif;
/* Used for a workaround to send disconnect before rejoining */
bool joined;
/* Current chipset configuration */
struct conf_drv_settings conf;
struct list_head list;
}; };
int wl1271_plt_start(struct wl1271 *wl); int wl1271_plt_start(struct wl1271 *wl);
@ -404,4 +455,13 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL1271 needs a 200ms sleep after power on */ /* WL1271 needs a 200ms sleep after power on */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
static inline bool wl1271_11a_enabled(void)
{
#ifdef WL1271_80211A_ENABLED
return true;
#else
return false;
#endif
}
#endif #endif

Some files were not shown because too many files have changed in this diff Show More