mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 16:54:20 +08:00
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.26
This commit is contained in:
commit
8c95b4773d
@ -142,6 +142,7 @@ enum ath5k_radio {
|
||||
AR5K_RF5112 = 2,
|
||||
AR5K_RF2413 = 3,
|
||||
AR5K_RF5413 = 4,
|
||||
AR5K_RF2425 = 5,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -449,14 +450,6 @@ struct ath5k_rx_status {
|
||||
#define AR5K_RXKEYIX_INVALID ((u8) - 1)
|
||||
#define AR5K_TXKEYIX_INVALID ((u32) - 1)
|
||||
|
||||
struct ath5k_mib_stats {
|
||||
u32 ackrcv_bad;
|
||||
u32 rts_bad;
|
||||
u32 rts_good;
|
||||
u32 fcs_bad;
|
||||
u32 beacons;
|
||||
};
|
||||
|
||||
|
||||
/**************************\
|
||||
BEACON TIMERS DEFINITIONS
|
||||
@ -1069,6 +1062,7 @@ extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
|
||||
extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
|
||||
extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
|
||||
extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
|
||||
/* EEPROM access functions */
|
||||
extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
|
||||
/* Protocol Control Unit Functions */
|
||||
@ -1097,7 +1091,6 @@ extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_be
|
||||
extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
|
||||
#endif
|
||||
extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics);
|
||||
/* ACK bit rate */
|
||||
void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
|
||||
/* ACK/CTS Timeouts */
|
||||
|
@ -126,6 +126,7 @@ static struct ath5k_srev_name srev_names[] = {
|
||||
{ "5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414 },
|
||||
{ "5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416 },
|
||||
{ "5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418 },
|
||||
{ "2425", AR5K_VERSION_VER, AR5K_SREV_VER_AR2425 },
|
||||
{ "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN },
|
||||
{ "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 },
|
||||
{ "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 },
|
||||
@ -2341,7 +2342,8 @@ ath5k_init(struct ath5k_softc *sc)
|
||||
* Enable interrupts.
|
||||
*/
|
||||
sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
|
||||
AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
|
||||
AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
|
||||
AR5K_INT_MIB;
|
||||
|
||||
ath5k_hw_set_intr(sc->ah, sc->imask);
|
||||
/* Set ack to be sent at low bit-rates */
|
||||
@ -2521,7 +2523,11 @@ ath5k_intr(int irq, void *dev_id)
|
||||
if (status & AR5K_INT_BMISS) {
|
||||
}
|
||||
if (status & AR5K_INT_MIB) {
|
||||
/* TODO */
|
||||
/*
|
||||
* These stats are also used for ANI i think
|
||||
* so how about updating them more often ?
|
||||
*/
|
||||
ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
|
||||
}
|
||||
}
|
||||
} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
|
||||
@ -3014,6 +3020,10 @@ ath5k_get_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats)
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
|
||||
/* Force update */
|
||||
ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
|
||||
|
||||
memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
|
||||
|
||||
|
@ -119,12 +119,70 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
|
||||
Attach/Detach Functions
|
||||
\***************************************/
|
||||
|
||||
/*
|
||||
* Power On Self Test helper function
|
||||
*/
|
||||
static int ath5k_hw_post(struct ath5k_hw *ah)
|
||||
{
|
||||
|
||||
int i, c;
|
||||
u16 cur_reg;
|
||||
u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
|
||||
u32 var_pattern;
|
||||
u32 static_pattern[4] = {
|
||||
0x55555555, 0xaaaaaaaa,
|
||||
0x66666666, 0x99999999
|
||||
};
|
||||
u32 init_val;
|
||||
u32 cur_val;
|
||||
|
||||
for (c = 0; c < 2; c++) {
|
||||
|
||||
cur_reg = regs[c];
|
||||
init_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
var_pattern = i << 16 | i;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
cur_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
if (cur_val != var_pattern) {
|
||||
ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Found on ndiswrapper dumps */
|
||||
var_pattern = 0x0039080f;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
var_pattern = static_pattern[i];
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
cur_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
if (cur_val != var_pattern) {
|
||||
ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Found on ndiswrapper dumps */
|
||||
var_pattern = 0x003b080f;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the device is supported and initialize the needed structs
|
||||
*/
|
||||
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
{
|
||||
struct ath5k_hw *ah;
|
||||
struct pci_dev *pdev = sc->pdev;
|
||||
u8 mac[ETH_ALEN];
|
||||
int ret;
|
||||
u32 srev;
|
||||
@ -204,15 +262,19 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
CHANNEL_2GHZ);
|
||||
|
||||
/* Return on unsuported chips (unsupported eeprom etc) */
|
||||
if(srev >= AR5K_SREV_VER_AR5416){
|
||||
if ((srev >= AR5K_SREV_VER_AR5416) &&
|
||||
(srev < AR5K_SREV_VER_AR2425)) {
|
||||
ATH5K_ERR(sc, "Device not yet supported.\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free;
|
||||
} else if (srev == AR5K_SREV_VER_AR2425) {
|
||||
ATH5K_WARN(sc, "Support for RF2425 is under development.\n");
|
||||
}
|
||||
|
||||
/* Identify single chip solutions */
|
||||
if((srev <= AR5K_SREV_VER_AR5414) &&
|
||||
(srev >= AR5K_SREV_VER_AR2413)) {
|
||||
if (((srev <= AR5K_SREV_VER_AR5414) &&
|
||||
(srev >= AR5K_SREV_VER_AR2413)) ||
|
||||
(srev == AR5K_SREV_VER_AR2425)) {
|
||||
ah->ah_single_chip = true;
|
||||
} else {
|
||||
ah->ah_single_chip = false;
|
||||
@ -241,23 +303,66 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
|
||||
ah->ah_radio = AR5K_RF2413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
|
||||
} else {
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
|
||||
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
|
||||
if (ah->ah_mac_srev <= AR5K_SREV_VER_AR5424 &&
|
||||
ah->ah_mac_srev >= AR5K_SREV_VER_AR2424)
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
|
||||
else if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2425)
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
|
||||
else
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
|
||||
|
||||
|
||||
/*
|
||||
* Register returns 0x4 for radio revision
|
||||
* so ath5k_hw_radio_revision doesn't parse the value
|
||||
* correctly. For now we are based on mac's srev to
|
||||
* identify RF2425 radio.
|
||||
*/
|
||||
} else if (srev == AR5K_SREV_VER_AR2425) {
|
||||
ah->ah_radio = AR5K_RF2425;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
|
||||
}
|
||||
|
||||
ah->ah_phy = AR5K_PHY(0);
|
||||
|
||||
/*
|
||||
* Identify AR5212-based PCI-E cards
|
||||
* And write some initial settings.
|
||||
*
|
||||
* (doing a "strings" on ndis driver
|
||||
* -ar5211.sys- reveals the following
|
||||
* pci-e related functions:
|
||||
*
|
||||
* pcieClockReq
|
||||
* pcieRxErrNotify
|
||||
* pcieL1SKPEnable
|
||||
* pcieAspm
|
||||
* pcieDisableAspmOnRfWake
|
||||
* pciePowerSaveEnable
|
||||
*
|
||||
* I guess these point to ClockReq but
|
||||
* i'm not sure.)
|
||||
*/
|
||||
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
|
||||
ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x24924924, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x28000039, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x53160824, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0xe5980579, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x001defff, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0xbe105554, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x000e3007, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x00000000, 0x4084);
|
||||
}
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
ret = ath5k_hw_post(ah);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
/*
|
||||
* Get card capabilities, values, ...
|
||||
*/
|
||||
@ -391,7 +496,7 @@ static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n");
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -655,7 +760,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
|
||||
if (ah->ah_radio != AR5K_RF5111 &&
|
||||
ah->ah_radio != AR5K_RF5112 &&
|
||||
ah->ah_radio != AR5K_RF5413 &&
|
||||
ah->ah_radio != AR5K_RF2413) {
|
||||
ah->ah_radio != AR5K_RF2413 &&
|
||||
ah->ah_radio != AR5K_RF2425) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid phy radio: %u\n", ah->ah_radio);
|
||||
return -EINVAL;
|
||||
@ -2849,15 +2955,19 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
|
||||
* Update mib counters (statistics)
|
||||
*/
|
||||
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
|
||||
struct ath5k_mib_stats *statistics)
|
||||
struct ieee80211_low_level_stats *stats)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/* Read-And-Clear */
|
||||
statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
|
||||
statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
|
||||
statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
|
||||
statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
|
||||
statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
|
||||
stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
|
||||
stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
|
||||
stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
|
||||
stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
|
||||
|
||||
/* XXX: Should we use this to track beacon count ?
|
||||
* -we read it anyway to clear the register */
|
||||
ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
|
||||
|
||||
/* Reset profile count registers on 5212*/
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
@ -2958,8 +3068,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
|
||||
for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
|
||||
|
||||
/* Set NULL encryption on non-5210*/
|
||||
if (ah->ah_version != AR5K_AR5210)
|
||||
/*
|
||||
* Set NULL encryption on AR5212+
|
||||
*
|
||||
* Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
|
||||
* AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
|
||||
*
|
||||
* Note2: Windows driver (ndiswrapper) sets this to
|
||||
* 0x00000714 instead of 0x00000007
|
||||
*/
|
||||
if (ah->ah_version > AR5K_AR5211)
|
||||
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
|
||||
AR5K_KEYTABLE_TYPE(entry));
|
||||
|
||||
|
@ -1282,6 +1282,213 @@ static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
|
||||
{ 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
|
||||
};
|
||||
|
||||
/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */
|
||||
/* XXX: No dumps for turbog yet, so turbog is the same with g here with some
|
||||
* minor tweaking based on dumps from other chips */
|
||||
static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
|
||||
{ AR5K_TXCFG,
|
||||
/* g gTurbo */
|
||||
{ 0x00000015, 0x00000015 } },
|
||||
{ AR5K_USEC_5211,
|
||||
{ 0x12e013ab, 0x098813cf } },
|
||||
{ AR5K_PHY_TURBO,
|
||||
{ 0x00000000, 0x00000003 } },
|
||||
{ AR5K_PHY(10),
|
||||
{ 0x0a020001, 0x0a020001 } },
|
||||
{ AR5K_PHY(13),
|
||||
{ 0x00000e0e, 0x00000e0e } },
|
||||
{ AR5K_PHY(14),
|
||||
{ 0x0000000b, 0x0000000b } },
|
||||
{ AR5K_PHY(17),
|
||||
{ 0x13721422, 0x13721422 } },
|
||||
{ AR5K_PHY(18),
|
||||
{ 0x00199a65, 0x00199a65 } },
|
||||
{ AR5K_PHY(20),
|
||||
{ 0x0c98b0da, 0x0c98b0da } },
|
||||
{ AR5K_PHY_SIG,
|
||||
{ 0x7ec80d2e, 0x7ec80d2e } },
|
||||
{ AR5K_PHY_AGCCOARSE,
|
||||
{ 0x3139605e, 0x3139605e } },
|
||||
{ AR5K_PHY(27),
|
||||
{ 0x050cb081, 0x050cb081 } },
|
||||
{ AR5K_PHY_RX_DELAY,
|
||||
{ 0x00000898, 0x000007d0 } },
|
||||
{ AR5K_PHY_FRAME_CTL_5211,
|
||||
{ 0xf7b81000, 0xf7b81000 } },
|
||||
{ AR5K_PHY_CCKTXCTL,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY(642),
|
||||
{ 0xd03e6788, 0xd03e6788 } },
|
||||
{ AR5K_PHY_GAIN_2GHZ,
|
||||
{ 0x0052c140, 0x0052c140 } },
|
||||
{ 0xa21c,
|
||||
{ 0x1883800a, 0x1883800a } },
|
||||
{ 0xa324,
|
||||
{ 0xa7cfa7cf, 0xa7cfa7cf } },
|
||||
{ 0xa328,
|
||||
{ 0xa7cfa7cf, 0xa7cfa7cf } },
|
||||
{ 0xa32c,
|
||||
{ 0xa7cfa7cf, 0xa7cfa7cf } },
|
||||
{ 0xa330,
|
||||
{ 0xa7cfa7cf, 0xa7cfa7cf } },
|
||||
{ 0xa334,
|
||||
{ 0xa7cfa7cf, 0xa7cfa7cf } },
|
||||
{ AR5K_DCU_FP,
|
||||
{ 0x000003e0, 0x000003e0 } },
|
||||
{ 0x8060,
|
||||
{ 0x0000000f, 0x0000000f } },
|
||||
{ 0x809c,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x80a0,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8118,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x811c,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8120,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8124,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8128,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x812c,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8130,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8134,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8138,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x813c,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0x8140,
|
||||
{ 0x800003f9, 0x800003f9 } },
|
||||
{ 0x8144,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY_AGC,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY(11),
|
||||
{ 0x0000a000, 0x0000a000 } },
|
||||
{ AR5K_PHY(15),
|
||||
{ 0x00200400, 0x00200400 } },
|
||||
{ AR5K_PHY(19),
|
||||
{ 0x1284233c, 0x1284233c } },
|
||||
{ AR5K_PHY_SCR,
|
||||
{ 0x0000001f, 0x0000001f } },
|
||||
{ AR5K_PHY_SLMT,
|
||||
{ 0x00000080, 0x00000080 } },
|
||||
{ AR5K_PHY_SCAL,
|
||||
{ 0x0000000e, 0x0000000e } },
|
||||
{ AR5K_PHY(86),
|
||||
{ 0x00081fff, 0x00081fff } },
|
||||
{ AR5K_PHY(96),
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY(97),
|
||||
{ 0x02800000, 0x02800000 } },
|
||||
{ AR5K_PHY(104),
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY(119),
|
||||
{ 0xfebadbe8, 0xfebadbe8 } },
|
||||
{ AR5K_PHY(120),
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ AR5K_PHY(121),
|
||||
{ 0xaaaaaaaa, 0xaaaaaaaa } },
|
||||
{ AR5K_PHY(122),
|
||||
{ 0x3c466478, 0x3c466478 } },
|
||||
{ AR5K_PHY(123),
|
||||
{ 0x000000aa, 0x000000aa } },
|
||||
{ AR5K_PHY_SCLOCK,
|
||||
{ 0x0000000c, 0x0000000c } },
|
||||
{ AR5K_PHY_SDELAY,
|
||||
{ 0x000000ff, 0x000000ff } },
|
||||
{ AR5K_PHY_SPENDING,
|
||||
{ 0x00000014, 0x00000014 } },
|
||||
{ 0xa228,
|
||||
{ 0x000009b5, 0x000009b5 } },
|
||||
{ AR5K_PHY_TXPOWER_RATE3,
|
||||
{ 0x20202020, 0x20202020 } },
|
||||
{ AR5K_PHY_TXPOWER_RATE4,
|
||||
{ 0x20202020, 0x20202020 } },
|
||||
{ 0xa23c,
|
||||
{ 0x93c889af, 0x93c889af } },
|
||||
{ 0xa24c,
|
||||
{ 0x00000001, 0x00000001 } },
|
||||
{ 0xa250,
|
||||
{ 0x0000a000, 0x0000a000 } },
|
||||
{ 0xa254,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0xa258,
|
||||
{ 0x0cc75380, 0x0cc75380 } },
|
||||
{ 0xa25c,
|
||||
{ 0x0f0f0f01, 0x0f0f0f01 } },
|
||||
{ 0xa260,
|
||||
{ 0x5f690f01, 0x5f690f01 } },
|
||||
{ 0xa264,
|
||||
{ 0x00418a11, 0x00418a11 } },
|
||||
{ 0xa268,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 0xa26c,
|
||||
{ 0x0c30c166, 0x0c30c166 } },
|
||||
{ 0xa270,
|
||||
{ 0x00820820, 0x00820820 } },
|
||||
{ 0xa274,
|
||||
{ 0x081a3caa, 0x081a3caa } },
|
||||
{ 0xa278,
|
||||
{ 0x1ce739ce, 0x1ce739ce } },
|
||||
{ 0xa27c,
|
||||
{ 0x051701ce, 0x051701ce } },
|
||||
{ 0xa300,
|
||||
{ 0x16010000, 0x16010000 } },
|
||||
{ 0xa304,
|
||||
{ 0x2c032402, 0x2c032402 } },
|
||||
{ 0xa308,
|
||||
{ 0x48433e42, 0x48433e42 } },
|
||||
{ 0xa30c,
|
||||
{ 0x5a0f500b, 0x5a0f500b } },
|
||||
{ 0xa310,
|
||||
{ 0x6c4b624a, 0x6c4b624a } },
|
||||
{ 0xa314,
|
||||
{ 0x7e8b748a, 0x7e8b748a } },
|
||||
{ 0xa318,
|
||||
{ 0x96cf8ccb, 0x96cf8ccb } },
|
||||
{ 0xa31c,
|
||||
{ 0xa34f9d0f, 0xa34f9d0f } },
|
||||
{ 0xa320,
|
||||
{ 0xa7cfa58f, 0xa7cfa58f } },
|
||||
{ 0xa348,
|
||||
{ 0x3fffffff, 0x3fffffff } },
|
||||
{ 0xa34c,
|
||||
{ 0x3fffffff, 0x3fffffff } },
|
||||
{ 0xa350,
|
||||
{ 0x3fffffff, 0x3fffffff } },
|
||||
{ 0xa354,
|
||||
{ 0x0003ffff, 0x0003ffff } },
|
||||
{ 0xa358,
|
||||
{ 0x79a8aa1f, 0x79a8aa1f } },
|
||||
{ 0xa35c,
|
||||
{ 0x066c420f, 0x066c420f } },
|
||||
{ 0xa360,
|
||||
{ 0x0f282207, 0x0f282207 } },
|
||||
{ 0xa364,
|
||||
{ 0x17601685, 0x17601685 } },
|
||||
{ 0xa368,
|
||||
{ 0x1f801104, 0x1f801104 } },
|
||||
{ 0xa36c,
|
||||
{ 0x37a00c03, 0x37a00c03 } },
|
||||
{ 0xa370,
|
||||
{ 0x3fc40883, 0x3fc40883 } },
|
||||
{ 0xa374,
|
||||
{ 0x57c00803, 0x57c00803 } },
|
||||
{ 0xa378,
|
||||
{ 0x5fd80682, 0x5fd80682 } },
|
||||
{ 0xa37c,
|
||||
{ 0x7fe00482, 0x7fe00482 } },
|
||||
{ 0xa380,
|
||||
{ 0x7f3c7bba, 0x7f3c7bba } },
|
||||
{ 0xa384,
|
||||
{ 0xf3307ff0, 0xf3307ff0 } },
|
||||
};
|
||||
|
||||
/*
|
||||
* Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
|
||||
* RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
|
||||
@ -1542,7 +1749,34 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
|
||||
ARRAY_SIZE(rf5112_ini_bbgain),
|
||||
rf5112_ini_bbgain, change_channel);
|
||||
|
||||
} else if (ah->ah_radio == AR5K_RF2425) {
|
||||
|
||||
if (mode < 2) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"unsupported channel mode: %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Map b to g */
|
||||
if (mode == 2)
|
||||
mode = 0;
|
||||
else
|
||||
mode = mode - 3;
|
||||
|
||||
/* Override a setting from ar5212_ini */
|
||||
ath5k_hw_reg_write(ah, 0x018830c6, AR5K_PHY(648));
|
||||
|
||||
ath5k_hw_ini_mode_registers(ah,
|
||||
ARRAY_SIZE(rf2425_ini_mode_end),
|
||||
rf2425_ini_mode_end, mode);
|
||||
|
||||
/* Baseband gain table */
|
||||
ath5k_hw_ini_registers(ah,
|
||||
ARRAY_SIZE(rf5112_ini_bbgain),
|
||||
rf5112_ini_bbgain, change_channel);
|
||||
|
||||
}
|
||||
|
||||
/* For AR5211 */
|
||||
} else if (ah->ah_version == AR5K_AR5211) {
|
||||
|
||||
|
@ -669,6 +669,7 @@ static const struct ath5k_ini_rf rfregs_5413[] = {
|
||||
/* RF2413/2414 mode-specific init registers */
|
||||
static const struct ath5k_ini_rf rfregs_2413[] = {
|
||||
{ 1, AR5K_RF_BUFFER_CONTROL_4,
|
||||
/* mode b mode g mode gTurbo */
|
||||
{ 0x00000020, 0x00000020, 0x00000020 } },
|
||||
{ 2, AR5K_RF_BUFFER_CONTROL_3,
|
||||
{ 0x02001408, 0x02001408, 0x02001408 } },
|
||||
@ -736,6 +737,83 @@ static const struct ath5k_ini_rf rfregs_2413[] = {
|
||||
{ 0x0000000e, 0x0000000e, 0x0000000e } },
|
||||
};
|
||||
|
||||
/* RF2425 mode-specific init registers */
|
||||
static const struct ath5k_ini_rf rfregs_2425[] = {
|
||||
{ 1, AR5K_RF_BUFFER_CONTROL_4,
|
||||
/* mode g mode gTurbo */
|
||||
{ 0x00000020, 0x00000020 } },
|
||||
{ 2, AR5K_RF_BUFFER_CONTROL_3,
|
||||
{ 0x02001408, 0x02001408 } },
|
||||
{ 3, AR5K_RF_BUFFER_CONTROL_6,
|
||||
{ 0x00e020c0, 0x00e020c0 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x10000000, 0x10000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x002a0000, 0x002a0000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00100000, 0x00100000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00020000, 0x00020000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00730000, 0x00730000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00f80000, 0x00f80000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00e70000, 0x00e70000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00140000, 0x00140000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00910040, 0x00910040 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x0007001a, 0x0007001a } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00410000, 0x00410000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00810060, 0x00810060 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00020803, 0x00020803 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00000000, 0x00000000 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00001660, 0x00001660 } },
|
||||
{ 6, AR5K_RF_BUFFER,
|
||||
{ 0x00001688, 0x00001688 } },
|
||||
{ 6, AR5K_RF_BUFFER_CONTROL_1,
|
||||
{ 0x00000001, 0x00000001 } },
|
||||
{ 7, AR5K_RF_BUFFER,
|
||||
{ 0x00006400, 0x00006400 } },
|
||||
{ 7, AR5K_RF_BUFFER,
|
||||
{ 0x00000800, 0x00000800 } },
|
||||
{ 7, AR5K_RF_BUFFER_CONTROL_2,
|
||||
{ 0x0000000e, 0x0000000e } },
|
||||
};
|
||||
|
||||
/* Initial RF Gain settings for RF5112 */
|
||||
static const struct ath5k_ini_rfgain rfgain_5112[] = {
|
||||
/* 5Ghz 2Ghz */
|
||||
@ -1348,7 +1426,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize RF5413/5414
|
||||
* Initialize RF5413/5414 and future chips
|
||||
* (until we come up with a better solution)
|
||||
*/
|
||||
static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channel, unsigned int mode)
|
||||
@ -1362,19 +1441,41 @@ static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
|
||||
|
||||
rf = ah->ah_rf_banks;
|
||||
|
||||
if (ah->ah_radio == AR5K_RF5413) {
|
||||
switch (ah->ah_radio) {
|
||||
case AR5K_RF5413:
|
||||
rf_ini = rfregs_5413;
|
||||
rf_size = ARRAY_SIZE(rfregs_5413);
|
||||
} else if (ah->ah_radio == AR5K_RF2413) {
|
||||
break;
|
||||
case AR5K_RF2413:
|
||||
rf_ini = rfregs_2413;
|
||||
rf_size = ARRAY_SIZE(rfregs_2413);
|
||||
|
||||
if (mode < 2) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid channel mode: %i\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mode = mode - 2;
|
||||
} else {
|
||||
break;
|
||||
case AR5K_RF2425:
|
||||
rf_ini = rfregs_2425;
|
||||
rf_size = ARRAY_SIZE(rfregs_2425);
|
||||
|
||||
if (mode < 2) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid channel mode: %i\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Map b to g */
|
||||
if (mode == 2)
|
||||
mode = 0;
|
||||
else
|
||||
mode = mode - 3;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1439,6 +1540,10 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
||||
ah->ah_rf_banks_size = sizeof(rfregs_2413);
|
||||
func = ath5k_hw_rf5413_rfregs;
|
||||
break;
|
||||
case AR5K_RF2425:
|
||||
ah->ah_rf_banks_size = sizeof(rfregs_2425);
|
||||
func = ath5k_hw_rf5413_rfregs;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1482,6 +1587,11 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
|
||||
size = ARRAY_SIZE(rfgain_2413);
|
||||
freq = 0; /* only 2Ghz */
|
||||
break;
|
||||
case AR5K_RF2425:
|
||||
ath5k_rfg = rfgain_2413;
|
||||
size = ARRAY_SIZE(rfgain_2413);
|
||||
freq = 0; /* only 2Ghz */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -2181,8 +2291,11 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
||||
* transmit anything if we call
|
||||
* this funtion, so we skip it
|
||||
* until we fix txpower.
|
||||
*
|
||||
* XXX: Assume same for RF2425
|
||||
* to be safe.
|
||||
*/
|
||||
if (ah->ah_radio == AR5K_RF2413)
|
||||
if ((ah->ah_radio == AR5K_RF2413) || (ah->ah_radio == AR5K_RF2425))
|
||||
return 0;
|
||||
|
||||
/* Reset TX power values */
|
||||
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic regulation domain extensions for the IEEE 802.11 stack
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "regdom.h"
|
||||
|
||||
static const struct ath5k_regdommap {
|
||||
enum ath5k_regdom dmn;
|
||||
enum ath5k_regdom dmn5;
|
||||
enum ath5k_regdom dmn2;
|
||||
} r_map[] = {
|
||||
{ DMN_DEFAULT, DMN_DEBUG, DMN_DEBUG },
|
||||
{ DMN_NULL_WORLD, DMN_NULL, DMN_WORLD },
|
||||
{ DMN_NULL_ETSIB, DMN_NULL, DMN_ETSIB },
|
||||
{ DMN_NULL_ETSIC, DMN_NULL, DMN_ETSIC },
|
||||
{ DMN_FCC1_FCCA, DMN_FCC1, DMN_FCCA },
|
||||
{ DMN_FCC1_WORLD, DMN_FCC1, DMN_WORLD },
|
||||
{ DMN_FCC2_FCCA, DMN_FCC2, DMN_FCCA },
|
||||
{ DMN_FCC2_WORLD, DMN_FCC2, DMN_WORLD },
|
||||
{ DMN_FCC2_ETSIC, DMN_FCC2, DMN_ETSIC },
|
||||
{ DMN_FRANCE_NULL, DMN_ETSI3, DMN_ETSI3 },
|
||||
{ DMN_FCC3_FCCA, DMN_FCC3, DMN_WORLD },
|
||||
{ DMN_ETSI1_WORLD, DMN_ETSI1, DMN_WORLD },
|
||||
{ DMN_ETSI3_ETSIA, DMN_ETSI3, DMN_WORLD },
|
||||
{ DMN_ETSI2_WORLD, DMN_ETSI2, DMN_WORLD },
|
||||
{ DMN_ETSI3_WORLD, DMN_ETSI3, DMN_WORLD },
|
||||
{ DMN_ETSI4_WORLD, DMN_ETSI4, DMN_WORLD },
|
||||
{ DMN_ETSI4_ETSIC, DMN_ETSI4, DMN_ETSIC },
|
||||
{ DMN_ETSI5_WORLD, DMN_ETSI5, DMN_WORLD },
|
||||
{ DMN_ETSI6_WORLD, DMN_ETSI6, DMN_WORLD },
|
||||
{ DMN_ETSI_NULL, DMN_ETSI1, DMN_ETSI1 },
|
||||
{ DMN_MKK1_MKKA, DMN_MKK1, DMN_MKKA },
|
||||
{ DMN_MKK1_MKKB, DMN_MKK1, DMN_MKKA },
|
||||
{ DMN_APL4_WORLD, DMN_APL4, DMN_WORLD },
|
||||
{ DMN_MKK2_MKKA, DMN_MKK2, DMN_MKKA },
|
||||
{ DMN_APL_NULL, DMN_APL1, DMN_NULL },
|
||||
{ DMN_APL2_WORLD, DMN_APL2, DMN_WORLD },
|
||||
{ DMN_APL2_APLC, DMN_APL2, DMN_WORLD },
|
||||
{ DMN_APL3_WORLD, DMN_APL3, DMN_WORLD },
|
||||
{ DMN_MKK1_FCCA, DMN_MKK1, DMN_FCCA },
|
||||
{ DMN_APL2_APLD, DMN_APL2, DMN_APLD },
|
||||
{ DMN_MKK1_MKKA1, DMN_MKK1, DMN_MKKA },
|
||||
{ DMN_MKK1_MKKA2, DMN_MKK1, DMN_MKKA },
|
||||
{ DMN_APL1_WORLD, DMN_APL1, DMN_WORLD },
|
||||
{ DMN_APL1_FCCA, DMN_APL1, DMN_FCCA },
|
||||
{ DMN_APL1_APLA, DMN_APL1, DMN_WORLD },
|
||||
{ DMN_APL1_ETSIC, DMN_APL1, DMN_ETSIC },
|
||||
{ DMN_APL2_ETSIC, DMN_APL2, DMN_ETSIC },
|
||||
{ DMN_APL5_WORLD, DMN_APL5, DMN_WORLD },
|
||||
{ DMN_WOR0_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR1_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR2_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR3_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR4_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR5_ETSIC, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR01_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WOR02_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_EU1_WORLD, DMN_ETSI1, DMN_WORLD },
|
||||
{ DMN_WOR9_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
{ DMN_WORA_WORLD, DMN_WORLD, DMN_WORLD },
|
||||
};
|
||||
|
||||
enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(r_map); i++) {
|
||||
if (r_map[i].dmn == dmn) {
|
||||
if (mhz >= 2000 && mhz <= 3000)
|
||||
return r_map[i].dmn2;
|
||||
if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN &&
|
||||
mhz <= IEEE80211_CHANNELS_5GHZ_MAX)
|
||||
return r_map[i].dmn5;
|
||||
}
|
||||
}
|
||||
|
||||
return DMN_DEBUG;
|
||||
}
|
||||
|
||||
u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee)
|
||||
{
|
||||
u32 regdomain = (u32)ieee;
|
||||
|
||||
/*
|
||||
* Use the default regulation domain if the value is empty
|
||||
* or not supported by the net80211 regulation code.
|
||||
*/
|
||||
if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) ==
|
||||
DMN_DEBUG)
|
||||
return (u16)AR5K_TUNE_REGDOMAIN;
|
||||
|
||||
/* It is supported, just return the value */
|
||||
return regdomain;
|
||||
}
|
||||
|
||||
enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain)
|
||||
{
|
||||
enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain;
|
||||
|
||||
return ieee;
|
||||
}
|
||||
|
@ -1,500 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _IEEE80211_REGDOMAIN_H_
|
||||
#define _IEEE80211_REGDOMAIN_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Default regulation domain if stored value EEPROM value is invalid */
|
||||
#define AR5K_TUNE_REGDOMAIN DMN_FCC2_FCCA /* Canada */
|
||||
#define AR5K_TUNE_CTRY CTRY_DEFAULT
|
||||
|
||||
|
||||
enum ath5k_regdom {
|
||||
DMN_DEFAULT = 0x00,
|
||||
DMN_NULL_WORLD = 0x03,
|
||||
DMN_NULL_ETSIB = 0x07,
|
||||
DMN_NULL_ETSIC = 0x08,
|
||||
DMN_FCC1_FCCA = 0x10,
|
||||
DMN_FCC1_WORLD = 0x11,
|
||||
DMN_FCC2_FCCA = 0x20,
|
||||
DMN_FCC2_WORLD = 0x21,
|
||||
DMN_FCC2_ETSIC = 0x22,
|
||||
DMN_FRANCE_NULL = 0x31,
|
||||
DMN_FCC3_FCCA = 0x3A,
|
||||
DMN_ETSI1_WORLD = 0x37,
|
||||
DMN_ETSI3_ETSIA = 0x32,
|
||||
DMN_ETSI2_WORLD = 0x35,
|
||||
DMN_ETSI3_WORLD = 0x36,
|
||||
DMN_ETSI4_WORLD = 0x30,
|
||||
DMN_ETSI4_ETSIC = 0x38,
|
||||
DMN_ETSI5_WORLD = 0x39,
|
||||
DMN_ETSI6_WORLD = 0x34,
|
||||
DMN_ETSI_NULL = 0x33,
|
||||
DMN_MKK1_MKKA = 0x40,
|
||||
DMN_MKK1_MKKB = 0x41,
|
||||
DMN_APL4_WORLD = 0x42,
|
||||
DMN_MKK2_MKKA = 0x43,
|
||||
DMN_APL_NULL = 0x44,
|
||||
DMN_APL2_WORLD = 0x45,
|
||||
DMN_APL2_APLC = 0x46,
|
||||
DMN_APL3_WORLD = 0x47,
|
||||
DMN_MKK1_FCCA = 0x48,
|
||||
DMN_APL2_APLD = 0x49,
|
||||
DMN_MKK1_MKKA1 = 0x4A,
|
||||
DMN_MKK1_MKKA2 = 0x4B,
|
||||
DMN_APL1_WORLD = 0x52,
|
||||
DMN_APL1_FCCA = 0x53,
|
||||
DMN_APL1_APLA = 0x54,
|
||||
DMN_APL1_ETSIC = 0x55,
|
||||
DMN_APL2_ETSIC = 0x56,
|
||||
DMN_APL5_WORLD = 0x58,
|
||||
DMN_WOR0_WORLD = 0x60,
|
||||
DMN_WOR1_WORLD = 0x61,
|
||||
DMN_WOR2_WORLD = 0x62,
|
||||
DMN_WOR3_WORLD = 0x63,
|
||||
DMN_WOR4_WORLD = 0x64,
|
||||
DMN_WOR5_ETSIC = 0x65,
|
||||
DMN_WOR01_WORLD = 0x66,
|
||||
DMN_WOR02_WORLD = 0x67,
|
||||
DMN_EU1_WORLD = 0x68,
|
||||
DMN_WOR9_WORLD = 0x69,
|
||||
DMN_WORA_WORLD = 0x6A,
|
||||
|
||||
DMN_APL1 = 0xf0000001,
|
||||
DMN_APL2 = 0xf0000002,
|
||||
DMN_APL3 = 0xf0000004,
|
||||
DMN_APL4 = 0xf0000008,
|
||||
DMN_APL5 = 0xf0000010,
|
||||
DMN_ETSI1 = 0xf0000020,
|
||||
DMN_ETSI2 = 0xf0000040,
|
||||
DMN_ETSI3 = 0xf0000080,
|
||||
DMN_ETSI4 = 0xf0000100,
|
||||
DMN_ETSI5 = 0xf0000200,
|
||||
DMN_ETSI6 = 0xf0000400,
|
||||
DMN_ETSIA = 0xf0000800,
|
||||
DMN_ETSIB = 0xf0001000,
|
||||
DMN_ETSIC = 0xf0002000,
|
||||
DMN_FCC1 = 0xf0004000,
|
||||
DMN_FCC2 = 0xf0008000,
|
||||
DMN_FCC3 = 0xf0010000,
|
||||
DMN_FCCA = 0xf0020000,
|
||||
DMN_APLD = 0xf0040000,
|
||||
DMN_MKK1 = 0xf0080000,
|
||||
DMN_MKK2 = 0xf0100000,
|
||||
DMN_MKKA = 0xf0200000,
|
||||
DMN_NULL = 0xf0400000,
|
||||
DMN_WORLD = 0xf0800000,
|
||||
DMN_DEBUG = 0xf1000000 /* used for debugging */
|
||||
};
|
||||
|
||||
#define IEEE80211_DMN(_d) ((_d) & ~0xf0000000)
|
||||
|
||||
enum ath5k_countrycode {
|
||||
CTRY_DEFAULT = 0, /* Default domain (NA) */
|
||||
CTRY_ALBANIA = 8, /* Albania */
|
||||
CTRY_ALGERIA = 12, /* Algeria */
|
||||
CTRY_ARGENTINA = 32, /* Argentina */
|
||||
CTRY_ARMENIA = 51, /* Armenia */
|
||||
CTRY_AUSTRALIA = 36, /* Australia */
|
||||
CTRY_AUSTRIA = 40, /* Austria */
|
||||
CTRY_AZERBAIJAN = 31, /* Azerbaijan */
|
||||
CTRY_BAHRAIN = 48, /* Bahrain */
|
||||
CTRY_BELARUS = 112, /* Belarus */
|
||||
CTRY_BELGIUM = 56, /* Belgium */
|
||||
CTRY_BELIZE = 84, /* Belize */
|
||||
CTRY_BOLIVIA = 68, /* Bolivia */
|
||||
CTRY_BRAZIL = 76, /* Brazil */
|
||||
CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */
|
||||
CTRY_BULGARIA = 100, /* Bulgaria */
|
||||
CTRY_CANADA = 124, /* Canada */
|
||||
CTRY_CHILE = 152, /* Chile */
|
||||
CTRY_CHINA = 156, /* People's Republic of China */
|
||||
CTRY_COLOMBIA = 170, /* Colombia */
|
||||
CTRY_COSTA_RICA = 188, /* Costa Rica */
|
||||
CTRY_CROATIA = 191, /* Croatia */
|
||||
CTRY_CYPRUS = 196, /* Cyprus */
|
||||
CTRY_CZECH = 203, /* Czech Republic */
|
||||
CTRY_DENMARK = 208, /* Denmark */
|
||||
CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */
|
||||
CTRY_ECUADOR = 218, /* Ecuador */
|
||||
CTRY_EGYPT = 818, /* Egypt */
|
||||
CTRY_EL_SALVADOR = 222, /* El Salvador */
|
||||
CTRY_ESTONIA = 233, /* Estonia */
|
||||
CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */
|
||||
CTRY_FINLAND = 246, /* Finland */
|
||||
CTRY_FRANCE = 250, /* France */
|
||||
CTRY_FRANCE2 = 255, /* France2 */
|
||||
CTRY_GEORGIA = 268, /* Georgia */
|
||||
CTRY_GERMANY = 276, /* Germany */
|
||||
CTRY_GREECE = 300, /* Greece */
|
||||
CTRY_GUATEMALA = 320, /* Guatemala */
|
||||
CTRY_HONDURAS = 340, /* Honduras */
|
||||
CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */
|
||||
CTRY_HUNGARY = 348, /* Hungary */
|
||||
CTRY_ICELAND = 352, /* Iceland */
|
||||
CTRY_INDIA = 356, /* India */
|
||||
CTRY_INDONESIA = 360, /* Indonesia */
|
||||
CTRY_IRAN = 364, /* Iran */
|
||||
CTRY_IRAQ = 368, /* Iraq */
|
||||
CTRY_IRELAND = 372, /* Ireland */
|
||||
CTRY_ISRAEL = 376, /* Israel */
|
||||
CTRY_ITALY = 380, /* Italy */
|
||||
CTRY_JAMAICA = 388, /* Jamaica */
|
||||
CTRY_JAPAN = 392, /* Japan */
|
||||
CTRY_JAPAN1 = 393, /* Japan (JP1) */
|
||||
CTRY_JAPAN2 = 394, /* Japan (JP0) */
|
||||
CTRY_JAPAN3 = 395, /* Japan (JP1-1) */
|
||||
CTRY_JAPAN4 = 396, /* Japan (JE1) */
|
||||
CTRY_JAPAN5 = 397, /* Japan (JE2) */
|
||||
CTRY_JORDAN = 400, /* Jordan */
|
||||
CTRY_KAZAKHSTAN = 398, /* Kazakhstan */
|
||||
CTRY_KENYA = 404, /* Kenya */
|
||||
CTRY_KOREA_NORTH = 408, /* North Korea */
|
||||
CTRY_KOREA_ROC = 410, /* South Korea */
|
||||
CTRY_KOREA_ROC2 = 411, /* South Korea */
|
||||
CTRY_KUWAIT = 414, /* Kuwait */
|
||||
CTRY_LATVIA = 428, /* Latvia */
|
||||
CTRY_LEBANON = 422, /* Lebanon */
|
||||
CTRY_LIBYA = 434, /* Libya */
|
||||
CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */
|
||||
CTRY_LITHUANIA = 440, /* Lithuania */
|
||||
CTRY_LUXEMBOURG = 442, /* Luxembourg */
|
||||
CTRY_MACAU = 446, /* Macau */
|
||||
CTRY_MACEDONIA = 807, /* Republic of Macedonia */
|
||||
CTRY_MALAYSIA = 458, /* Malaysia */
|
||||
CTRY_MEXICO = 484, /* Mexico */
|
||||
CTRY_MONACO = 492, /* Principality of Monaco */
|
||||
CTRY_MOROCCO = 504, /* Morocco */
|
||||
CTRY_NETHERLANDS = 528, /* Netherlands */
|
||||
CTRY_NEW_ZEALAND = 554, /* New Zealand */
|
||||
CTRY_NICARAGUA = 558, /* Nicaragua */
|
||||
CTRY_NORWAY = 578, /* Norway */
|
||||
CTRY_OMAN = 512, /* Oman */
|
||||
CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */
|
||||
CTRY_PANAMA = 591, /* Panama */
|
||||
CTRY_PARAGUAY = 600, /* Paraguay */
|
||||
CTRY_PERU = 604, /* Peru */
|
||||
CTRY_PHILIPPINES = 608, /* Republic of the Philippines */
|
||||
CTRY_POLAND = 616, /* Poland */
|
||||
CTRY_PORTUGAL = 620, /* Portugal */
|
||||
CTRY_PUERTO_RICO = 630, /* Puerto Rico */
|
||||
CTRY_QATAR = 634, /* Qatar */
|
||||
CTRY_ROMANIA = 642, /* Romania */
|
||||
CTRY_RUSSIA = 643, /* Russia */
|
||||
CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */
|
||||
CTRY_SINGAPORE = 702, /* Singapore */
|
||||
CTRY_SLOVAKIA = 703, /* Slovak Republic */
|
||||
CTRY_SLOVENIA = 705, /* Slovenia */
|
||||
CTRY_SOUTH_AFRICA = 710, /* South Africa */
|
||||
CTRY_SPAIN = 724, /* Spain */
|
||||
CTRY_SRI_LANKA = 728, /* Sri Lanka */
|
||||
CTRY_SWEDEN = 752, /* Sweden */
|
||||
CTRY_SWITZERLAND = 756, /* Switzerland */
|
||||
CTRY_SYRIA = 760, /* Syria */
|
||||
CTRY_TAIWAN = 158, /* Taiwan */
|
||||
CTRY_THAILAND = 764, /* Thailand */
|
||||
CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */
|
||||
CTRY_TUNISIA = 788, /* Tunisia */
|
||||
CTRY_TURKEY = 792, /* Turkey */
|
||||
CTRY_UAE = 784, /* U.A.E. */
|
||||
CTRY_UKRAINE = 804, /* Ukraine */
|
||||
CTRY_UNITED_KINGDOM = 826, /* United Kingdom */
|
||||
CTRY_UNITED_STATES = 840, /* United States */
|
||||
CTRY_URUGUAY = 858, /* Uruguay */
|
||||
CTRY_UZBEKISTAN = 860, /* Uzbekistan */
|
||||
CTRY_VENEZUELA = 862, /* Venezuela */
|
||||
CTRY_VIET_NAM = 704, /* Viet Nam */
|
||||
CTRY_YEMEN = 887, /* Yemen */
|
||||
CTRY_ZIMBABWE = 716, /* Zimbabwe */
|
||||
};
|
||||
|
||||
#define IEEE80211_CHANNELS_2GHZ_MIN 2412 /* 2GHz channel 1 */
|
||||
#define IEEE80211_CHANNELS_2GHZ_MAX 2732 /* 2GHz channel 26 */
|
||||
#define IEEE80211_CHANNELS_5GHZ_MIN 5005 /* 5GHz channel 1 */
|
||||
#define IEEE80211_CHANNELS_5GHZ_MAX 6100 /* 5GHz channel 220 */
|
||||
|
||||
struct ath5k_regchannel {
|
||||
u16 chan;
|
||||
enum ath5k_regdom domain;
|
||||
u32 mode;
|
||||
};
|
||||
|
||||
#define IEEE80211_CHANNELS_2GHZ { \
|
||||
/*2412*/ { 1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2417*/ { 2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2422*/ { 3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2427*/ { 4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2432*/ { 5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2442*/ { 7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2447*/ { 8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2452*/ { 9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2457*/ { 10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2462*/ { 11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2467*/ { 12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2472*/ { 13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
\
|
||||
/*2432*/ { 5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*2442*/ { 7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
\
|
||||
/*2412*/ { 1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2417*/ { 2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2422*/ { 3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2427*/ { 4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2432*/ { 5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*2442*/ { 7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2447*/ { 8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2452*/ { 9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2457*/ { 10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2462*/ { 11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2467*/ { 12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2472*/ { 13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
\
|
||||
/*2412*/ { 1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2417*/ { 2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2422*/ { 3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2427*/ { 4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2432*/ { 5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*2442*/ { 7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2447*/ { 8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2452*/ { 9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2457*/ { 10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2462*/ { 11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
\
|
||||
/*2412*/ { 1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2417*/ { 2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2422*/ { 3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2427*/ { 4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2432*/ { 5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2442*/ { 7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2447*/ { 8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2452*/ { 9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2457*/ { 10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2462*/ { 11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2467*/ { 12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2472*/ { 13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2484*/ { 14, DMN_MKKA, CHANNEL_CCK }, \
|
||||
\
|
||||
/*2412*/ { 1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2417*/ { 2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2422*/ { 3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2427*/ { 4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2432*/ { 5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2437*/ { 6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*2442*/ { 7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2447*/ { 8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2452*/ { 9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2457*/ { 10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2462*/ { 11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2467*/ { 12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
/*2472*/ { 13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \
|
||||
}
|
||||
|
||||
#define IEEE80211_CHANNELS_5GHZ { \
|
||||
/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5280*/ { 56, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5300*/ { 60, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5260*/ { 52, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5300*/ { 60, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI2, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI2, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI2, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI2, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5260*/ { 52, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5300*/ { 60, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_ETSI3, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5260*/ { 52, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5300*/ { 60, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_ETSI4, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI5, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI5, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI5, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI5, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5260*/ { 52, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5210*/ { 42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5220*/ { 44, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5250*/ { 50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5260*/ { 52, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5290*/ { 58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5300*/ { 60, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5260*/ { 52, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5300*/ { 60, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5210*/ { 42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5220*/ { 44, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5250*/ { 50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5260*/ { 52, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5280*/ { 56, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5290*/ { 58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5300*/ { 60, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5320*/ { 64, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \
|
||||
/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5170*/ { 34, DMN_MKK1, CHANNEL_OFDM }, \
|
||||
/*5190*/ { 38, DMN_MKK1, CHANNEL_OFDM }, \
|
||||
/*5210*/ { 42, DMN_MKK1, CHANNEL_OFDM }, \
|
||||
/*5230*/ { 46, DMN_MKK1, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5040*/ { 8, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5060*/ { 12, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5080*/ { 16, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5170*/ { 34, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5190*/ { 38, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5210*/ { 42, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
/*5230*/ { 46, DMN_MKK2, CHANNEL_OFDM }, \
|
||||
\
|
||||
/*5180*/ { 36, DMN_WORLD, CHANNEL_OFDM }, \
|
||||
/*5200*/ { 40, DMN_WORLD, CHANNEL_OFDM }, \
|
||||
/*5220*/ { 44, DMN_WORLD, CHANNEL_OFDM }, \
|
||||
/*5240*/ { 48, DMN_WORLD, CHANNEL_OFDM }, \
|
||||
}
|
||||
|
||||
enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16);
|
||||
u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee);
|
||||
enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain);
|
||||
|
||||
#endif
|
@ -2343,6 +2343,13 @@ static void b43_mac_suspend(struct b43_wldev *dev)
|
||||
& ~B43_MACCTL_ENABLED);
|
||||
/* force pci to flush the write */
|
||||
b43_read32(dev, B43_MMIO_MACCTL);
|
||||
for (i = 35; i; i--) {
|
||||
tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
|
||||
if (tmp & B43_IRQ_MAC_SUSPENDED)
|
||||
goto out;
|
||||
udelay(10);
|
||||
}
|
||||
/* Hm, it seems this will take some time. Use msleep(). */
|
||||
for (i = 40; i; i--) {
|
||||
tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
|
||||
if (tmp & B43_IRQ_MAC_SUSPENDED)
|
||||
|
@ -97,6 +97,7 @@
|
||||
#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A
|
||||
#define B43legacy_MMIO_GPIO_CONTROL 0x49C
|
||||
#define B43legacy_MMIO_GPIO_MASK 0x49E
|
||||
#define B43legacy_MMIO_TSF_CFP_PRETBTT 0x612
|
||||
#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */
|
||||
#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */
|
||||
#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */
|
||||
@ -149,6 +150,8 @@
|
||||
#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
|
||||
#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
|
||||
#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */
|
||||
#define B43legacy_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
|
||||
#define B43legacy_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
|
||||
|
||||
#define B43legacy_UCODEFLAGS_OFFSET 0x005E
|
||||
|
||||
|
@ -3005,6 +3005,34 @@ static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
|
||||
}
|
||||
|
||||
static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
|
||||
bool idle) {
|
||||
u16 pu_delay = 1050;
|
||||
|
||||
if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
|
||||
pu_delay = 500;
|
||||
if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
|
||||
pu_delay = max(pu_delay, (u16)2400);
|
||||
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
|
||||
B43legacy_SHM_SH_SPUWKUP, pu_delay);
|
||||
}
|
||||
|
||||
/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */
|
||||
static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev)
|
||||
{
|
||||
u16 pretbtt;
|
||||
|
||||
/* The time value is in microseconds. */
|
||||
if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
|
||||
pretbtt = 2;
|
||||
else
|
||||
pretbtt = 250;
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
|
||||
B43legacy_SHM_SH_PRETBTT, pretbtt);
|
||||
b43legacy_write16(dev, B43legacy_MMIO_TSF_CFP_PRETBTT, pretbtt);
|
||||
}
|
||||
|
||||
/* Shutdown a wireless core */
|
||||
/* Locking: wl->mutex */
|
||||
static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
|
||||
@ -3191,9 +3219,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
|
||||
if (err)
|
||||
goto err_chip_exit;
|
||||
|
||||
b43legacy_write16(dev, 0x0612, 0x0050);
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
|
||||
b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
|
||||
b43legacy_set_synth_pu_delay(dev, 1);
|
||||
|
||||
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
|
||||
b43legacy_upload_card_macaddress(dev);
|
||||
@ -3249,6 +3275,8 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
|
||||
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
b43legacy_adjust_opmode(dev);
|
||||
b43legacy_set_pretbtt(dev);
|
||||
b43legacy_set_synth_pu_delay(dev, 0);
|
||||
b43legacy_upload_card_macaddress(dev);
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
|
||||
|
@ -6,7 +6,7 @@ config IWLWIFI_LEDS
|
||||
bool
|
||||
default n
|
||||
|
||||
config IWLCORE_RFKILL
|
||||
config IWLWIFI_RFKILL
|
||||
boolean "IWLWIFI RF kill support"
|
||||
depends on IWLCORE
|
||||
select RFKILL
|
||||
|
@ -1,26 +1,13 @@
|
||||
obj-$(CONFIG_IWLCORE) += iwlcore.o
|
||||
iwlcore-objs = iwl-core.o iwl-eeprom.o iwl-hcmd.o
|
||||
|
||||
ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y)
|
||||
iwlcore-objs += iwl-debugfs.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_IWLWIFI_LEDS),y)
|
||||
iwlcore-objs += iwl-led.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_IWLCORE_RFKILL),y)
|
||||
iwlcore-objs += iwl-rfkill.o
|
||||
endif
|
||||
obj-$(CONFIG_IWLCORE) := iwlcore.o
|
||||
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o
|
||||
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
|
||||
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
|
||||
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
|
||||
|
||||
obj-$(CONFIG_IWL3945) += iwl3945.o
|
||||
iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
|
||||
|
||||
ifeq ($(CONFIG_IWL3945_LEDS),y)
|
||||
iwl3945-objs += iwl-3945-led.o
|
||||
endif
|
||||
|
||||
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
|
||||
iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
|
||||
|
||||
obj-$(CONFIG_IWL4965) += iwl4965.o
|
||||
iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o
|
||||
iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
|
||||
|
||||
|
@ -456,7 +456,7 @@ struct iwl3945_eeprom {
|
||||
/* Size of uCode instruction memory in bootstrap state machine */
|
||||
#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
|
||||
|
||||
#define IWL_MAX_NUM_QUEUES 8
|
||||
#define IWL39_MAX_NUM_QUEUES 8
|
||||
|
||||
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
|
||||
{
|
||||
|
@ -687,6 +687,8 @@ enum {
|
||||
|
||||
#endif
|
||||
|
||||
#define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES
|
||||
|
||||
struct iwl3945_priv {
|
||||
|
||||
/* ieee device used by generic ieee processing code */
|
||||
|
@ -84,6 +84,9 @@ enum {
|
||||
REPLY_REMOVE_STA = 0x19, /* not used */
|
||||
REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
|
||||
|
||||
/* Security */
|
||||
REPLY_WEPKEY = 0x20,
|
||||
|
||||
/* RX, TX, LEDs */
|
||||
REPLY_TX = 0x1c,
|
||||
REPLY_RATE_SCALE = 0x47, /* 3945 only */
|
||||
@ -266,11 +269,10 @@ struct iwl_cmd_header {
|
||||
* 10 B active, A inactive
|
||||
* 11 Both active
|
||||
*/
|
||||
#define RATE_MCS_ANT_A_POS 14
|
||||
#define RATE_MCS_ANT_B_POS 15
|
||||
#define RATE_MCS_ANT_A_MSK 0x4000
|
||||
#define RATE_MCS_ANT_B_MSK 0x8000
|
||||
#define RATE_MCS_ANT_AB_MSK 0xc000
|
||||
#define RATE_MCS_ANT_POS 14
|
||||
#define RATE_MCS_ANT_A_MSK 0x04000
|
||||
#define RATE_MCS_ANT_B_MSK 0x08000
|
||||
#define RATE_MCS_ANT_AB_MSK 0x0C000
|
||||
|
||||
|
||||
/**
|
||||
@ -850,6 +852,30 @@ struct iwl4965_add_sta_resp {
|
||||
u8 status; /* ADD_STA_* */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* REPLY_WEP_KEY = 0x20
|
||||
*/
|
||||
struct iwl_wep_key {
|
||||
u8 key_index;
|
||||
u8 key_offset;
|
||||
u8 reserved1[2];
|
||||
u8 key_size;
|
||||
u8 reserved2[3];
|
||||
u8 key[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct iwl_wep_cmd {
|
||||
u8 num_keys;
|
||||
u8 global_key_type;
|
||||
u8 flags;
|
||||
u8 reserved;
|
||||
struct iwl_wep_key key[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define WEP_KEY_WEP_TYPE 1
|
||||
#define WEP_KEYS_MAX 4
|
||||
#define WEP_INVALID_OFFSET 0xff
|
||||
#define WEP_KEY_LEN_128 13
|
||||
|
||||
/******************************************************************************
|
||||
* (4)
|
||||
@ -1387,11 +1413,11 @@ struct iwl4965_txpowertable_cmd {
|
||||
|
||||
|
||||
/**
|
||||
* struct iwl4965_link_qual_general_params
|
||||
* struct iwl_link_qual_general_params
|
||||
*
|
||||
* Used in REPLY_TX_LINK_QUALITY_CMD
|
||||
*/
|
||||
struct iwl4965_link_qual_general_params {
|
||||
struct iwl_link_qual_general_params {
|
||||
u8 flags;
|
||||
|
||||
/* No entries at or above this (driver chosen) index contain MIMO */
|
||||
@ -1418,11 +1444,11 @@ struct iwl4965_link_qual_general_params {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct iwl4965_link_qual_agg_params
|
||||
* struct iwl_link_qual_agg_params
|
||||
*
|
||||
* Used in REPLY_TX_LINK_QUALITY_CMD
|
||||
*/
|
||||
struct iwl4965_link_qual_agg_params {
|
||||
struct iwl_link_qual_agg_params {
|
||||
|
||||
/* Maximum number of uSec in aggregation.
|
||||
* Driver should set this to 4000 (4 milliseconds). */
|
||||
@ -1632,14 +1658,14 @@ struct iwl4965_link_qual_agg_params {
|
||||
* legacy), and then repeat the search process.
|
||||
*
|
||||
*/
|
||||
struct iwl4965_link_quality_cmd {
|
||||
struct iwl_link_quality_cmd {
|
||||
|
||||
/* Index of destination/recipient station in uCode's station table */
|
||||
u8 sta_id;
|
||||
u8 reserved1;
|
||||
__le16 control; /* not used */
|
||||
struct iwl4965_link_qual_general_params general_params;
|
||||
struct iwl4965_link_qual_agg_params agg_params;
|
||||
struct iwl_link_qual_general_params general_params;
|
||||
struct iwl_link_qual_agg_params agg_params;
|
||||
|
||||
/*
|
||||
* Rate info; when using rate-scaling, Tx command's initial_rate_index
|
||||
|
@ -1385,10 +1385,10 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
|
||||
* up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array
|
||||
* in DRAM containing 256 Transmit Frame Descriptors (TFDs).
|
||||
*/
|
||||
#define IWL4965_MAX_WIN_SIZE 64
|
||||
#define IWL4965_QUEUE_SIZE 256
|
||||
#define IWL4965_NUM_FIFOS 7
|
||||
#define IWL_MAX_NUM_QUEUES 16
|
||||
#define IWL4965_MAX_WIN_SIZE 64
|
||||
#define IWL4965_QUEUE_SIZE 256
|
||||
#define IWL4965_NUM_FIFOS 7
|
||||
#define IWL4965_MAX_NUM_QUEUES 16
|
||||
|
||||
|
||||
/**
|
||||
@ -1553,30 +1553,30 @@ struct iwl4965_sched_queue_byte_cnt_tbl {
|
||||
*/
|
||||
struct iwl4965_shared {
|
||||
struct iwl4965_sched_queue_byte_cnt_tbl
|
||||
queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
|
||||
__le32 val0;
|
||||
queues_byte_cnt_tbls[IWL4965_MAX_NUM_QUEUES];
|
||||
__le32 rb_closed;
|
||||
|
||||
/* __le32 rb_closed_stts_rb_num:12; */
|
||||
#define IWL_rb_closed_stts_rb_num_POS 0
|
||||
#define IWL_rb_closed_stts_rb_num_LEN 12
|
||||
#define IWL_rb_closed_stts_rb_num_SYM val0
|
||||
#define IWL_rb_closed_stts_rb_num_SYM rb_closed
|
||||
/* __le32 rsrv1:4; */
|
||||
/* __le32 rb_closed_stts_rx_frame_num:12; */
|
||||
#define IWL_rb_closed_stts_rx_frame_num_POS 16
|
||||
#define IWL_rb_closed_stts_rx_frame_num_LEN 12
|
||||
#define IWL_rb_closed_stts_rx_frame_num_SYM val0
|
||||
#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
|
||||
/* __le32 rsrv2:4; */
|
||||
|
||||
__le32 val1;
|
||||
__le32 frm_finished;
|
||||
/* __le32 frame_finished_stts_rb_num:12; */
|
||||
#define IWL_frame_finished_stts_rb_num_POS 0
|
||||
#define IWL_frame_finished_stts_rb_num_LEN 12
|
||||
#define IWL_frame_finished_stts_rb_num_SYM val1
|
||||
#define IWL_frame_finished_stts_rb_num_SYM frm_finished
|
||||
/* __le32 rsrv3:4; */
|
||||
/* __le32 frame_finished_stts_rx_frame_num:12; */
|
||||
#define IWL_frame_finished_stts_rx_frame_num_POS 16
|
||||
#define IWL_frame_finished_stts_rx_frame_num_LEN 12
|
||||
#define IWL_frame_finished_stts_rx_frame_num_SYM val1
|
||||
#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
|
||||
/* __le32 rsrv4:4; */
|
||||
|
||||
__le32 padding1; /* so that allocation will be aligned to 16B */
|
||||
|
@ -150,7 +150,7 @@ struct iwl4965_lq_sta {
|
||||
u16 active_mimo_rate;
|
||||
u16 active_rate_basic;
|
||||
|
||||
struct iwl4965_link_quality_cmd lq;
|
||||
struct iwl_link_quality_cmd lq;
|
||||
struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
|
||||
#ifdef CONFIG_IWL4965_HT
|
||||
struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT];
|
||||
@ -173,7 +173,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
struct sta_info *sta);
|
||||
static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
|
||||
struct iwl4965_rate *tx_mcs,
|
||||
struct iwl4965_link_quality_cmd *tbl);
|
||||
struct iwl_link_quality_cmd *tbl);
|
||||
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
@ -230,58 +230,11 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
|
||||
0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
|
||||
};
|
||||
|
||||
static int iwl4965_lq_sync_callback(struct iwl_priv *priv,
|
||||
struct iwl_cmd *cmd, struct sk_buff *skb)
|
||||
{
|
||||
/*We didn't cache the SKB; let the caller free it */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
|
||||
{
|
||||
return (u8)(rate_n_flags & 0xFF);
|
||||
}
|
||||
|
||||
static int rs_send_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl4965_link_quality_cmd *lq, u8 flags)
|
||||
{
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
int i;
|
||||
#endif
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_TX_LINK_QUALITY_CMD,
|
||||
.len = sizeof(struct iwl4965_link_quality_cmd),
|
||||
.meta.flags = flags,
|
||||
.data = lq,
|
||||
};
|
||||
|
||||
if ((lq->sta_id == 0xFF) &&
|
||||
(priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
|
||||
return -EINVAL;
|
||||
|
||||
if (lq->sta_id == 0xFF)
|
||||
lq->sta_id = IWL_AP_ID;
|
||||
|
||||
IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
|
||||
IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
|
||||
lq->general_params.single_stream_ant_msk,
|
||||
lq->general_params.dual_stream_ant_msk);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
IWL_DEBUG_RATE("lq index %d 0x%X\n",
|
||||
i, lq->rs_table[i].rate_n_flags);
|
||||
#endif
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
cmd.meta.u.callback = iwl4965_lq_sync_callback;
|
||||
|
||||
if (iwl_is_associated(priv) && priv->assoc_station_added &&
|
||||
priv->lq_mngr.lq_ready)
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
|
||||
{
|
||||
window->data = 0;
|
||||
@ -819,7 +772,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
|
||||
u8 retries;
|
||||
int rs_index, index = 0;
|
||||
struct iwl4965_lq_sta *lq_sta;
|
||||
struct iwl4965_link_quality_cmd *table;
|
||||
struct iwl_link_quality_cmd *table;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
|
||||
@ -1879,7 +1832,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
if (update_lq) {
|
||||
rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
|
||||
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
|
||||
rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
}
|
||||
goto out;
|
||||
|
||||
@ -2044,7 +1997,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
if (update_lq) {
|
||||
rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
|
||||
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
|
||||
rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
}
|
||||
|
||||
/* Should we stay with this modulation mode, or search for a new one? */
|
||||
@ -2084,7 +2037,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
tbl->current_rate.rate_n_flags, index);
|
||||
rs_fill_link_cmd(lq_sta, &tbl->current_rate,
|
||||
&lq_sta->lq);
|
||||
rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
}
|
||||
|
||||
/* If the "active" (non-search) mode was legacy,
|
||||
@ -2197,7 +2150,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
|
||||
tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
|
||||
rs_get_expected_tpt_table(lq_sta, tbl);
|
||||
rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
|
||||
rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@ -2392,7 +2345,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
|
||||
|
||||
static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
|
||||
struct iwl4965_rate *tx_mcs,
|
||||
struct iwl4965_link_quality_cmd *lq_cmd)
|
||||
struct iwl_link_quality_cmd *lq_cmd)
|
||||
{
|
||||
int index = 0;
|
||||
int rate_idx;
|
||||
@ -2591,7 +2544,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
|
||||
|
||||
if (lq_sta->dbg_fixed.rate_n_flags) {
|
||||
rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq);
|
||||
rs_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
|
||||
iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
/* module parameters */
|
||||
static struct iwl_mod_params iwl4965_mod_params = {
|
||||
.num_of_queues = IWL_MAX_NUM_QUEUES,
|
||||
.num_of_queues = IWL4965_MAX_NUM_QUEUES,
|
||||
.enable_qos = 1,
|
||||
.amsdu_size_8K = 1,
|
||||
/* the rest are 0 by default */
|
||||
@ -114,6 +114,151 @@ static const u16 default_tid_to_tx_fifo[] = {
|
||||
|
||||
#endif /*CONFIG_IWL4965_HT */
|
||||
|
||||
/* check contents of special bootstrap uCode SRAM */
|
||||
static int iwl4965_verify_bsm(struct iwl_priv *priv)
|
||||
{
|
||||
__le32 *image = priv->ucode_boot.v_addr;
|
||||
u32 len = priv->ucode_boot.len;
|
||||
u32 reg;
|
||||
u32 val;
|
||||
|
||||
IWL_DEBUG_INFO("Begin verify bsm\n");
|
||||
|
||||
/* verify BSM SRAM contents */
|
||||
val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
|
||||
for (reg = BSM_SRAM_LOWER_BOUND;
|
||||
reg < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg += sizeof(u32), image++) {
|
||||
val = iwl_read_prph(priv, reg);
|
||||
if (val != le32_to_cpu(*image)) {
|
||||
IWL_ERROR("BSM uCode verification failed at "
|
||||
"addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
|
||||
BSM_SRAM_LOWER_BOUND,
|
||||
reg - BSM_SRAM_LOWER_BOUND, len,
|
||||
val, le32_to_cpu(*image));
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_load_bsm - Load bootstrap instructions
|
||||
*
|
||||
* BSM operation:
|
||||
*
|
||||
* The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
|
||||
* in special SRAM that does not power down during RFKILL. When powering back
|
||||
* up after power-saving sleeps (or during initial uCode load), the BSM loads
|
||||
* the bootstrap program into the on-board processor, and starts it.
|
||||
*
|
||||
* The bootstrap program loads (via DMA) instructions and data for a new
|
||||
* program from host DRAM locations indicated by the host driver in the
|
||||
* BSM_DRAM_* registers. Once the new program is loaded, it starts
|
||||
* automatically.
|
||||
*
|
||||
* When initializing the NIC, the host driver points the BSM to the
|
||||
* "initialize" uCode image. This uCode sets up some internal data, then
|
||||
* notifies host via "initialize alive" that it is complete.
|
||||
*
|
||||
* The host then replaces the BSM_DRAM_* pointer values to point to the
|
||||
* normal runtime uCode instructions and a backup uCode data cache buffer
|
||||
* (filled initially with starting data values for the on-board processor),
|
||||
* then triggers the "initialize" uCode to load and launch the runtime uCode,
|
||||
* which begins normal operation.
|
||||
*
|
||||
* When doing a power-save shutdown, runtime uCode saves data SRAM into
|
||||
* the backup data cache in DRAM before SRAM is powered down.
|
||||
*
|
||||
* When powering back up, the BSM loads the bootstrap program. This reloads
|
||||
* the runtime uCode instructions and the backup data cache into SRAM,
|
||||
* and re-launches the runtime uCode from where it left off.
|
||||
*/
|
||||
static int iwl4965_load_bsm(struct iwl_priv *priv)
|
||||
{
|
||||
__le32 *image = priv->ucode_boot.v_addr;
|
||||
u32 len = priv->ucode_boot.len;
|
||||
dma_addr_t pinst;
|
||||
dma_addr_t pdata;
|
||||
u32 inst_len;
|
||||
u32 data_len;
|
||||
int i;
|
||||
u32 done;
|
||||
u32 reg_offset;
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_INFO("Begin load bsm\n");
|
||||
|
||||
/* make sure bootstrap program is no larger than BSM's SRAM size */
|
||||
if (len > IWL_MAX_BSM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/* Tell bootstrap uCode where to find the "Initialize" uCode
|
||||
* in host DRAM ... host DRAM physical address bits 35:4 for 4965.
|
||||
* NOTE: iwl4965_initialize_alive_start() will replace these values,
|
||||
* after the "initialize" uCode has run, to point to
|
||||
* runtime/protocol instructions and backup data cache. */
|
||||
pinst = priv->ucode_init.p_addr >> 4;
|
||||
pdata = priv->ucode_init_data.p_addr >> 4;
|
||||
inst_len = priv->ucode_init.len;
|
||||
data_len = priv->ucode_init_data.len;
|
||||
|
||||
ret = iwl_grab_nic_access(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
|
||||
|
||||
/* Fill BSM memory with bootstrap instructions */
|
||||
for (reg_offset = BSM_SRAM_LOWER_BOUND;
|
||||
reg_offset < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg_offset += sizeof(u32), image++)
|
||||
_iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));
|
||||
|
||||
ret = iwl4965_verify_bsm(priv);
|
||||
if (ret) {
|
||||
iwl_release_nic_access(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
|
||||
iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
|
||||
iwl_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
|
||||
iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
|
||||
|
||||
/* Load bootstrap code into instruction SRAM now,
|
||||
* to prepare to load "initialize" uCode */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
|
||||
|
||||
/* Wait for load of bootstrap uCode to finish */
|
||||
for (i = 0; i < 100; i++) {
|
||||
done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
|
||||
if (!(done & BSM_WR_CTRL_REG_BIT_START))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (i < 100)
|
||||
IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
|
||||
else {
|
||||
IWL_ERROR("BSM write did not complete!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Enable future boot loads whenever power management unit triggers it
|
||||
* (e.g. when powering back up after power-save shutdown) */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
|
||||
|
||||
iwl_release_nic_access(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl4965_init_drv(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@ -129,6 +274,18 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
|
||||
spin_lock_init(&priv->hcmd_lock);
|
||||
spin_lock_init(&priv->lq_mngr.lock);
|
||||
|
||||
priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
|
||||
sizeof(struct iwl4965_shared),
|
||||
&priv->shared_phys);
|
||||
|
||||
if (!priv->shared_virt) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
|
||||
|
||||
|
||||
for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
|
||||
INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
|
||||
|
||||
@ -253,7 +410,7 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
|
||||
int rate_index;
|
||||
|
||||
control->antenna_sel_tx =
|
||||
((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_A_POS);
|
||||
((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
|
||||
if (rate_n_flags & RATE_MCS_HT_MSK)
|
||||
control->flags |= IEEE80211_TXCTL_OFDM_HT;
|
||||
if (rate_n_flags & RATE_MCS_GF_MSK)
|
||||
@ -347,10 +504,10 @@ u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr)
|
||||
start = IWL_STA_ID;
|
||||
|
||||
if (is_broadcast_ether_addr(addr))
|
||||
return priv->hw_setting.bcast_sta_id;
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
for (i = start; i < priv->hw_setting.max_stations; i++)
|
||||
for (i = start; i < priv->hw_params.max_stations; i++)
|
||||
if ((priv->stations[i].used) &&
|
||||
(!compare_ether_addr
|
||||
(priv->stations[i].sta.sta.addr, addr))) {
|
||||
@ -401,15 +558,15 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
|
||||
|
||||
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
|
||||
{
|
||||
int rc;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned int rb_size;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
rc = iwl_grab_nic_access(priv);
|
||||
if (rc) {
|
||||
ret = iwl_grab_nic_access(priv);
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
return rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->cfg->mod_params->amsdu_size_8K)
|
||||
@ -429,15 +586,15 @@ static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
|
||||
|
||||
/* Tell device where in DRAM to update its Rx status */
|
||||
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||||
(priv->hw_setting.shared_phys +
|
||||
offsetof(struct iwl4965_shared, val0)) >> 4);
|
||||
(priv->shared_phys +
|
||||
offsetof(struct iwl4965_shared, rb_closed)) >> 4);
|
||||
|
||||
/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
|
||||
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
|
||||
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
|
||||
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
|
||||
rb_size |
|
||||
/*0x10 << 4 | */
|
||||
/* 0x10 << 4 | */
|
||||
(RX_QUEUE_SIZE_LOG <<
|
||||
FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
|
||||
|
||||
@ -545,7 +702,7 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
|
||||
|
||||
/* Alloc and init all (default 16) Tx queues,
|
||||
* including the command queue (#4) */
|
||||
for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
|
||||
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
|
||||
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
|
||||
rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
|
||||
@ -751,7 +908,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
|
||||
unsigned long flags;
|
||||
|
||||
/* Stop each Tx DMA channel, and wait for it to be idle */
|
||||
for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (iwl_grab_nic_access(priv)) {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
@ -819,40 +976,21 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv)
|
||||
/**
|
||||
* iwl4965_bg_statistics_periodic - Timer callback to queue statistics
|
||||
*
|
||||
* This callback is provided in order to queue the statistics_work
|
||||
* in work_queue context (v. softirq)
|
||||
* This callback is provided in order to send a statistics request.
|
||||
*
|
||||
* This timer function is continually reset to execute within
|
||||
* REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
|
||||
* was received. We need to ensure we receive the statistics in order
|
||||
* to update the temperature used for calibrating the TXPOWER. However,
|
||||
* we can't send the statistics command from softirq context (which
|
||||
* is the context which timers run at) so we have to queue off the
|
||||
* statistics_work to actually send the command to the hardware.
|
||||
* to update the temperature used for calibrating the TXPOWER.
|
||||
*/
|
||||
static void iwl4965_bg_statistics_periodic(unsigned long data)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)data;
|
||||
|
||||
queue_work(priv->workqueue, &priv->statistics_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_bg_statistics_work - Send the statistics request to the hardware.
|
||||
*
|
||||
* This is queued by iwl4965_bg_statistics_periodic.
|
||||
*/
|
||||
static void iwl4965_bg_statistics_work(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work, struct iwl_priv,
|
||||
statistics_work);
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl4965_send_statistics_request(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC);
|
||||
}
|
||||
|
||||
#define CT_LIMIT_CONST 259
|
||||
@ -1816,19 +1954,19 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
|
||||
iwl_write_targ_mem(priv, a, 0);
|
||||
for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
|
||||
iwl_write_targ_mem(priv, a, 0);
|
||||
for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
|
||||
for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
|
||||
iwl_write_targ_mem(priv, a, 0);
|
||||
|
||||
/* Tel 4965 where to find Tx byte count tables */
|
||||
iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
|
||||
(priv->hw_setting.shared_phys +
|
||||
(priv->shared_phys +
|
||||
offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
|
||||
|
||||
/* Disable chain mode for all queues */
|
||||
iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
|
||||
|
||||
/* Initialize each Tx queue (including the command queue) */
|
||||
for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
|
||||
for (i = 0; i < priv->hw_params.max_txq_num; i++) {
|
||||
|
||||
/* TFD circular buffer read/write indexes */
|
||||
iwl_write_prph(priv, IWL49_SCD_QUEUE_RDPTR(i), 0);
|
||||
@ -1851,7 +1989,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
|
||||
|
||||
}
|
||||
iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK,
|
||||
(1 << priv->hw_setting.max_txq_num) - 1);
|
||||
(1 << priv->hw_params.max_txq_num) - 1);
|
||||
|
||||
/* Activate all Tx DMA/FIFO channels */
|
||||
iwl_write_prph(priv, IWL49_SCD_TXFACT,
|
||||
@ -1869,55 +2007,45 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
|
||||
iwl_release_nic_access(priv);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Ask for statistics now, the uCode will send statistics notification
|
||||
* periodically after association */
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_hw_set_hw_setting
|
||||
* iwl4965_hw_set_hw_params
|
||||
*
|
||||
* Called when initializing driver
|
||||
*/
|
||||
int iwl4965_hw_set_hw_setting(struct iwl_priv *priv)
|
||||
int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if ((priv->cfg->mod_params->num_of_queues > IWL_MAX_NUM_QUEUES) ||
|
||||
if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) ||
|
||||
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
|
||||
IWL_ERROR("invalid queues_num, should be between %d and %d\n",
|
||||
IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allocate area for Tx byte count tables and Rx queue status */
|
||||
priv->hw_setting.shared_virt =
|
||||
pci_alloc_consistent(priv->pci_dev,
|
||||
sizeof(struct iwl4965_shared),
|
||||
&priv->hw_setting.shared_phys);
|
||||
|
||||
if (!priv->hw_setting.shared_virt) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared));
|
||||
|
||||
priv->hw_setting.max_txq_num = priv->cfg->mod_params->num_of_queues;
|
||||
priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
|
||||
priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
|
||||
priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
|
||||
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
|
||||
priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
|
||||
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
|
||||
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
|
||||
if (priv->cfg->mod_params->amsdu_size_8K)
|
||||
priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K;
|
||||
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
|
||||
else
|
||||
priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K;
|
||||
priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
|
||||
priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
|
||||
priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
|
||||
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
|
||||
priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
|
||||
priv->hw_params.max_stations = IWL4965_STATION_COUNT;
|
||||
priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
|
||||
|
||||
priv->hw_setting.tx_ant_num = 2;
|
||||
priv->hw_params.tx_chains_num = 2;
|
||||
priv->hw_params.rx_chains_num = 2;
|
||||
priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
|
||||
priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1930,7 +2058,7 @@ void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
|
||||
int txq_id;
|
||||
|
||||
/* Tx queues */
|
||||
for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
|
||||
iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
|
||||
|
||||
/* Keep-warm buffer */
|
||||
@ -2756,6 +2884,46 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct iwl4965_rxon_assoc_cmd rxon_assoc;
|
||||
const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
|
||||
const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
|
||||
|
||||
if ((rxon1->flags == rxon2->flags) &&
|
||||
(rxon1->filter_flags == rxon2->filter_flags) &&
|
||||
(rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
|
||||
(rxon1->ofdm_ht_single_stream_basic_rates ==
|
||||
rxon2->ofdm_ht_single_stream_basic_rates) &&
|
||||
(rxon1->ofdm_ht_dual_stream_basic_rates ==
|
||||
rxon2->ofdm_ht_dual_stream_basic_rates) &&
|
||||
(rxon1->rx_chain == rxon2->rx_chain) &&
|
||||
(rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
|
||||
IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rxon_assoc.flags = priv->staging_rxon.flags;
|
||||
rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
|
||||
rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
|
||||
rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
|
||||
rxon_assoc.reserved = 0;
|
||||
rxon_assoc.ofdm_ht_single_stream_basic_rates =
|
||||
priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
|
||||
rxon_assoc.ofdm_ht_dual_stream_basic_rates =
|
||||
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
|
||||
rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
|
||||
|
||||
ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
|
||||
sizeof(rxon_assoc), &rxon_assoc, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
|
||||
{
|
||||
int rc;
|
||||
@ -2869,9 +3037,8 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
|
||||
|
||||
int iwl4965_hw_get_rx_read(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
|
||||
|
||||
return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
|
||||
struct iwl4965_shared *s = priv->shared_virt;
|
||||
return le32_to_cpu(s->rb_closed) & 0xFFF;
|
||||
}
|
||||
|
||||
int iwl4965_hw_get_temperature(struct iwl_priv *priv)
|
||||
@ -2888,7 +3055,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
|
||||
tx_beacon_cmd = &frame->u.beacon;
|
||||
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
|
||||
|
||||
tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id;
|
||||
tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
|
||||
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
||||
|
||||
frame_size = iwl4965_fill_beacon_frame(priv,
|
||||
@ -2996,17 +3163,15 @@ static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
|
||||
#define IWL_TX_DELIMITER_SIZE 4
|
||||
|
||||
/**
|
||||
* iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array
|
||||
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
|
||||
*/
|
||||
int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
|
||||
struct iwl4965_tx_queue *txq, u16 byte_cnt)
|
||||
static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
|
||||
struct iwl4965_tx_queue *txq,
|
||||
u16 byte_cnt)
|
||||
{
|
||||
int len;
|
||||
int txq_id = txq->q.id;
|
||||
struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
|
||||
|
||||
if (txq->need_update == 0)
|
||||
return 0;
|
||||
struct iwl4965_shared *shared_data = priv->shared_virt;
|
||||
|
||||
len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
|
||||
|
||||
@ -3019,8 +3184,6 @@ int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
|
||||
IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
|
||||
tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr],
|
||||
byte_cnt, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3500,7 +3663,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
|
||||
rx_start->byte_count = amsdu->byte_count;
|
||||
rx_end = (__le32 *) (((u8 *) hdr) + len);
|
||||
}
|
||||
if (len > priv->hw_setting.max_pkt_size || len < 16) {
|
||||
if (len > priv->hw_params.max_pkt_size || len < 16) {
|
||||
IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
|
||||
return;
|
||||
}
|
||||
@ -3528,7 +3691,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
|
||||
stats->flag = 0;
|
||||
hdr = (struct ieee80211_hdr *)rxb->skb->data;
|
||||
|
||||
if (priv->cfg->mod_params->hw_crypto)
|
||||
if (!priv->cfg->mod_params->sw_crypto)
|
||||
iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
|
||||
|
||||
if (priv->add_radiotap)
|
||||
@ -4199,7 +4362,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
|
||||
* (in Tx queue's circular buffer) of first TFD/frame in window */
|
||||
u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
|
||||
|
||||
if (scd_flow >= ARRAY_SIZE(priv->txq)) {
|
||||
if (scd_flow >= priv->hw_params.max_txq_num) {
|
||||
IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
|
||||
return;
|
||||
}
|
||||
@ -4361,7 +4524,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
|
||||
void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
||||
{
|
||||
int i, r;
|
||||
struct iwl4965_link_quality_cmd link_cmd = {
|
||||
struct iwl_link_quality_cmd link_cmd = {
|
||||
.reserved1 = 0,
|
||||
};
|
||||
u16 rate_flags;
|
||||
@ -4395,7 +4558,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
||||
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
|
||||
|
||||
/* Update the rate scaling for control frame Tx to AP */
|
||||
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id;
|
||||
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
|
||||
|
||||
iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
|
||||
sizeof(link_cmd), &link_cmd, NULL);
|
||||
@ -4584,7 +4747,7 @@ static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
|
||||
{
|
||||
int txq_id;
|
||||
|
||||
for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
|
||||
if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
|
||||
return txq_id;
|
||||
return -1;
|
||||
@ -4767,7 +4930,6 @@ void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
|
||||
void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
|
||||
INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
|
||||
#ifdef CONFIG_IWL4965_SENSITIVITY
|
||||
INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
|
||||
#endif
|
||||
@ -4783,12 +4945,23 @@ void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv)
|
||||
cancel_delayed_work(&priv->init_alive_start);
|
||||
}
|
||||
|
||||
|
||||
static struct iwl_hcmd_ops iwl4965_hcmd = {
|
||||
.rxon_assoc = iwl4965_send_rxon_assoc,
|
||||
};
|
||||
|
||||
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
|
||||
.enqueue_hcmd = iwl4965_enqueue_hcmd,
|
||||
};
|
||||
|
||||
static struct iwl_lib_ops iwl4965_lib = {
|
||||
.init_drv = iwl4965_init_drv,
|
||||
.set_hw_params = iwl4965_hw_set_hw_params,
|
||||
.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
|
||||
.hw_nic_init = iwl4965_hw_nic_init,
|
||||
.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
|
||||
.alive_notify = iwl4965_alive_notify,
|
||||
.load_ucode = iwl4965_load_bsm,
|
||||
.eeprom_ops = {
|
||||
.verify_signature = iwlcore_eeprom_verify_signature,
|
||||
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
|
||||
@ -4799,10 +4972,11 @@ static struct iwl_lib_ops iwl4965_lib = {
|
||||
|
||||
static struct iwl_ops iwl4965_ops = {
|
||||
.lib = &iwl4965_lib,
|
||||
.hcmd = &iwl4965_hcmd,
|
||||
.utils = &iwl4965_hcmd_utils,
|
||||
};
|
||||
|
||||
static struct iwl_cfg iwl4965_agn_cfg = {
|
||||
struct iwl_cfg iwl4965_agn_cfg = {
|
||||
.name = "4965AGN",
|
||||
.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
|
||||
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
||||
@ -4810,21 +4984,12 @@ static struct iwl_cfg iwl4965_agn_cfg = {
|
||||
.mod_params = &iwl4965_mod_params,
|
||||
};
|
||||
|
||||
struct pci_device_id iwl4965_hw_card_ids[] = {
|
||||
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{0}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
|
||||
|
||||
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
|
||||
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
|
||||
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
|
||||
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
|
||||
module_param_named(hwcrypto, iwl4965_mod_params.hw_crypto, int, 0444);
|
||||
MODULE_PARM_DESC(hwcrypto,
|
||||
"using hardware crypto engine (default 0 [software])\n");
|
||||
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
|
||||
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])\n");
|
||||
module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
|
||||
MODULE_PARM_DESC(debug, "debug output mask");
|
||||
module_param_named(
|
||||
|
@ -36,9 +36,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
/* Hardware specific file defines the PCI IDs table for that hardware module */
|
||||
extern struct pci_device_id iwl4965_hw_card_ids[];
|
||||
|
||||
#define DRV_NAME "iwl4965"
|
||||
#include "iwl-rfkill.h"
|
||||
#include "iwl-eeprom.h"
|
||||
@ -48,6 +45,9 @@ extern struct pci_device_id iwl4965_hw_card_ids[];
|
||||
#include "iwl-debug.h"
|
||||
#include "iwl-led.h"
|
||||
|
||||
/* configuration for the iwl4965 */
|
||||
extern struct iwl_cfg iwl4965_agn_cfg;
|
||||
|
||||
/* Change firmware file name, using "-" and incrementing number,
|
||||
* *only* when uCode interface or architecture changes so that it
|
||||
* is not compatible with earlier drivers.
|
||||
@ -461,6 +461,7 @@ struct iwl4965_tid_data {
|
||||
struct iwl4965_hw_key {
|
||||
enum ieee80211_key_alg alg;
|
||||
int keylen;
|
||||
u8 keyidx;
|
||||
struct ieee80211_key_conf *conf;
|
||||
u8 key[32];
|
||||
};
|
||||
@ -566,7 +567,7 @@ struct iwl4965_ibss_seq {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl4965_driver_hw_info
|
||||
* struct iwl_hw_params
|
||||
* @max_txq_num: Max # Tx queues supported
|
||||
* @tx_cmd_len: Size of Tx command (but not including frame itself)
|
||||
* @tx_ant_num: Number of TX antennas
|
||||
@ -575,21 +576,20 @@ struct iwl4965_ibss_seq {
|
||||
* @max_rxq_log: Log-base-2 of max_rxq_size
|
||||
* @max_stations:
|
||||
* @bcast_sta_id:
|
||||
* @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
|
||||
* @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
|
||||
*/
|
||||
struct iwl4965_driver_hw_info {
|
||||
struct iwl_hw_params {
|
||||
u16 max_txq_num;
|
||||
u16 tx_cmd_len;
|
||||
u16 tx_ant_num;
|
||||
u8 tx_chains_num;
|
||||
u8 rx_chains_num;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u16 max_rxq_size;
|
||||
u16 max_rxq_log;
|
||||
u32 rx_buf_size;
|
||||
u32 max_pkt_size;
|
||||
u16 max_rxq_log;
|
||||
u8 max_stations;
|
||||
u8 bcast_sta_id;
|
||||
void *shared_virt;
|
||||
dma_addr_t shared_phys;
|
||||
};
|
||||
|
||||
#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
|
||||
@ -641,7 +641,6 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
|
||||
const u8 *dest, int left);
|
||||
extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
|
||||
struct iwl4965_rx_queue *q);
|
||||
extern int iwl4965_send_statistics_request(struct iwl_priv *priv);
|
||||
extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
|
||||
u32 decrypt_res,
|
||||
struct ieee80211_rx_status *stats);
|
||||
@ -679,7 +678,7 @@ extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv);
|
||||
extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
|
||||
extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv);
|
||||
extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv);
|
||||
extern int iwl4965_hw_set_hw_setting(struct iwl_priv *priv);
|
||||
extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv);
|
||||
extern int iwl4965_hw_nic_init(struct iwl_priv *priv);
|
||||
extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv);
|
||||
extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv);
|
||||
@ -942,6 +941,8 @@ enum {
|
||||
|
||||
#endif
|
||||
|
||||
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
|
||||
|
||||
struct iwl_priv {
|
||||
|
||||
/* ieee device used by generic ieee processing code */
|
||||
@ -1033,7 +1034,7 @@ struct iwl_priv {
|
||||
* 4965's initialize alive response contains some calibration data. */
|
||||
struct iwl4965_init_alive_resp card_alive_init;
|
||||
struct iwl4965_alive_resp card_alive;
|
||||
#ifdef CONFIG_IWLCORE_RFKILL
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
struct iwl_rfkill_mngr rfkill_mngr;
|
||||
#endif
|
||||
|
||||
@ -1112,6 +1113,10 @@ struct iwl_priv {
|
||||
spinlock_t sta_lock;
|
||||
int num_stations;
|
||||
struct iwl4965_station_entry stations[IWL_STATION_COUNT];
|
||||
struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
|
||||
u8 default_wep_key;
|
||||
u8 key_mapping_key;
|
||||
unsigned long ucode_key_table;
|
||||
|
||||
/* Indication if ieee80211_ops->open has been called */
|
||||
u8 is_open;
|
||||
@ -1142,9 +1147,14 @@ struct iwl_priv {
|
||||
/* Last Rx'd beacon timestamp */
|
||||
u64 timestamp;
|
||||
u16 beacon_int;
|
||||
struct iwl4965_driver_hw_info hw_setting;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
struct iwl_hw_params hw_params;
|
||||
/* driver/uCode shared Tx Byte Counts and Rx status */
|
||||
void *shared_virt;
|
||||
/* Physical Pointer to Tx Byte Counts and Rx status */
|
||||
dma_addr_t shared_phys;
|
||||
|
||||
/* Current association information needed to configure the
|
||||
* hardware */
|
||||
u16 assoc_id;
|
||||
@ -1200,7 +1210,6 @@ struct iwl_priv {
|
||||
#ifdef CONFIG_IWL4965_SENSITIVITY
|
||||
struct work_struct sensitivity_work;
|
||||
#endif
|
||||
struct work_struct statistics_work;
|
||||
struct timer_list statistics_periodic;
|
||||
}; /*iwl_priv */
|
||||
|
||||
|
@ -277,3 +277,16 @@ int iwlcore_low_level_notify(struct iwl_priv *priv,
|
||||
}
|
||||
EXPORT_SYMBOL(iwlcore_low_level_notify);
|
||||
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
|
||||
{
|
||||
u32 stat_flags = 0;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_STATISTICS_CMD,
|
||||
.meta.flags = flags,
|
||||
.len = sizeof(stat_flags),
|
||||
.data = (u8 *) &stat_flags,
|
||||
};
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_send_statistics_request);
|
||||
|
||||
|
@ -82,6 +82,9 @@ struct iwl_cmd;
|
||||
#define IWL_SKU_A 0x2
|
||||
#define IWL_SKU_N 0x8
|
||||
|
||||
struct iwl_hcmd_ops {
|
||||
int (*rxon_assoc)(struct iwl_priv *priv);
|
||||
};
|
||||
struct iwl_hcmd_utils_ops {
|
||||
int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
|
||||
};
|
||||
@ -89,19 +92,35 @@ struct iwl_hcmd_utils_ops {
|
||||
struct iwl_lib_ops {
|
||||
/* iwlwifi driver (priv) init */
|
||||
int (*init_drv)(struct iwl_priv *priv);
|
||||
/* set hw dependant perameters */
|
||||
int (*set_hw_params)(struct iwl_priv *priv);
|
||||
|
||||
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
|
||||
struct iwl4965_tx_queue *txq,
|
||||
u16 byte_cnt);
|
||||
/* nic init */
|
||||
int (*hw_nic_init)(struct iwl_priv *priv);
|
||||
/* alive notification */
|
||||
int (*alive_notify)(struct iwl_priv *priv);
|
||||
/* check validity of rtc data address */
|
||||
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||
/* 1st ucode load */
|
||||
int (*load_ucode)(struct iwl_priv *priv);
|
||||
/* rfkill */
|
||||
void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
|
||||
/* eeprom operations (as defined in iwl-eeprom.h) */
|
||||
struct iwl_eeprom_ops eeprom_ops;
|
||||
void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
|
||||
};
|
||||
|
||||
struct iwl_ops {
|
||||
const struct iwl_lib_ops *lib;
|
||||
const struct iwl_hcmd_ops *hcmd;
|
||||
const struct iwl_hcmd_utils_ops *utils;
|
||||
};
|
||||
|
||||
struct iwl_mod_params {
|
||||
int disable; /* def: 0 = enable radio */
|
||||
int hw_crypto; /* def: 0 = using software encryption */
|
||||
int sw_crypto; /* def: 0 = using hardware encryption */
|
||||
int debug; /* def: 0 = minimal debug log messages */
|
||||
int disable_hw_scan; /* def: 0 = use h/w scan */
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
@ -215,4 +234,13 @@ enum iwlcore_card_notify {
|
||||
|
||||
int iwlcore_low_level_notify(struct iwl_priv *priv,
|
||||
enum iwlcore_card_notify notify);
|
||||
extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
|
||||
int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq, u8 flags);
|
||||
|
||||
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
|
||||
{
|
||||
return priv->cfg->ops->hcmd->rxon_assoc(priv);
|
||||
}
|
||||
|
||||
#endif /* __iwl_core_h__ */
|
||||
|
@ -102,10 +102,14 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
char buf[256];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += sprintf(buf+pos, "mgmt: %u\n", priv->tx_stats[0].cnt);
|
||||
pos += sprintf(buf+pos, "ctrl: %u\n", priv->tx_stats[1].cnt);
|
||||
pos += sprintf(buf+pos, "data: %u\n", priv->tx_stats[2].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
|
||||
priv->tx_stats[0].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
|
||||
priv->tx_stats[1].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
|
||||
priv->tx_stats[2].cnt);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
@ -117,10 +121,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
char buf[256];
|
||||
int pos = 0;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
pos += sprintf(buf+pos, "mgmt: %u\n", priv->rx_stats[0].cnt);
|
||||
pos += sprintf(buf+pos, "ctrl: %u\n", priv->rx_stats[1].cnt);
|
||||
pos += sprintf(buf+pos, "data: %u\n", priv->rx_stats[2].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
|
||||
priv->rx_stats[0].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
|
||||
priv->rx_stats[1].cnt);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
|
||||
priv->rx_stats[2].cnt);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
@ -138,6 +146,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||
int i;
|
||||
int pos = 0;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
printk(KERN_DEBUG "offset is: 0x%x\tlen is: 0x%x\n",
|
||||
priv->dbgfs->sram_offset, priv->dbgfs->sram_len);
|
||||
@ -159,9 +168,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos += sprintf(buf+pos, "0x%08x ", val);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
|
||||
}
|
||||
pos += sprintf(buf+pos, "\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
iwl_release_nic_access(priv);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
@ -198,7 +207,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
struct iwl4965_station_entry *station;
|
||||
int max_sta = priv->hw_setting.max_stations;
|
||||
int max_sta = priv->hw_params.max_stations;
|
||||
char *buf;
|
||||
int i, j, pos = 0;
|
||||
ssize_t ret;
|
||||
@ -210,44 +219,50 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
|
||||
if(!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += sprintf(buf+pos, "num of stations: %d\n\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
|
||||
priv->num_stations);
|
||||
|
||||
for (i = 0; i < max_sta; i++) {
|
||||
station = &priv->stations[i];
|
||||
if (station->used) {
|
||||
pos += sprintf(buf+pos, "station %d:\ngeneral data:\n",
|
||||
i+1);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"station %d:\ngeneral data:\n", i+1);
|
||||
print_mac(mac, station->sta.sta.addr);
|
||||
pos += sprintf(buf+pos, "id: %u\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
|
||||
station->sta.sta.sta_id);
|
||||
pos += sprintf(buf+pos, "mode: %u\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
|
||||
station->sta.mode);
|
||||
pos += sprintf(buf+pos, "flags: 0x%x\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"flags: 0x%x\n",
|
||||
station->sta.station_flags_msk);
|
||||
pos += sprintf(buf+pos, "ps_status: %u\n",
|
||||
station->ps_status);
|
||||
|
||||
pos += sprintf(buf+pos, "tid data:\n");
|
||||
|
||||
pos += sprintf(buf+pos, "seq_num\t\ttxq_id\t");
|
||||
pos += sprintf(buf+pos, "frame_count\twait_for_ba\t");
|
||||
pos += sprintf(buf+pos, "start_idx\tbitmap0\t");
|
||||
pos += sprintf(buf+pos, "bitmap1\trate_n_flags\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"ps_status: %u\n", station->ps_status);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"seq_num\t\ttxq_id\t");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"frame_count\twait_for_ba\t");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"start_idx\tbitmap0\t");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"bitmap1\trate_n_flags\n");
|
||||
|
||||
for (j = 0; j < MAX_TID_COUNT; j++) {
|
||||
pos += sprintf(buf+pos, "[%d]:\t\t%u\t",
|
||||
j, station->tid[j].seq_number);
|
||||
pos += sprintf(buf+pos, "%u\t\t%u\t\t%u\t\t",
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"[%d]:\t\t%u\t", j,
|
||||
station->tid[j].seq_number);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%u\t\t%u\t\t%u\t\t",
|
||||
station->tid[j].agg.txq_id,
|
||||
station->tid[j].agg.frame_count,
|
||||
station->tid[j].agg.wait_for_ba);
|
||||
pos += sprintf(buf+pos, "%u\t%llu\t%u\n",
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"%u\t%llu\t%u\n",
|
||||
station->tid[j].agg.start_idx,
|
||||
(unsigned long long)station->tid[j].agg.bitmap,
|
||||
station->tid[j].agg.rate_n_flags);
|
||||
}
|
||||
pos += sprintf(buf+pos, "\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ const char *get_cmd_string(u8 cmd)
|
||||
IWL_CMD(REPLY_ADD_STA);
|
||||
IWL_CMD(REPLY_REMOVE_STA);
|
||||
IWL_CMD(REPLY_REMOVE_ALL_STA);
|
||||
IWL_CMD(REPLY_WEPKEY);
|
||||
IWL_CMD(REPLY_TX);
|
||||
IWL_CMD(REPLY_RATE_SCALE);
|
||||
IWL_CMD(REPLY_LEDS_CMD);
|
||||
|
@ -47,6 +47,9 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
||||
if (!priv->rfkill_mngr.rfkill)
|
||||
return 0;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return 0;
|
||||
|
||||
IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
|
@ -34,7 +34,7 @@ struct iwl_priv;
|
||||
#include <linux/input.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_IWLCORE_RFKILL
|
||||
#ifdef CONFIG_IWLWIFI_RFKILL
|
||||
struct iwl_rfkill_mngr {
|
||||
struct rfkill *rfkill;
|
||||
struct input_dev *input_dev;
|
||||
|
355
drivers/net/wireless/iwlwifi/iwl-sta.c
Normal file
355
drivers/net/wireless/iwlwifi/iwl-sta.c
Normal file
@ -0,0 +1,355 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project, as well
|
||||
* as portions of the ieee80211 subsystem header files.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-sta.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-sta.h"
|
||||
|
||||
int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < STA_KEY_MAX_NUM; i++)
|
||||
if (!test_and_set_bit(i, &priv->ucode_key_table))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
|
||||
{
|
||||
int i, not_empty = 0;
|
||||
u8 buff[sizeof(struct iwl_wep_cmd) +
|
||||
sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
|
||||
struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
|
||||
size_t cmd_size = sizeof(struct iwl_wep_cmd);
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_WEPKEY,
|
||||
.data = wep_cmd,
|
||||
.meta.flags = CMD_ASYNC,
|
||||
};
|
||||
|
||||
memset(wep_cmd, 0, cmd_size +
|
||||
(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
|
||||
|
||||
for (i = 0; i < WEP_KEYS_MAX ; i++) {
|
||||
wep_cmd->key[i].key_index = i;
|
||||
if (priv->wep_keys[i].key_size) {
|
||||
wep_cmd->key[i].key_offset = i;
|
||||
not_empty = 1;
|
||||
} else {
|
||||
wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
|
||||
}
|
||||
|
||||
wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
|
||||
memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
|
||||
priv->wep_keys[i].key_size);
|
||||
}
|
||||
|
||||
wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
|
||||
wep_cmd->num_keys = WEP_KEYS_MAX;
|
||||
|
||||
cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
|
||||
|
||||
cmd.len = cmd_size;
|
||||
|
||||
if (not_empty || send_if_empty)
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_remove_default_wep_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
|
||||
IWL_ERROR("index %d not used in uCode key table.\n",
|
||||
keyconf->keyidx);
|
||||
|
||||
priv->default_wep_key--;
|
||||
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
|
||||
ret = iwl_send_static_wepkey_cmd(priv, 1);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_set_default_wep_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->default_wep_key++;
|
||||
|
||||
if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
|
||||
IWL_ERROR("index %d already used in uCode key table.\n",
|
||||
keyconf->keyidx);
|
||||
|
||||
priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
|
||||
memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
ret = iwl_send_static_wepkey_cmd(priv, 0);
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
__le16 key_flags = 0;
|
||||
int ret;
|
||||
|
||||
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
|
||||
key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (keyconf->keylen == WEP_KEY_LEN_128)
|
||||
key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
|
||||
|
||||
if (sta_id == priv->hw_params.bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||
priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
|
||||
|
||||
memcpy(priv->stations[sta_id].keyinfo.key,
|
||||
keyconf->key, keyconf->keylen);
|
||||
|
||||
memcpy(&priv->stations[sta_id].sta.key.key[3],
|
||||
keyconf->key, keyconf->keylen);
|
||||
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_get_free_ucode_key_index(priv);
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
ret = iwl4965_send_add_station(priv,
|
||||
&priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
__le16 key_flags = 0;
|
||||
|
||||
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (sta_id == priv->hw_params.bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_get_free_ucode_key_index(priv);
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
|
||||
return iwl4965_send_add_station(priv,
|
||||
&priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
}
|
||||
|
||||
static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||
priv->stations[sta_id].keyinfo.conf = keyconf;
|
||||
priv->stations[sta_id].keyinfo.keylen = 16;
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
iwl_get_free_ucode_key_index(priv);
|
||||
|
||||
/* This copy is acutally not needed: we get the key with each TX */
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
priv->key_mapping_key = 0;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
|
||||
&priv->ucode_key_table))
|
||||
IWL_ERROR("index %d not used in uCode key table.\n",
|
||||
priv->stations[sta_id].sta.key.key_offset);
|
||||
memset(&priv->stations[sta_id].keyinfo, 0,
|
||||
sizeof(struct iwl4965_hw_key));
|
||||
memset(&priv->stations[sta_id].sta.key, 0,
|
||||
sizeof(struct iwl4965_keyinfo));
|
||||
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
|
||||
return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
|
||||
}
|
||||
|
||||
int iwl_set_dynamic_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key, u8 sta_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
priv->key_mapping_key = 1;
|
||||
|
||||
switch (key->alg) {
|
||||
case ALG_CCMP:
|
||||
ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
|
||||
break;
|
||||
case ALG_WEP:
|
||||
ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
|
||||
break;
|
||||
default:
|
||||
IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static void iwl_dump_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq)
|
||||
{
|
||||
int i;
|
||||
IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
|
||||
IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
|
||||
lq->general_params.single_stream_ant_msk,
|
||||
lq->general_params.dual_stream_ant_msk);
|
||||
|
||||
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
|
||||
IWL_DEBUG_RATE("lq index %d 0x%X\n",
|
||||
i, lq->rs_table[i].rate_n_flags);
|
||||
}
|
||||
#else
|
||||
static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq, u8 flags)
|
||||
{
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_TX_LINK_QUALITY_CMD,
|
||||
.len = sizeof(struct iwl_link_quality_cmd),
|
||||
.meta.flags = flags,
|
||||
.data = lq,
|
||||
};
|
||||
|
||||
if ((lq->sta_id == 0xFF) &&
|
||||
(priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
|
||||
return -EINVAL;
|
||||
|
||||
if (lq->sta_id == 0xFF)
|
||||
lq->sta_id = IWL_AP_ID;
|
||||
|
||||
iwl_dump_lq_cmd(priv,lq);
|
||||
|
||||
if (iwl_is_associated(priv) && priv->assoc_station_added &&
|
||||
priv->lq_mngr.lq_ready)
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_send_lq_cmd);
|
||||
|
49
drivers/net/wireless/iwlwifi/iwl-sta.h
Normal file
49
drivers/net/wireless/iwlwifi/iwl-sta.h
Normal file
@ -0,0 +1,49 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project, as well
|
||||
* as portions of the ieee80211 subsystem header files.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in the
|
||||
* file called LICENSE.
|
||||
*
|
||||
* Contact Information:
|
||||
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef __iwl_sta_h__
|
||||
#define __iwl_sta_h__
|
||||
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-eeprom.h"
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-4965.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
|
||||
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
|
||||
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
|
||||
int iwl_remove_default_wep_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key);
|
||||
int iwl_set_default_wep_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key);
|
||||
int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id);
|
||||
int iwl_set_dynamic_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key, u8 sta_id);
|
||||
#endif /* __iwl_sta_h__ */
|
@ -70,7 +70,7 @@ static int iwl3945_param_disable; /* def: 0 = enable radio */
|
||||
static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */
|
||||
int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */
|
||||
static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
|
||||
int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
|
||||
int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
|
||||
|
||||
/*
|
||||
* module name, copyright, version, etc.
|
||||
@ -7974,10 +7974,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
iwl3945_hw_ops.hw_scan = NULL;
|
||||
}
|
||||
|
||||
if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) ||
|
||||
if ((iwl3945_param_queues_num > IWL39_MAX_NUM_QUEUES) ||
|
||||
(iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) {
|
||||
IWL_ERROR("invalid queues_num, should be between %d and %d\n",
|
||||
IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
|
||||
IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "iwl-core.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-helpers.h"
|
||||
#include "iwl-sta.h"
|
||||
|
||||
static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
|
||||
struct iwl4965_tx_queue *txq);
|
||||
@ -397,9 +398,9 @@ static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_a
|
||||
if (is_ap)
|
||||
index = IWL_AP_ID;
|
||||
else if (is_broadcast_ether_addr(addr))
|
||||
index = priv->hw_setting.bcast_sta_id;
|
||||
index = priv->hw_params.bcast_sta_id;
|
||||
else
|
||||
for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
|
||||
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
|
||||
if (priv->stations[i].used &&
|
||||
!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
||||
addr)) {
|
||||
@ -439,9 +440,9 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
|
||||
if (is_ap)
|
||||
index = IWL_AP_ID;
|
||||
else if (is_broadcast_ether_addr(addr))
|
||||
index = priv->hw_setting.bcast_sta_id;
|
||||
index = priv->hw_params.bcast_sta_id;
|
||||
else
|
||||
for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
|
||||
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
|
||||
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
||||
addr)) {
|
||||
index = i;
|
||||
@ -482,7 +483,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
|
||||
|
||||
#ifdef CONFIG_IWL4965_HT
|
||||
/* BCAST station and IBSS stations do not work in HT mode */
|
||||
if (index != priv->hw_setting.bcast_sta_id &&
|
||||
if (index != priv->hw_params.bcast_sta_id &&
|
||||
priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
|
||||
iwl4965_set_ht_add_station(priv, index,
|
||||
(struct ieee80211_ht_info *) ht_data);
|
||||
@ -574,11 +575,11 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||
txq->need_update = 1;
|
||||
|
||||
/* Set up entry in queue's byte count circular buffer */
|
||||
ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
|
||||
priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
|
||||
|
||||
/* Increment and update queue's write index */
|
||||
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
|
||||
iwl4965_tx_queue_update_write_ptr(priv, txq);
|
||||
ret = iwl4965_tx_queue_update_write_ptr(priv, txq);
|
||||
|
||||
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
|
||||
return ret ? ret : idx;
|
||||
@ -595,13 +596,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
|
||||
|
||||
}
|
||||
|
||||
int iwl4965_send_statistics_request(struct iwl_priv *priv)
|
||||
{
|
||||
u32 flags = 0;
|
||||
return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
sizeof(flags), &flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_rxon_add_station - add station into station table.
|
||||
*
|
||||
@ -755,60 +749,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
|
||||
{
|
||||
int rc = 0;
|
||||
struct iwl4965_rx_packet *res = NULL;
|
||||
struct iwl4965_rxon_assoc_cmd rxon_assoc;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_RXON_ASSOC,
|
||||
.len = sizeof(rxon_assoc),
|
||||
.meta.flags = CMD_WANT_SKB,
|
||||
.data = &rxon_assoc,
|
||||
};
|
||||
const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
|
||||
const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
|
||||
|
||||
if ((rxon1->flags == rxon2->flags) &&
|
||||
(rxon1->filter_flags == rxon2->filter_flags) &&
|
||||
(rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
|
||||
(rxon1->ofdm_ht_single_stream_basic_rates ==
|
||||
rxon2->ofdm_ht_single_stream_basic_rates) &&
|
||||
(rxon1->ofdm_ht_dual_stream_basic_rates ==
|
||||
rxon2->ofdm_ht_dual_stream_basic_rates) &&
|
||||
(rxon1->rx_chain == rxon2->rx_chain) &&
|
||||
(rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
|
||||
IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rxon_assoc.flags = priv->staging_rxon.flags;
|
||||
rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
|
||||
rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
|
||||
rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
|
||||
rxon_assoc.reserved = 0;
|
||||
rxon_assoc.ofdm_ht_single_stream_basic_rates =
|
||||
priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
|
||||
rxon_assoc.ofdm_ht_dual_stream_basic_rates =
|
||||
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
|
||||
rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
|
||||
|
||||
rc = iwl_send_cmd_sync(priv, &cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
|
||||
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
|
||||
IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb_any(cmd.meta.u.skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_commit_rxon - commit staging_rxon to hardware
|
||||
*
|
||||
@ -840,7 +780,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
||||
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter
|
||||
* and other flags for the current radio configuration. */
|
||||
if (!iwl4965_full_rxon_required(priv)) {
|
||||
rc = iwl4965_send_rxon_assoc(priv);
|
||||
rc = iwl_send_rxon_assoc(priv);
|
||||
if (rc) {
|
||||
IWL_ERROR("Error setting RXON_ASSOC "
|
||||
"configuration (%d).\n", rc);
|
||||
@ -895,7 +835,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
||||
le16_to_cpu(priv->staging_rxon.channel),
|
||||
print_mac(mac, priv->staging_rxon.bssid_addr));
|
||||
|
||||
iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto);
|
||||
iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
|
||||
/* Apply the new configuration */
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
|
||||
sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
|
||||
@ -941,6 +881,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
|
||||
return -EIO;
|
||||
}
|
||||
priv->assoc_station_added = 1;
|
||||
if (priv->default_wep_key &&
|
||||
iwl_send_static_wepkey_cmd(priv, 0))
|
||||
IWL_ERROR("Could not send WEP static key.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1108,131 +1051,6 @@ int iwl4965_send_add_station(struct iwl_priv *priv,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
__le16 key_flags = 0;
|
||||
|
||||
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
|
||||
if (sta_id == priv->hw_setting.bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
|
||||
keyconf->keylen);
|
||||
|
||||
priv->stations[sta_id].sta.key.key_offset
|
||||
= (sta_id % STA_KEY_MAX_NUM);/*FIXME*/
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
|
||||
return iwl4965_send_add_station(priv,
|
||||
&priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
}
|
||||
|
||||
static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *keyconf,
|
||||
u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
keyconf->hw_key_idx = keyconf->keyidx;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||
priv->stations[sta_id].keyinfo.conf = keyconf;
|
||||
priv->stations[sta_id].keyinfo.keylen = 16;
|
||||
|
||||
/* This copy is acutally not needed: we get the key with each TX */
|
||||
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
|
||||
|
||||
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
|
||||
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
|
||||
memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo));
|
||||
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
|
||||
iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key, u8 sta_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (key->alg) {
|
||||
case ALG_CCMP:
|
||||
ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
|
||||
break;
|
||||
case ALG_TKIP:
|
||||
ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id);
|
||||
break;
|
||||
case ALG_WEP:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
default:
|
||||
IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl4965_remove_static_key(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl4965_set_static_key(struct iwl_priv *priv,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
if (key->alg == ALG_WEP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
IWL_ERROR("Static key invalid: alg %d\n", key->alg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void iwl4965_clear_free_frames(struct iwl_priv *priv)
|
||||
{
|
||||
struct list_head *element;
|
||||
@ -1353,13 +1171,13 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void iwl4965_unset_hw_setting(struct iwl_priv *priv)
|
||||
static void iwl4965_unset_hw_params(struct iwl_priv *priv)
|
||||
{
|
||||
if (priv->hw_setting.shared_virt)
|
||||
if (priv->shared_virt)
|
||||
pci_free_consistent(priv->pci_dev,
|
||||
sizeof(struct iwl4965_shared),
|
||||
priv->hw_setting.shared_virt,
|
||||
priv->hw_setting.shared_phys);
|
||||
priv->shared_virt,
|
||||
priv->shared_phys);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1976,7 +1794,7 @@ static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
|
||||
| RXON_FLG_CCK_MSK);
|
||||
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
} else {
|
||||
/* Copied from iwl4965_bg_post_associate() */
|
||||
/* Copied from iwl4965_post_associate() */
|
||||
if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
|
||||
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
|
||||
else
|
||||
@ -2115,6 +1933,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
||||
int sta_id)
|
||||
{
|
||||
struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
|
||||
struct iwl_wep_key *wepkey;
|
||||
int keyidx = 0;
|
||||
|
||||
BUG_ON(ctl->key_idx > 3);
|
||||
|
||||
switch (keyinfo->alg) {
|
||||
case ALG_CCMP:
|
||||
@ -2133,16 +1955,29 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
||||
break;
|
||||
|
||||
case ALG_WEP:
|
||||
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
|
||||
(ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
|
||||
wepkey = &priv->wep_keys[ctl->key_idx];
|
||||
cmd->cmd.tx.sec_ctl = 0;
|
||||
if (priv->default_wep_key) {
|
||||
/* the WEP key was sent as static */
|
||||
keyidx = ctl->key_idx;
|
||||
memcpy(&cmd->cmd.tx.key[3], wepkey->key,
|
||||
wepkey->key_size);
|
||||
if (wepkey->key_size == WEP_KEY_LEN_128)
|
||||
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
|
||||
} else {
|
||||
/* the WEP key was sent as dynamic */
|
||||
keyidx = keyinfo->keyidx;
|
||||
memcpy(&cmd->cmd.tx.key[3], keyinfo->key,
|
||||
keyinfo->keylen);
|
||||
if (keyinfo->keylen == WEP_KEY_LEN_128)
|
||||
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
|
||||
}
|
||||
|
||||
if (keyinfo->keylen == 13)
|
||||
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
|
||||
|
||||
memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
|
||||
cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP |
|
||||
(keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
|
||||
|
||||
IWL_DEBUG_TX("Configuring packet for WEP encryption "
|
||||
"with key %d\n", ctl->key_idx);
|
||||
"with key %d\n", keyidx);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2240,7 +2075,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
|
||||
/* If this frame is broadcast or management, use broadcast station id */
|
||||
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
|
||||
is_multicast_ether_addr(hdr->addr1))
|
||||
return priv->hw_setting.bcast_sta_id;
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
switch (priv->iw_mode) {
|
||||
|
||||
@ -2254,7 +2089,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
|
||||
sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
|
||||
if (sta_id != IWL_INVALID_STATION)
|
||||
return sta_id;
|
||||
return priv->hw_setting.bcast_sta_id;
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
/* If this frame is going out to an IBSS network, find the station,
|
||||
* or create a new station table entry */
|
||||
@ -2274,11 +2109,11 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
|
||||
"Defaulting to broadcast...\n",
|
||||
print_mac(mac, hdr->addr1));
|
||||
iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
|
||||
return priv->hw_setting.bcast_sta_id;
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
default:
|
||||
IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
|
||||
return priv->hw_setting.bcast_sta_id;
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2425,7 +2260,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
|
||||
* of the MAC header (device reads on dword boundaries).
|
||||
* We'll tell device about this padding later.
|
||||
*/
|
||||
len = priv->hw_setting.tx_cmd_len +
|
||||
len = priv->hw_params.tx_cmd_len +
|
||||
sizeof(struct iwl_cmd_header) + hdr_len;
|
||||
|
||||
len_org = len;
|
||||
@ -2496,7 +2331,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
|
||||
ieee80211_get_hdrlen(fc));
|
||||
|
||||
/* Set up entry for this TFD in Tx byte-count array */
|
||||
iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
|
||||
priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
|
||||
|
||||
/* Tell device the write index *just past* this latest filled TFD */
|
||||
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
|
||||
@ -2592,7 +2427,8 @@ void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
|
||||
CSR_UCODE_SW_BIT_RFKILL);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
/* call the host command only if no hw rf-kill set */
|
||||
if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
|
||||
if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
|
||||
iwl_is_ready(priv))
|
||||
iwl4965_send_card_state(priv,
|
||||
CARD_STATE_CMD_DISABLE,
|
||||
0);
|
||||
@ -3852,7 +3688,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
|
||||
|
||||
/* Alloc a new receive buffer */
|
||||
rxb->skb =
|
||||
alloc_skb(priv->hw_setting.rx_buf_size,
|
||||
alloc_skb(priv->hw_params.rx_buf_size,
|
||||
__GFP_NOWARN | GFP_ATOMIC);
|
||||
if (!rxb->skb) {
|
||||
if (net_ratelimit())
|
||||
@ -3869,7 +3705,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
|
||||
/* Get physical address of RB/SKB */
|
||||
rxb->dma_addr =
|
||||
pci_map_single(priv->pci_dev, rxb->skb->data,
|
||||
priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
|
||||
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
|
||||
list_add_tail(&rxb->list, &rxq->rx_free);
|
||||
rxq->free_count++;
|
||||
}
|
||||
@ -3912,7 +3748,7 @@ static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue
|
||||
if (rxq->pool[i].skb != NULL) {
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
rxq->pool[i].dma_addr,
|
||||
priv->hw_setting.rx_buf_size,
|
||||
priv->hw_params.rx_buf_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb(rxq->pool[i].skb);
|
||||
}
|
||||
@ -3964,7 +3800,7 @@ void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
|
||||
if (rxq->pool[i].skb != NULL) {
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
rxq->pool[i].dma_addr,
|
||||
priv->hw_setting.rx_buf_size,
|
||||
priv->hw_params.rx_buf_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
priv->alloc_rxb_skb--;
|
||||
dev_kfree_skb(rxq->pool[i].skb);
|
||||
@ -4099,7 +3935,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
|
||||
rxq->queue[i] = NULL;
|
||||
|
||||
pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
|
||||
priv->hw_setting.rx_buf_size,
|
||||
priv->hw_params.rx_buf_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
|
||||
|
||||
@ -4152,7 +3988,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
|
||||
}
|
||||
|
||||
pci_unmap_single(priv->pci_dev, rxb->dma_addr,
|
||||
priv->hw_setting.rx_buf_size,
|
||||
priv->hw_params.rx_buf_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
spin_lock_irqsave(&rxq->lock, flags);
|
||||
list_add_tail(&rxb->list, &priv->rxq.rx_used);
|
||||
@ -4305,7 +4141,7 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
|
||||
|
||||
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
|
||||
|
||||
if (!iwl4965_hw_valid_rtc_data_addr(base)) {
|
||||
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
||||
IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
|
||||
return;
|
||||
}
|
||||
@ -4400,7 +4236,7 @@ static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
|
||||
u32 size; /* # entries that we'll print */
|
||||
|
||||
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
||||
if (!iwl4965_hw_valid_rtc_data_addr(base)) {
|
||||
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
|
||||
IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
|
||||
return;
|
||||
}
|
||||
@ -5175,156 +5011,6 @@ static int iwl4965_verify_ucode(struct iwl_priv *priv)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* check contents of special bootstrap uCode SRAM */
|
||||
static int iwl4965_verify_bsm(struct iwl_priv *priv)
|
||||
{
|
||||
__le32 *image = priv->ucode_boot.v_addr;
|
||||
u32 len = priv->ucode_boot.len;
|
||||
u32 reg;
|
||||
u32 val;
|
||||
|
||||
IWL_DEBUG_INFO("Begin verify bsm\n");
|
||||
|
||||
/* verify BSM SRAM contents */
|
||||
val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
|
||||
for (reg = BSM_SRAM_LOWER_BOUND;
|
||||
reg < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg += sizeof(u32), image ++) {
|
||||
val = iwl_read_prph(priv, reg);
|
||||
if (val != le32_to_cpu(*image)) {
|
||||
IWL_ERROR("BSM uCode verification failed at "
|
||||
"addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
|
||||
BSM_SRAM_LOWER_BOUND,
|
||||
reg - BSM_SRAM_LOWER_BOUND, len,
|
||||
val, le32_to_cpu(*image));
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl4965_load_bsm - Load bootstrap instructions
|
||||
*
|
||||
* BSM operation:
|
||||
*
|
||||
* The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
|
||||
* in special SRAM that does not power down during RFKILL. When powering back
|
||||
* up after power-saving sleeps (or during initial uCode load), the BSM loads
|
||||
* the bootstrap program into the on-board processor, and starts it.
|
||||
*
|
||||
* The bootstrap program loads (via DMA) instructions and data for a new
|
||||
* program from host DRAM locations indicated by the host driver in the
|
||||
* BSM_DRAM_* registers. Once the new program is loaded, it starts
|
||||
* automatically.
|
||||
*
|
||||
* When initializing the NIC, the host driver points the BSM to the
|
||||
* "initialize" uCode image. This uCode sets up some internal data, then
|
||||
* notifies host via "initialize alive" that it is complete.
|
||||
*
|
||||
* The host then replaces the BSM_DRAM_* pointer values to point to the
|
||||
* normal runtime uCode instructions and a backup uCode data cache buffer
|
||||
* (filled initially with starting data values for the on-board processor),
|
||||
* then triggers the "initialize" uCode to load and launch the runtime uCode,
|
||||
* which begins normal operation.
|
||||
*
|
||||
* When doing a power-save shutdown, runtime uCode saves data SRAM into
|
||||
* the backup data cache in DRAM before SRAM is powered down.
|
||||
*
|
||||
* When powering back up, the BSM loads the bootstrap program. This reloads
|
||||
* the runtime uCode instructions and the backup data cache into SRAM,
|
||||
* and re-launches the runtime uCode from where it left off.
|
||||
*/
|
||||
static int iwl4965_load_bsm(struct iwl_priv *priv)
|
||||
{
|
||||
__le32 *image = priv->ucode_boot.v_addr;
|
||||
u32 len = priv->ucode_boot.len;
|
||||
dma_addr_t pinst;
|
||||
dma_addr_t pdata;
|
||||
u32 inst_len;
|
||||
u32 data_len;
|
||||
int rc;
|
||||
int i;
|
||||
u32 done;
|
||||
u32 reg_offset;
|
||||
|
||||
IWL_DEBUG_INFO("Begin load bsm\n");
|
||||
|
||||
/* make sure bootstrap program is no larger than BSM's SRAM size */
|
||||
if (len > IWL_MAX_BSM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/* Tell bootstrap uCode where to find the "Initialize" uCode
|
||||
* in host DRAM ... host DRAM physical address bits 35:4 for 4965.
|
||||
* NOTE: iwl4965_initialize_alive_start() will replace these values,
|
||||
* after the "initialize" uCode has run, to point to
|
||||
* runtime/protocol instructions and backup data cache. */
|
||||
pinst = priv->ucode_init.p_addr >> 4;
|
||||
pdata = priv->ucode_init_data.p_addr >> 4;
|
||||
inst_len = priv->ucode_init.len;
|
||||
data_len = priv->ucode_init_data.len;
|
||||
|
||||
rc = iwl_grab_nic_access(priv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
|
||||
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
|
||||
iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
|
||||
|
||||
/* Fill BSM memory with bootstrap instructions */
|
||||
for (reg_offset = BSM_SRAM_LOWER_BOUND;
|
||||
reg_offset < BSM_SRAM_LOWER_BOUND + len;
|
||||
reg_offset += sizeof(u32), image++)
|
||||
_iwl_write_prph(priv, reg_offset,
|
||||
le32_to_cpu(*image));
|
||||
|
||||
rc = iwl4965_verify_bsm(priv);
|
||||
if (rc) {
|
||||
iwl_release_nic_access(priv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
|
||||
iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
|
||||
iwl_write_prph(priv, BSM_WR_MEM_DST_REG,
|
||||
RTC_INST_LOWER_BOUND);
|
||||
iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
|
||||
|
||||
/* Load bootstrap code into instruction SRAM now,
|
||||
* to prepare to load "initialize" uCode */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
BSM_WR_CTRL_REG_BIT_START);
|
||||
|
||||
/* Wait for load of bootstrap uCode to finish */
|
||||
for (i = 0; i < 100; i++) {
|
||||
done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
|
||||
if (!(done & BSM_WR_CTRL_REG_BIT_START))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (i < 100)
|
||||
IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
|
||||
else {
|
||||
IWL_ERROR("BSM write did not complete!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Enable future boot loads whenever power management unit triggers it
|
||||
* (e.g. when powering back up after power-save shutdown) */
|
||||
iwl_write_prph(priv, BSM_WR_CTRL_REG,
|
||||
BSM_WR_CTRL_REG_BIT_START_EN);
|
||||
|
||||
iwl_release_nic_access(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl4965_nic_start(struct iwl_priv *priv)
|
||||
{
|
||||
/* Remove all resets to allow NIC to operate */
|
||||
@ -5634,7 +5320,7 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
|
||||
*/
|
||||
static void iwl4965_alive_start(struct iwl_priv *priv)
|
||||
{
|
||||
int rc = 0;
|
||||
int ret = 0;
|
||||
|
||||
IWL_DEBUG_INFO("Runtime Alive received.\n");
|
||||
|
||||
@ -5657,10 +5343,10 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
|
||||
|
||||
iwlcore_clear_stations_table(priv);
|
||||
|
||||
rc = iwl4965_alive_notify(priv);
|
||||
if (rc) {
|
||||
ret = priv->cfg->ops->lib->alive_notify(priv);
|
||||
if (ret) {
|
||||
IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
|
||||
rc);
|
||||
ret);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
@ -5835,7 +5521,8 @@ static void iwl4965_down(struct iwl_priv *priv)
|
||||
|
||||
static int __iwl4965_up(struct iwl_priv *priv)
|
||||
{
|
||||
int rc, i;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
|
||||
IWL_WARNING("Exit pending; will not bring the NIC up\n");
|
||||
@ -5870,10 +5557,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
|
||||
iwl_rfkill_set_hw_state(priv);
|
||||
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
||||
|
||||
rc = iwl4965_hw_nic_init(priv);
|
||||
if (rc) {
|
||||
IWL_ERROR("Unable to int nic\n");
|
||||
return rc;
|
||||
ret = priv->cfg->ops->lib->hw_nic_init(priv);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to init nic\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure rfkill handshake bits are cleared */
|
||||
@ -5906,10 +5593,10 @@ static int __iwl4965_up(struct iwl_priv *priv)
|
||||
/* load bootstrap state machine,
|
||||
* load bootstrap program into processor's memory,
|
||||
* prepare to load the "initialize" uCode */
|
||||
rc = iwl4965_load_bsm(priv);
|
||||
ret = priv->cfg->ops->lib->load_ucode(priv);
|
||||
|
||||
if (rc) {
|
||||
IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -6146,7 +5833,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
|
||||
}
|
||||
|
||||
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
|
||||
scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
|
||||
scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
|
||||
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
||||
|
||||
|
||||
@ -6272,10 +5959,8 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
|
||||
|
||||
#define IWL_DELAY_NEXT_SCAN (HZ*2)
|
||||
|
||||
static void iwl4965_bg_post_associate(struct work_struct *data)
|
||||
static void iwl4965_post_associate(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(data, struct iwl_priv,
|
||||
post_associate.work);
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
int ret = 0;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
@ -6293,12 +5978,10 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (!priv->vif || !priv->is_open) {
|
||||
mutex_unlock(&priv->mutex);
|
||||
if (!priv->vif || !priv->is_open)
|
||||
return;
|
||||
}
|
||||
|
||||
iwl4965_scan_cancel_timeout(priv, 200);
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
@ -6382,7 +6065,18 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
|
||||
|
||||
/* we have just associated, don't start scan too early */
|
||||
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
|
||||
}
|
||||
|
||||
|
||||
static void iwl4965_bg_post_associate(struct work_struct *data)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(data, struct iwl_priv,
|
||||
post_associate.work);
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl4965_post_associate(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
}
|
||||
|
||||
static void iwl4965_bg_abort_scan(struct work_struct *work)
|
||||
@ -7004,6 +6698,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
if (changes & BSS_CHANGED_ASSOC) {
|
||||
IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
|
||||
/* This should never happen as this function should
|
||||
* never be called from interrupt context. */
|
||||
if (WARN_ON_ONCE(in_interrupt()))
|
||||
return;
|
||||
if (bss_conf->assoc) {
|
||||
priv->assoc_id = bss_conf->aid;
|
||||
priv->beacon_int = bss_conf->beacon_int;
|
||||
@ -7011,14 +6709,16 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
|
||||
priv->assoc_capability = bss_conf->assoc_capability;
|
||||
priv->next_scan_jiffies = jiffies +
|
||||
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
|
||||
queue_work(priv->workqueue, &priv->post_associate.work);
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl4965_post_associate(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
} else {
|
||||
priv->assoc_id = 0;
|
||||
IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
|
||||
}
|
||||
} else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
|
||||
IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
|
||||
iwl4965_send_rxon_assoc(priv);
|
||||
iwl_send_rxon_assoc(priv);
|
||||
}
|
||||
|
||||
}
|
||||
@ -7106,13 +6806,11 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
|
||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||
|
||||
if (sta_id == priv->hw_setting.bcast_sta_id)
|
||||
if (sta_id == priv->hw_params.bcast_sta_id)
|
||||
key_flags |= STA_KEY_MULTICAST_MSK;
|
||||
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
|
||||
priv->stations[sta_id].sta.key.key_offset =
|
||||
(sta_id % STA_KEY_MAX_NUM);/* FIXME */
|
||||
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||
priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
|
||||
|
||||
@ -7138,11 +6836,11 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
DECLARE_MAC_BUF(mac);
|
||||
int ret = 0;
|
||||
u8 sta_id = IWL_INVALID_STATION;
|
||||
u8 static_key;
|
||||
u8 is_default_wep_key = 0;
|
||||
|
||||
IWL_DEBUG_MAC80211("enter\n");
|
||||
|
||||
if (!priv->cfg->mod_params->hw_crypto) {
|
||||
if (priv->cfg->mod_params->sw_crypto) {
|
||||
IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -7151,35 +6849,44 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
/* only support pairwise keys */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* FIXME: need to differenciate between static and dynamic key
|
||||
* in the level of mac80211 */
|
||||
static_key = !iwl_is_associated(priv);
|
||||
sta_id = iwl4965_hw_find_station(priv, addr);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
|
||||
print_mac(mac, addr));
|
||||
return -EINVAL;
|
||||
|
||||
if (!static_key) {
|
||||
sta_id = iwl4965_hw_find_station(priv, addr);
|
||||
if (sta_id == IWL_INVALID_STATION) {
|
||||
IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
|
||||
print_mac(mac, addr));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl4965_scan_cancel_timeout(priv, 100);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
/* If we are getting WEP group key and we didn't receive any key mapping
|
||||
* so far, we are in legacy wep mode (group key only), otherwise we are
|
||||
* in 1X mode.
|
||||
* In legacy wep mode, we use another host command to the uCode */
|
||||
if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
|
||||
priv->iw_mode != IEEE80211_IF_TYPE_AP) {
|
||||
if (cmd == SET_KEY)
|
||||
is_default_wep_key = !priv->key_mapping_key;
|
||||
else
|
||||
is_default_wep_key = priv->default_wep_key;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
if (static_key)
|
||||
ret = iwl4965_set_static_key(priv, key);
|
||||
if (is_default_wep_key)
|
||||
ret = iwl_set_default_wep_key(priv, key);
|
||||
else
|
||||
ret = iwl4965_set_dynamic_key(priv, key, sta_id);
|
||||
ret = iwl_set_dynamic_key(priv, key, sta_id);
|
||||
|
||||
IWL_DEBUG_MAC80211("enable hwcrypto key\n");
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
if (static_key)
|
||||
ret = iwl4965_remove_static_key(priv);
|
||||
if (is_default_wep_key)
|
||||
ret = iwl_remove_default_wep_key(priv, key);
|
||||
else
|
||||
ret = iwl4965_clear_sta_key_info(priv, sta_id);
|
||||
ret = iwl_remove_dynamic_key(priv, sta_id);
|
||||
|
||||
IWL_DEBUG_MAC80211("disable hwcrypto key\n");
|
||||
break;
|
||||
@ -7776,7 +7483,7 @@ static ssize_t show_statistics(struct device *d,
|
||||
return -EAGAIN;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
rc = iwl4965_send_statistics_request(priv);
|
||||
rc = iwl_send_statistics_request(priv, 0);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (rc) {
|
||||
@ -8084,8 +7791,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
* 5. Setup HW constants
|
||||
************************/
|
||||
/* Device-specific setup */
|
||||
if (iwl4965_hw_set_hw_setting(priv)) {
|
||||
IWL_ERROR("failed to set hw settings\n");
|
||||
if (priv->cfg->ops->lib->set_hw_params(priv)) {
|
||||
IWL_ERROR("failed to set hw parameters\n");
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
@ -8095,7 +7802,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
|
||||
err = iwl_setup(priv);
|
||||
if (err)
|
||||
goto out_unset_hw_settings;
|
||||
goto out_unset_hw_params;
|
||||
/* At this point both hw and priv are initialized. */
|
||||
|
||||
/**********************************
|
||||
@ -8121,7 +7828,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
|
||||
if (err) {
|
||||
IWL_ERROR("failed to create sysfs device attributes\n");
|
||||
goto out_unset_hw_settings;
|
||||
goto out_unset_hw_params;
|
||||
}
|
||||
|
||||
err = iwl_dbgfs_register(priv, DRV_NAME);
|
||||
@ -8145,8 +7852,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
||||
|
||||
out_remove_sysfs:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
|
||||
out_unset_hw_settings:
|
||||
iwl4965_unset_hw_setting(priv);
|
||||
out_unset_hw_params:
|
||||
iwl4965_unset_hw_params(priv);
|
||||
out_iounmap:
|
||||
pci_iounmap(pdev, priv->hw_base);
|
||||
out_pci_release_regions:
|
||||
@ -8208,7 +7915,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
|
||||
iwl4965_rx_queue_free(priv, &priv->rxq);
|
||||
iwl4965_hw_txq_ctx_free(priv);
|
||||
|
||||
iwl4965_unset_hw_setting(priv);
|
||||
iwl4965_unset_hw_params(priv);
|
||||
iwlcore_clear_stations_table(priv);
|
||||
|
||||
|
||||
@ -8273,9 +7980,17 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static struct pci_driver iwl4965_driver = {
|
||||
/* Hardware specific file defines the PCI IDs table for that hardware module */
|
||||
static struct pci_device_id iwl_hw_card_ids[] = {
|
||||
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
|
||||
|
||||
static struct pci_driver iwl_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = iwl4965_hw_card_ids,
|
||||
.id_table = iwl_hw_card_ids,
|
||||
.probe = iwl4965_pci_probe,
|
||||
.remove = __devexit_p(iwl4965_pci_remove),
|
||||
#ifdef CONFIG_PM
|
||||
@ -8297,13 +8012,13 @@ static int __init iwl4965_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pci_register_driver(&iwl4965_driver);
|
||||
ret = pci_register_driver(&iwl_driver);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to initialize PCI module\n");
|
||||
goto error_register;
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
|
||||
ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
|
||||
if (ret) {
|
||||
IWL_ERROR("Unable to create driver sysfs file\n");
|
||||
goto error_debug;
|
||||
@ -8314,7 +8029,7 @@ static int __init iwl4965_init(void)
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
error_debug:
|
||||
pci_unregister_driver(&iwl4965_driver);
|
||||
pci_unregister_driver(&iwl_driver);
|
||||
#endif
|
||||
error_register:
|
||||
iwl4965_rate_control_unregister();
|
||||
@ -8324,9 +8039,9 @@ error_register:
|
||||
static void __exit iwl4965_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
|
||||
driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
|
||||
#endif
|
||||
pci_unregister_driver(&iwl4965_driver);
|
||||
pci_unregister_driver(&iwl_driver);
|
||||
iwl4965_rate_control_unregister();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include "host.h"
|
||||
#include "hostcmd.h"
|
||||
#include "decl.h"
|
||||
@ -295,6 +296,7 @@ int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
|
||||
|
||||
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));
|
||||
|
||||
@ -358,7 +360,9 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(cmd_action);
|
||||
|
||||
if (cmd_action == CMD_ACT_SET) {
|
||||
if (cmd_action == CMD_ACT_GET)
|
||||
cmd.enable = 0;
|
||||
else {
|
||||
if (*enable)
|
||||
cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
|
||||
else
|
||||
@ -810,6 +814,7 @@ int lbs_get_channel(struct lbs_private *priv)
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
|
||||
|
||||
@ -857,6 +862,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
|
||||
cmd.channel = cpu_to_le16(channel);
|
||||
@ -1829,15 +1835,20 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
|
||||
|
||||
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
|
||||
sizeof(confirm_sleep));
|
||||
|
||||
if (ret) {
|
||||
lbs_pr_alert("confirm_sleep failed\n");
|
||||
} else {
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
if (!priv->intcounter)
|
||||
priv->psstate = PS_STATE_SLEEP;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
/* If nothing to do, go back to sleep (?) */
|
||||
if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
|
||||
priv->psstate = PS_STATE_SLEEP;
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
@ -1899,13 +1910,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
/* In-progress command? */
|
||||
if (priv->cur_cmd) {
|
||||
allowed = 0;
|
||||
lbs_deb_host("cur_cmd was set\n");
|
||||
}
|
||||
if (priv->intcounter > 0) {
|
||||
|
||||
/* Pending events or command responses? */
|
||||
if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
|
||||
allowed = 0;
|
||||
lbs_deb_host("intcounter %d\n", priv->intcounter);
|
||||
lbs_deb_host("pending events or command responses\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
|
@ -384,7 +384,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_process_rx_command(struct lbs_private *priv)
|
||||
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
|
||||
{
|
||||
uint16_t respcmd, curcmd;
|
||||
struct cmd_header *resp;
|
||||
@ -404,14 +404,14 @@ int lbs_process_rx_command(struct lbs_private *priv)
|
||||
goto done;
|
||||
}
|
||||
|
||||
resp = (void *)priv->upld_buf;
|
||||
resp = (void *)data;
|
||||
curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
|
||||
respcmd = le16_to_cpu(resp->command);
|
||||
result = le16_to_cpu(resp->result);
|
||||
|
||||
lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
|
||||
respcmd, le16_to_cpu(resp->seqnum), priv->upld_len);
|
||||
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, priv->upld_len);
|
||||
respcmd, le16_to_cpu(resp->seqnum), len);
|
||||
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
|
||||
|
||||
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
|
||||
lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
|
||||
@ -569,18 +569,13 @@ static int lbs_send_confirmwake(struct lbs_private *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lbs_process_event(struct lbs_private *priv)
|
||||
int lbs_process_event(struct lbs_private *priv, u32 event)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 eventcause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
switch (eventcause) {
|
||||
switch (event) {
|
||||
case MACREG_INT_CODE_LINK_SENSED:
|
||||
lbs_deb_cmd("EVENT: link sensed\n");
|
||||
break;
|
||||
@ -696,14 +691,10 @@ int lbs_process_event(struct lbs_private *priv)
|
||||
break;
|
||||
|
||||
default:
|
||||
lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
|
||||
lbs_pr_alert("EVENT: unknown event id %d\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
priv->eventcause = 0;
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -824,7 +824,6 @@ struct debug_data {
|
||||
/* To debug any member of struct lbs_private, simply add one line here.
|
||||
*/
|
||||
static struct debug_data items[] = {
|
||||
{"intcounter", item_size(intcounter), item_addr(intcounter)},
|
||||
{"psmode", item_size(psmode), item_addr(psmode)},
|
||||
{"psstate", item_size(psstate), item_addr(psstate)},
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ struct cmd_ds_command;
|
||||
|
||||
void lbs_set_mac_control(struct lbs_private *priv);
|
||||
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv);
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
|
||||
|
||||
int lbs_free_cmd_buffer(struct lbs_private *priv);
|
||||
|
||||
@ -30,14 +30,16 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
|
||||
|
||||
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);
|
||||
void lbs_interrupt(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_radio_control(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_rx_command(struct lbs_private *priv);
|
||||
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);
|
||||
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||
|
@ -177,8 +177,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
|
||||
#define MRVDRV_CMD_UPLD_RDY 0x0008
|
||||
#define MRVDRV_CARDEVENT 0x0010
|
||||
|
||||
#define SBI_EVENT_CAUSE_SHIFT 3
|
||||
|
||||
/** TxPD status */
|
||||
|
||||
/* Station firmware use TxPD status field to report final Tx transmit
|
||||
|
@ -129,10 +129,6 @@ struct lbs_private {
|
||||
u32 bbp_offset;
|
||||
u32 rf_offset;
|
||||
|
||||
/** Upload length */
|
||||
u32 upld_len;
|
||||
/* Upload buffer */
|
||||
u8 upld_buf[LBS_UPLD_SIZE];
|
||||
/* Download sent:
|
||||
bit0 1/0=data_sent/data_tx_done,
|
||||
bit1 1/0=cmd_sent/cmd_tx_done,
|
||||
@ -155,21 +151,16 @@ struct lbs_private {
|
||||
|
||||
/** Hardware access */
|
||||
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
|
||||
int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
|
||||
int (*hw_read_event_cause) (struct lbs_private *);
|
||||
|
||||
/* Wake On LAN */
|
||||
uint32_t wol_criteria;
|
||||
uint8_t wol_gpio;
|
||||
uint8_t wol_gap;
|
||||
|
||||
/* was struct lbs_adapter from here... */
|
||||
|
||||
/** Wlan adapter data structure*/
|
||||
/** STATUS variables */
|
||||
u32 fwrelease;
|
||||
u32 fwcapinfo;
|
||||
/* protected with big lock */
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
@ -181,7 +172,6 @@ struct lbs_private {
|
||||
|
||||
/** command-related variables */
|
||||
u16 seqnum;
|
||||
/* protected by big lock */
|
||||
|
||||
struct cmd_ctrl_node *cmd_array;
|
||||
/** Current command */
|
||||
@ -194,12 +184,17 @@ struct lbs_private {
|
||||
struct list_head cmdpendingq;
|
||||
|
||||
wait_queue_head_t cmd_pending;
|
||||
/* command related variables protected by priv->driver_lock */
|
||||
|
||||
/** Async and Sync Event variables */
|
||||
u32 intcounter;
|
||||
u32 eventcause;
|
||||
u8 nodename[16]; /* nickname */
|
||||
/* Command responses sent from the hardware to the driver */
|
||||
u8 resp_idx;
|
||||
u8 resp_buf[2][LBS_UPLD_SIZE];
|
||||
u32 resp_len[2];
|
||||
|
||||
/* Events sent from hardware to driver */
|
||||
struct kfifo *event_fifo;
|
||||
|
||||
/* nickname */
|
||||
u8 nodename[16];
|
||||
|
||||
/** spin locks */
|
||||
spinlock_t driver_lock;
|
||||
@ -209,8 +204,6 @@ struct lbs_private {
|
||||
int nr_retries;
|
||||
int cmd_timed_out;
|
||||
|
||||
u8 hisregcpy;
|
||||
|
||||
/** current ssid/bssid related parameters*/
|
||||
struct current_bss_params curbssparams;
|
||||
|
||||
|
@ -83,14 +83,14 @@ static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
|
||||
{
|
||||
unsigned int val = ioread8(card->iobase + reg);
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
|
||||
printk(KERN_INFO "inb %08x<%02x\n", reg, val);
|
||||
return val;
|
||||
}
|
||||
static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
|
||||
{
|
||||
unsigned int val = ioread16(card->iobase + reg);
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
|
||||
printk(KERN_INFO "inw %08x<%04x\n", reg, val);
|
||||
return val;
|
||||
}
|
||||
static inline void if_cs_read16_rep(
|
||||
@ -100,7 +100,7 @@ static inline void if_cs_read16_rep(
|
||||
unsigned long count)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
|
||||
printk(KERN_INFO "insw %08x<(0x%lx words)\n",
|
||||
reg, count);
|
||||
ioread16_rep(card->iobase + reg, buf, count);
|
||||
}
|
||||
@ -108,14 +108,14 @@ static inline void if_cs_read16_rep(
|
||||
static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
|
||||
printk(KERN_INFO "outb %08x>%02x\n", reg, val);
|
||||
iowrite8(val, card->iobase + reg);
|
||||
}
|
||||
|
||||
static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
|
||||
printk(KERN_INFO "outw %08x>%04x\n", reg, val);
|
||||
iowrite16(val, card->iobase + reg);
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ static inline void if_cs_write16_rep(
|
||||
unsigned long count)
|
||||
{
|
||||
if (debug_output)
|
||||
printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
|
||||
printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
|
||||
reg, count);
|
||||
iowrite16_rep(card->iobase + reg, buf, count);
|
||||
}
|
||||
@ -199,17 +199,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
|
||||
#define IF_CS_C_S_CARDEVENT 0x0010
|
||||
#define IF_CS_C_S_MASK 0x001f
|
||||
#define IF_CS_C_S_STATUS_MASK 0x7f00
|
||||
/* The following definitions should be the same as the MRVDRV_ ones */
|
||||
|
||||
#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
|
||||
#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
|
||||
#endif
|
||||
#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
|
||||
#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
|
||||
#endif
|
||||
#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
|
||||
#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
|
||||
#endif
|
||||
|
||||
#define IF_CS_C_INT_CAUSE 0x00000022
|
||||
#define IF_CS_C_IC_MASK 0x001f
|
||||
@ -225,55 +214,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Interrupts */
|
||||
/********************************************************************/
|
||||
|
||||
static inline void if_cs_enable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, 0);
|
||||
}
|
||||
|
||||
static inline void if_cs_disable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
|
||||
}
|
||||
|
||||
static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||
{
|
||||
struct if_cs_card *card = data;
|
||||
u16 int_cause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
|
||||
if (int_cause == 0x0) {
|
||||
/* Not for us */
|
||||
return IRQ_NONE;
|
||||
|
||||
} else if (int_cause == 0xffff) {
|
||||
/* Read in junk, the card has probably been removed */
|
||||
card->priv->surpriseremoved = 1;
|
||||
return IRQ_HANDLED;
|
||||
} else {
|
||||
if (int_cause & IF_CS_H_IC_TX_OVER)
|
||||
lbs_host_to_card_done(card->priv);
|
||||
|
||||
/* clear interrupt */
|
||||
if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
|
||||
}
|
||||
spin_lock(&card->priv->driver_lock);
|
||||
lbs_interrupt(card->priv);
|
||||
spin_unlock(&card->priv->driver_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* I/O */
|
||||
/********************************************************************/
|
||||
@ -351,6 +291,7 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
*/
|
||||
static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = -1;
|
||||
u16 val;
|
||||
|
||||
@ -378,6 +319,12 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
|
||||
* bytes */
|
||||
*len -= 8;
|
||||
ret = 0;
|
||||
|
||||
/* Clear this flag again */
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
priv->dnld_sent = DNLD_RES_RECEIVED;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
|
||||
return ret;
|
||||
@ -396,11 +343,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
|
||||
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
|
||||
lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
|
||||
priv->stats.rx_dropped++;
|
||||
printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
|
||||
goto dat_err;
|
||||
}
|
||||
|
||||
//TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
|
||||
skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
|
||||
if (!skb)
|
||||
goto out;
|
||||
@ -424,6 +369,96 @@ out:
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Interrupts */
|
||||
/********************************************************************/
|
||||
|
||||
static inline void if_cs_enable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, 0);
|
||||
}
|
||||
|
||||
static inline void if_cs_disable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||
{
|
||||
struct if_cs_card *card = data;
|
||||
struct lbs_private *priv = card->priv;
|
||||
u16 cause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
|
||||
if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
|
||||
|
||||
lbs_deb_cs("cause 0x%04x\n", cause);
|
||||
if (cause == 0) {
|
||||
/* Not for us */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (cause == 0xffff) {
|
||||
/* Read in junk, the card has probably been removed */
|
||||
card->priv->surpriseremoved = 1;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* TODO: I'm not sure what the best ordering is */
|
||||
|
||||
cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
|
||||
|
||||
if (cause & IF_CS_C_S_RX_UPLD_RDY) {
|
||||
struct sk_buff *skb;
|
||||
lbs_deb_cs("rx packet\n");
|
||||
skb = if_cs_receive_data(priv);
|
||||
if (skb)
|
||||
lbs_process_rxed_packet(priv, skb);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_H_IC_TX_OVER) {
|
||||
lbs_deb_cs("tx over\n");
|
||||
lbs_host_to_card_done(priv);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
|
||||
unsigned long flags;
|
||||
u8 i;
|
||||
|
||||
lbs_deb_cs("cmd upload ready\n");
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
i = (priv->resp_idx == 0) ? 1 : 0;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
BUG_ON(priv->resp_len[i]);
|
||||
if_cs_receive_cmdres(priv, priv->resp_buf[i],
|
||||
&priv->resp_len[i]);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
lbs_notify_command_response(priv, i);
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
}
|
||||
|
||||
if (cause & IF_CS_H_IC_HOST_EVENT) {
|
||||
u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
|
||||
& IF_CS_C_S_STATUS_MASK;
|
||||
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
|
||||
IF_CS_H_IC_HOST_EVENT);
|
||||
lbs_deb_cs("eventcause 0x%04x\n", event);
|
||||
lbs_queue_event(priv, event >> 8 & 0xff);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Firmware */
|
||||
/********************************************************************/
|
||||
@ -476,8 +511,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
|
||||
|
||||
if (remain < count)
|
||||
count = remain;
|
||||
/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
|
||||
__LINE__, sent, fw->size); */
|
||||
|
||||
/* "write the number of bytes to be sent to the I/O Command
|
||||
* write length register" */
|
||||
@ -544,18 +577,12 @@ static int if_cs_prog_real(struct if_cs_card *card)
|
||||
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
|
||||
if (ret < 0) {
|
||||
int i;
|
||||
lbs_pr_err("helper firmware doesn't answer\n");
|
||||
for (i = 0; i < 0x50; i += 2)
|
||||
printk(KERN_INFO "## HS %02x: %04x\n",
|
||||
i, if_cs_read16(card, i));
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
for (sent = 0; sent < fw->size; sent += len) {
|
||||
len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
|
||||
/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
|
||||
__LINE__, sent, fw->size); */
|
||||
if (len & 1) {
|
||||
retry++;
|
||||
lbs_pr_info("odd, need to retry this firmware block\n");
|
||||
@ -642,64 +669,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
|
||||
}
|
||||
|
||||
|
||||
static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
|
||||
{
|
||||
struct if_cs_card *card = (struct if_cs_card *)priv->card;
|
||||
int ret = 0;
|
||||
u16 int_cause;
|
||||
*ireg = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
if (priv->surpriseremoved)
|
||||
goto out;
|
||||
|
||||
int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
|
||||
if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
|
||||
|
||||
*ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
|
||||
|
||||
if (!*ireg)
|
||||
goto sbi_get_int_status_exit;
|
||||
|
||||
sbi_get_int_status_exit:
|
||||
|
||||
/* is there a data packet for us? */
|
||||
if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
|
||||
struct sk_buff *skb = if_cs_receive_data(priv);
|
||||
lbs_process_rxed_packet(priv, skb);
|
||||
*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
|
||||
}
|
||||
|
||||
if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
|
||||
priv->dnld_sent = DNLD_RES_RECEIVED;
|
||||
}
|
||||
|
||||
/* Card has a command result for us */
|
||||
if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
|
||||
ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
|
||||
if (ret < 0)
|
||||
lbs_pr_err("could not receive cmd from card\n");
|
||||
}
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int if_cs_read_event_cause(struct lbs_private *priv)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
|
||||
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* Card Services */
|
||||
/********************************************************************/
|
||||
@ -852,13 +821,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* Store pointers to our call-back functions */
|
||||
/* Finish setting up fields in lbs_private */
|
||||
card->priv = priv;
|
||||
priv->card = card;
|
||||
priv->hw_host_to_card = if_cs_host_to_card;
|
||||
priv->hw_get_int_status = if_cs_get_int_status;
|
||||
priv->hw_read_event_cause = if_cs_read_event_cause;
|
||||
|
||||
priv->hw_host_to_card = if_cs_host_to_card;
|
||||
priv->fw_ready = 1;
|
||||
|
||||
/* Now actually get the IRQ */
|
||||
|
@ -91,8 +91,6 @@ struct if_sdio_card {
|
||||
const char *firmware;
|
||||
|
||||
u8 buffer[65536];
|
||||
u8 int_cause;
|
||||
u32 event;
|
||||
|
||||
spinlock_t lock;
|
||||
struct if_sdio_packet *packets;
|
||||
@ -129,13 +127,13 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
|
||||
static int if_sdio_handle_cmd(struct if_sdio_card *card,
|
||||
u8 *buffer, unsigned size)
|
||||
{
|
||||
struct lbs_private *priv = card->priv;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
u8 i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
spin_lock_irqsave(&card->priv->driver_lock, flags);
|
||||
|
||||
if (size > LBS_CMD_BUFFER_SIZE) {
|
||||
lbs_deb_sdio("response packet too large (%d bytes)\n",
|
||||
(int)size);
|
||||
@ -143,20 +141,20 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(card->priv->upld_buf, buffer, size);
|
||||
card->priv->upld_len = size;
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
card->int_cause |= MRVDRV_CMD_UPLD_RDY;
|
||||
i = (priv->resp_idx == 0) ? 1 : 0;
|
||||
BUG_ON(priv->resp_len[i]);
|
||||
priv->resp_len[i] = size;
|
||||
memcpy(priv->resp_buf[i], buffer, size);
|
||||
lbs_notify_command_response(priv, i);
|
||||
|
||||
lbs_interrupt(card->priv);
|
||||
spin_unlock_irqrestore(&card->priv->driver_lock, flags);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&card->priv->driver_lock, flags);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -202,7 +200,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
|
||||
u8 *buffer, unsigned size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
u32 event;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
@ -222,18 +219,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
|
||||
event |= buffer[2] << 16;
|
||||
event |= buffer[1] << 8;
|
||||
event |= buffer[0] << 0;
|
||||
event <<= SBI_EVENT_CAUSE_SHIFT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&card->priv->driver_lock, flags);
|
||||
|
||||
card->event = event;
|
||||
card->int_cause |= MRVDRV_CARDEVENT;
|
||||
|
||||
lbs_interrupt(card->priv);
|
||||
|
||||
spin_unlock_irqrestore(&card->priv->driver_lock, flags);
|
||||
|
||||
lbs_queue_event(card->priv, event & 0xFF);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
@ -770,37 +758,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg)
|
||||
{
|
||||
struct if_sdio_card *card;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
card = priv->card;
|
||||
|
||||
*ireg = card->int_cause;
|
||||
card->int_cause = 0;
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int if_sdio_read_event_cause(struct lbs_private *priv)
|
||||
{
|
||||
struct if_sdio_card *card;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
card = priv->card;
|
||||
|
||||
priv->eventcause = card->event;
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* SDIO callbacks */
|
||||
/*******************************************************************/
|
||||
@ -953,8 +910,6 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||
|
||||
priv->card = card;
|
||||
priv->hw_host_to_card = if_sdio_host_to_card;
|
||||
priv->hw_get_int_status = if_sdio_get_int_status;
|
||||
priv->hw_read_event_cause = if_sdio_read_event_cause;
|
||||
|
||||
priv->fw_ready = 1;
|
||||
|
||||
|
@ -38,8 +38,6 @@ static void if_usb_receive_fwload(struct urb *urb);
|
||||
static int if_usb_prog_firmware(struct if_usb_card *cardp);
|
||||
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
|
||||
uint8_t *payload, uint16_t nb);
|
||||
static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
|
||||
static int if_usb_read_event_cause(struct lbs_private *);
|
||||
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
|
||||
uint16_t nb);
|
||||
static void if_usb_free(struct if_usb_card *cardp);
|
||||
@ -233,8 +231,6 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||
cardp->priv->fw_ready = 1;
|
||||
|
||||
priv->hw_host_to_card = if_usb_host_to_card;
|
||||
priv->hw_get_int_status = if_usb_get_int_status;
|
||||
priv->hw_read_event_cause = if_usb_read_event_cause;
|
||||
cardp->boot2_version = udev->descriptor.bcdDevice;
|
||||
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
@ -582,7 +578,6 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
|
||||
skb_pull(skb, MESSAGE_HEADER_LEN);
|
||||
|
||||
lbs_process_rxed_packet(priv, skb);
|
||||
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
|
||||
}
|
||||
|
||||
static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
|
||||
@ -590,6 +585,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
|
||||
struct if_usb_card *cardp,
|
||||
struct lbs_private *priv)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
if (recvlength > LBS_CMD_BUFFER_SIZE) {
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
"The receive buffer is too large\n");
|
||||
@ -601,12 +598,15 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
|
||||
BUG();
|
||||
|
||||
spin_lock(&priv->driver_lock);
|
||||
cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
|
||||
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
|
||||
memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
|
||||
|
||||
i = (priv->resp_idx == 0) ? 1 : 0;
|
||||
BUG_ON(priv->resp_len[i]);
|
||||
priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
|
||||
memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
|
||||
priv->resp_len[i]);
|
||||
kfree_skb(skb);
|
||||
lbs_interrupt(priv);
|
||||
lbs_notify_command_response(priv, i);
|
||||
|
||||
spin_unlock(&priv->driver_lock);
|
||||
|
||||
lbs_deb_usbd(&cardp->udev->dev,
|
||||
@ -629,6 +629,7 @@ static void if_usb_receive(struct urb *urb)
|
||||
uint8_t *recvbuff = NULL;
|
||||
uint32_t recvtype = 0;
|
||||
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
|
||||
uint32_t event;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
@ -660,26 +661,20 @@ static void if_usb_receive(struct urb *urb)
|
||||
break;
|
||||
|
||||
case CMD_TYPE_INDICATION:
|
||||
/* Event cause handling */
|
||||
spin_lock(&priv->driver_lock);
|
||||
|
||||
cardp->usb_event_cause = le32_to_cpu(pkt[1]);
|
||||
|
||||
lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
|
||||
cardp->usb_event_cause);
|
||||
/* Event handling */
|
||||
event = le32_to_cpu(pkt[1]);
|
||||
lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Icky undocumented magic special case */
|
||||
if (cardp->usb_event_cause & 0xffff0000) {
|
||||
lbs_send_tx_feedback(priv);
|
||||
spin_unlock(&priv->driver_lock);
|
||||
break;
|
||||
}
|
||||
cardp->usb_event_cause <<= 3;
|
||||
cardp->usb_int_cause |= MRVDRV_CARDEVENT;
|
||||
kfree_skb(skb);
|
||||
lbs_interrupt(priv);
|
||||
spin_unlock(&priv->driver_lock);
|
||||
goto rx_exit;
|
||||
if (event & 0xffff0000) {
|
||||
u32 trycount = (event & 0xffff0000) >> 16;
|
||||
|
||||
lbs_send_tx_feedback(priv, trycount);
|
||||
} else
|
||||
lbs_queue_event(priv, event & 0xFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
|
||||
recvtype);
|
||||
@ -722,30 +717,6 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
|
||||
return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
|
||||
}
|
||||
|
||||
/* called with priv->driver_lock held */
|
||||
static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
|
||||
{
|
||||
struct if_usb_card *cardp = priv->card;
|
||||
|
||||
*ireg = cardp->usb_int_cause;
|
||||
cardp->usb_int_cause = 0;
|
||||
|
||||
lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int if_usb_read_event_cause(struct lbs_private *priv)
|
||||
{
|
||||
struct if_usb_card *cardp = priv->card;
|
||||
|
||||
priv->eventcause = cardp->usb_event_cause;
|
||||
/* Re-submit rx urb here to avoid event lost issue */
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function issues Boot command to the Boot2 code
|
||||
* @param ivalue 1:Boot from FW by USB-Download
|
||||
|
@ -46,8 +46,6 @@ struct if_usb_card {
|
||||
struct lbs_private *priv;
|
||||
|
||||
struct sk_buff *rx_skb;
|
||||
uint32_t usb_event_cause;
|
||||
uint8_t usb_int_cause;
|
||||
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/ieee80211.h>
|
||||
@ -480,10 +481,9 @@ static void lbs_tx_timeout(struct net_device *dev)
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
if (priv->currenttxskb) {
|
||||
priv->eventcause = 0x01000000;
|
||||
lbs_send_tx_feedback(priv);
|
||||
}
|
||||
if (priv->currenttxskb)
|
||||
lbs_send_tx_feedback(priv, 0);
|
||||
|
||||
/* XX: Shouldn't we also call into the hw-specific driver
|
||||
to kick it somehow? */
|
||||
lbs_host_to_card_done(priv);
|
||||
@ -659,7 +659,6 @@ static int lbs_thread(void *data)
|
||||
struct net_device *dev = data;
|
||||
struct lbs_private *priv = dev->priv;
|
||||
wait_queue_t wait;
|
||||
u8 ireg = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
@ -667,9 +666,10 @@ static int lbs_thread(void *data)
|
||||
|
||||
for (;;) {
|
||||
int shouldsleep;
|
||||
u8 resp_idx;
|
||||
|
||||
lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
|
||||
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
|
||||
lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
|
||||
priv->currenttxskb, priv->dnld_sent);
|
||||
|
||||
add_wait_queue(&priv->waitq, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
@ -681,8 +681,6 @@ static int lbs_thread(void *data)
|
||||
shouldsleep = 1; /* We need to wait until we're _told_ to die */
|
||||
else if (priv->psstate == PS_STATE_SLEEP)
|
||||
shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
|
||||
else if (priv->intcounter)
|
||||
shouldsleep = 0; /* Interrupt pending. Deal with it now */
|
||||
else if (priv->cmd_timed_out)
|
||||
shouldsleep = 0; /* Command timed out. Recover */
|
||||
else if (!priv->fw_ready)
|
||||
@ -695,29 +693,34 @@ static int lbs_thread(void *data)
|
||||
shouldsleep = 1; /* Can't send a command; one already running */
|
||||
else if (!list_empty(&priv->cmdpendingq))
|
||||
shouldsleep = 0; /* We have a command to send */
|
||||
else if (__kfifo_len(priv->event_fifo))
|
||||
shouldsleep = 0; /* We have an event to process */
|
||||
else if (priv->resp_len[priv->resp_idx])
|
||||
shouldsleep = 0; /* We have a command response */
|
||||
else
|
||||
shouldsleep = 1; /* No command */
|
||||
|
||||
if (shouldsleep) {
|
||||
lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
|
||||
priv->connect_status, priv->intcounter,
|
||||
priv->psmode, priv->psstate);
|
||||
lbs_deb_thread("sleeping, connect_status %d, "
|
||||
"ps_mode %d, ps_state %d\n",
|
||||
priv->connect_status,
|
||||
priv->psmode, priv->psstate);
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
schedule();
|
||||
} else
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n",
|
||||
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
|
||||
lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
|
||||
priv->currenttxskb, priv->dnld_sent);
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&priv->waitq, &wait);
|
||||
|
||||
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
|
||||
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
|
||||
lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
|
||||
priv->currenttxskb, priv->dnld_sent);
|
||||
|
||||
if (kthread_should_stop()) {
|
||||
lbs_deb_thread("main-thread: break from main thread\n");
|
||||
lbs_deb_thread("break from main thread\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -726,35 +729,23 @@ static int lbs_thread(void *data)
|
||||
continue;
|
||||
}
|
||||
|
||||
lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
|
||||
priv->currenttxskb, priv->dnld_sent);
|
||||
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
|
||||
if (priv->intcounter) {
|
||||
u8 int_status;
|
||||
|
||||
priv->intcounter = 0;
|
||||
int_status = priv->hw_get_int_status(priv, &ireg);
|
||||
|
||||
if (int_status) {
|
||||
lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
continue;
|
||||
}
|
||||
priv->hisregcpy |= ireg;
|
||||
}
|
||||
|
||||
lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
|
||||
priv->intcounter, priv->currenttxskb, priv->dnld_sent);
|
||||
|
||||
/* command response? */
|
||||
if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
|
||||
lbs_deb_thread("main-thread: cmd response ready\n");
|
||||
|
||||
priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
|
||||
/* Process any pending command response */
|
||||
resp_idx = priv->resp_idx;
|
||||
if (priv->resp_len[resp_idx]) {
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
lbs_process_rx_command(priv);
|
||||
lbs_process_command_response(priv,
|
||||
priv->resp_buf[resp_idx],
|
||||
priv->resp_len[resp_idx]);
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
priv->resp_len[resp_idx] = 0;
|
||||
}
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
/* command timeout stuff */
|
||||
if (priv->cmd_timed_out && priv->cur_cmd) {
|
||||
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
|
||||
|
||||
@ -775,21 +766,18 @@ static int lbs_thread(void *data)
|
||||
}
|
||||
priv->cmd_timed_out = 0;
|
||||
|
||||
/* Any Card Event */
|
||||
if (priv->hisregcpy & MRVDRV_CARDEVENT) {
|
||||
lbs_deb_thread("main-thread: Card Event Activity\n");
|
||||
/* Process hardware events, e.g. card removed, link lost */
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
while (__kfifo_len(priv->event_fifo)) {
|
||||
u32 event;
|
||||
|
||||
priv->hisregcpy &= ~MRVDRV_CARDEVENT;
|
||||
|
||||
if (priv->hw_read_event_cause(priv)) {
|
||||
lbs_pr_alert("main-thread: hw_read_event_cause failed\n");
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
continue;
|
||||
}
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
lbs_process_event(priv);
|
||||
} else
|
||||
__kfifo_get(priv->event_fifo, (unsigned char *) &event,
|
||||
sizeof(event));
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
lbs_process_event(priv, event);
|
||||
spin_lock_irq(&priv->driver_lock);
|
||||
}
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
if (!priv->fw_ready)
|
||||
continue;
|
||||
@ -798,8 +786,10 @@ static int lbs_thread(void *data)
|
||||
if (priv->psstate == PS_STATE_PRE_SLEEP &&
|
||||
!priv->dnld_sent && !priv->cur_cmd) {
|
||||
if (priv->connect_status == LBS_CONNECTED) {
|
||||
lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n",
|
||||
priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);
|
||||
lbs_deb_thread("pre-sleep, currenttxskb %p, "
|
||||
"dnld_sent %d, cur_cmd %p\n",
|
||||
priv->currenttxskb, priv->dnld_sent,
|
||||
priv->cur_cmd);
|
||||
|
||||
lbs_ps_confirm_sleep(priv);
|
||||
} else {
|
||||
@ -809,7 +799,8 @@ static int lbs_thread(void *data)
|
||||
* after firmware fixes it
|
||||
*/
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n");
|
||||
lbs_pr_alert("ignore PS_SleepConfirm in "
|
||||
"non-connected state\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1046,7 +1037,18 @@ static int lbs_init_adapter(struct lbs_private *priv)
|
||||
/* Allocate the command buffers */
|
||||
if (lbs_allocate_cmd_buffer(priv)) {
|
||||
lbs_pr_err("Out of memory allocating command buffers\n");
|
||||
ret = -1;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
priv->resp_idx = 0;
|
||||
priv->resp_len[0] = priv->resp_len[1] = 0;
|
||||
|
||||
/* Create the event FIFO */
|
||||
priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
|
||||
if (IS_ERR(priv->event_fifo)) {
|
||||
lbs_pr_err("Out of memory allocating event FIFO buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -1060,6 +1062,8 @@ static void lbs_free_adapter(struct lbs_private *priv)
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
lbs_free_cmd_buffer(priv);
|
||||
if (priv->event_fifo)
|
||||
kfifo_free(priv->event_fifo);
|
||||
del_timer(&priv->command_timer);
|
||||
kfree(priv->networks);
|
||||
priv->networks = NULL;
|
||||
@ -1434,27 +1438,41 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles the interrupt. it will change PS
|
||||
* state if applicable. it will wake up main_thread to handle
|
||||
* the interrupt event as well.
|
||||
*
|
||||
* @param dev A pointer to net_device structure
|
||||
* @return n/a
|
||||
*/
|
||||
void lbs_interrupt(struct lbs_private *priv)
|
||||
void lbs_queue_event(struct lbs_private *priv, u32 event)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->psstate == PS_STATE_SLEEP)
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
|
||||
__kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32));
|
||||
|
||||
wake_up_interruptible(&priv->waitq);
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_queue_event);
|
||||
|
||||
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
|
||||
priv->intcounter++;
|
||||
if (priv->psstate == PS_STATE_SLEEP)
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
|
||||
/* Swap buffers by flipping the response index */
|
||||
BUG_ON(resp_idx > 1);
|
||||
priv->resp_idx = resp_idx;
|
||||
|
||||
wake_up_interruptible(&priv->waitq);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_interrupt);
|
||||
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
|
||||
|
||||
static int __init lbs_init_module(void)
|
||||
{
|
||||
|
@ -145,14 +145,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
|
||||
struct net_device *dev = priv->dev;
|
||||
struct rxpackethdr *p_rx_pkt;
|
||||
struct rxpd *p_rx_pd;
|
||||
|
||||
int hdrchop;
|
||||
struct ethhdr *p_ethhdr;
|
||||
|
||||
const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
BUG_ON(!skb);
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
if (priv->monitormode)
|
||||
|
@ -179,31 +179,17 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv)
|
||||
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
|
||||
{
|
||||
struct tx_radiotap_hdr *radiotap_hdr;
|
||||
u32 status = priv->eventcause;
|
||||
int txfail;
|
||||
int try_count;
|
||||
|
||||
if (!priv->monitormode || priv->currenttxskb == NULL)
|
||||
return;
|
||||
|
||||
radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
|
||||
|
||||
txfail = (status >> 24);
|
||||
|
||||
#if 0
|
||||
/* The version of roofnet that we've tested does not use this yet
|
||||
* But it may be used in the future.
|
||||
*/
|
||||
if (txfail)
|
||||
radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
|
||||
#endif
|
||||
try_count = (status >> 16) & 0xff;
|
||||
radiotap_hdr->data_retries = (try_count) ?
|
||||
(1 + priv->txretrycount - try_count) : 0;
|
||||
|
||||
radiotap_hdr->data_retries = try_count ?
|
||||
(1 + priv->txretrycount - try_count) : 0;
|
||||
|
||||
priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
|
||||
priv->rtap_net_dev);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
@ -2582,7 +2583,7 @@ static char *nettype[] = {"Adhoc", "Infra "};
|
||||
static char *framing[] = {"Encapsulation", "Translation"}
|
||||
;
|
||||
/*===========================================================================*/
|
||||
static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
|
||||
static int ray_cs_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
/* Print current values which are not available via other means
|
||||
* eg ifconfig
|
||||
@ -2606,83 +2607,93 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
|
||||
if (!local)
|
||||
return 0;
|
||||
|
||||
len = 0;
|
||||
|
||||
len += sprintf(buf + len, "Raylink Wireless LAN driver status\n");
|
||||
len += sprintf(buf + len, "%s\n", rcsid);
|
||||
seq_puts(m, "Raylink Wireless LAN driver status\n");
|
||||
seq_printf(m, "%s\n", rcsid);
|
||||
/* build 4 does not report version, and field is 0x55 after memtest */
|
||||
len += sprintf(buf + len, "Firmware version = ");
|
||||
seq_puts(m, "Firmware version = ");
|
||||
if (local->fw_ver == 0x55)
|
||||
len += sprintf(buf + len, "4 - Use dump_cis for more details\n");
|
||||
seq_puts(m, "4 - Use dump_cis for more details\n");
|
||||
else
|
||||
len += sprintf(buf + len, "%2d.%02d.%02d\n",
|
||||
seq_printf(m, "%2d.%02d.%02d\n",
|
||||
local->fw_ver, local->fw_bld, local->fw_var);
|
||||
|
||||
for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i];
|
||||
c[32] = 0;
|
||||
len += sprintf(buf + len, "%s network ESSID = \"%s\"\n",
|
||||
seq_printf(m, "%s network ESSID = \"%s\"\n",
|
||||
nettype[local->sparm.b5.a_network_type], c);
|
||||
|
||||
p = local->bss_id;
|
||||
len += sprintf(buf + len, "BSSID = %s\n",
|
||||
seq_printf(m, "BSSID = %s\n",
|
||||
print_mac(mac, p));
|
||||
|
||||
len += sprintf(buf + len, "Country code = %d\n",
|
||||
seq_printf(m, "Country code = %d\n",
|
||||
local->sparm.b5.a_curr_country_code);
|
||||
|
||||
i = local->card_status;
|
||||
if (i < 0) i = 10;
|
||||
if (i > 16) i = 10;
|
||||
len += sprintf(buf + len, "Card status = %s\n", card_status[i]);
|
||||
seq_printf(m, "Card status = %s\n", card_status[i]);
|
||||
|
||||
len += sprintf(buf + len, "Framing mode = %s\n",framing[translate]);
|
||||
seq_printf(m, "Framing mode = %s\n",framing[translate]);
|
||||
|
||||
len += sprintf(buf + len, "Last pkt signal lvl = %d\n", local->last_rsl);
|
||||
seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl);
|
||||
|
||||
if (local->beacon_rxed) {
|
||||
/* Pull some fields out of last beacon received */
|
||||
len += sprintf(buf + len, "Beacon Interval = %d Kus\n",
|
||||
seq_printf(m, "Beacon Interval = %d Kus\n",
|
||||
local->last_bcn.beacon_intvl[0]
|
||||
+ 256 * local->last_bcn.beacon_intvl[1]);
|
||||
|
||||
p = local->last_bcn.elements;
|
||||
if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2;
|
||||
else {
|
||||
len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]);
|
||||
return len;
|
||||
seq_printf(m, "Parse beacon failed at essid element id = %d\n",p[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
|
||||
len += sprintf(buf + len, "Supported rate codes = ");
|
||||
seq_puts(m, "Supported rate codes = ");
|
||||
for (i=2; i<p[1] + 2; i++)
|
||||
len += sprintf(buf + len, "0x%02x ", p[i]);
|
||||
len += sprintf(buf + len, "\n");
|
||||
seq_printf(m, "0x%02x ", p[i]);
|
||||
seq_putc(m, '\n');
|
||||
p += p[1] + 2;
|
||||
}
|
||||
else {
|
||||
len += sprintf(buf + len, "Parse beacon failed at rates element\n");
|
||||
return len;
|
||||
seq_puts(m, "Parse beacon failed at rates element\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
|
||||
pfh = (struct freq_hop_element *)p;
|
||||
len += sprintf(buf + len, "Hop dwell = %d Kus\n",
|
||||
seq_printf(m, "Hop dwell = %d Kus\n",
|
||||
pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
|
||||
len += sprintf(buf + len, "Hop set = %d \n", pfh->hop_set);
|
||||
len += sprintf(buf + len, "Hop pattern = %d \n", pfh->hop_pattern);
|
||||
len += sprintf(buf + len, "Hop index = %d \n", pfh->hop_index);
|
||||
seq_printf(m, "Hop set = %d \n", pfh->hop_set);
|
||||
seq_printf(m, "Hop pattern = %d \n", pfh->hop_pattern);
|
||||
seq_printf(m, "Hop index = %d \n", pfh->hop_index);
|
||||
p += p[1] + 2;
|
||||
}
|
||||
else {
|
||||
len += sprintf(buf + len, "Parse beacon failed at FH param element\n");
|
||||
return len;
|
||||
seq_puts(m, "Parse beacon failed at FH param element\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
len += sprintf(buf + len, "No beacons received\n");
|
||||
seq_puts(m, "No beacons received\n");
|
||||
}
|
||||
return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ray_cs_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ray_cs_proc_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations ray_cs_proc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ray_cs_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
/*===========================================================================*/
|
||||
static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
|
||||
@ -2815,7 +2826,7 @@ static int __init init_ray_cs(void)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
proc_mkdir("driver/ray_cs", NULL);
|
||||
|
||||
create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_read);
|
||||
proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops);
|
||||
raycs_write("driver/ray_cs/essid", write_essid, NULL);
|
||||
raycs_write("driver/ray_cs/net_type", write_int, &net_type);
|
||||
raycs_write("driver/ray_cs/translate", write_int, &translate);
|
||||
|
@ -433,11 +433,9 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
|
||||
|
||||
if (delayed_flags & DELAYED_UPDATE_BEACON) {
|
||||
skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
|
||||
if (skb) {
|
||||
rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
|
||||
&control);
|
||||
if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
|
||||
skb, &control))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (delayed_flags & DELAYED_CONFIG_ERP)
|
||||
|
@ -562,15 +562,9 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
|
||||
u32 intvec;
|
||||
|
||||
intvec = ssb_read32(pdev, SSB_INTVEC);
|
||||
if ((bus->chip_id & 0xFF00) == 0x4400) {
|
||||
/* Workaround: On the BCM44XX the BPFLAG routing
|
||||
* bit is wrong. Use a hardcoded constant. */
|
||||
intvec |= 0x00000002;
|
||||
} else {
|
||||
tmp = ssb_read32(dev, SSB_TPSFLAG);
|
||||
tmp &= SSB_TPSFLAG_BPFLAG;
|
||||
intvec |= (1 << tmp);
|
||||
}
|
||||
tmp = ssb_read32(dev, SSB_TPSFLAG);
|
||||
tmp &= SSB_TPSFLAG_BPFLAG;
|
||||
intvec |= (1 << tmp);
|
||||
ssb_write32(pdev, SSB_INTVEC, intvec);
|
||||
}
|
||||
|
||||
|
@ -1020,8 +1020,7 @@ enum ieee80211_ampdu_mlme_action {
|
||||
* level driver (e.g. assoc/disassoc status, erp parameters).
|
||||
* This function should not be used if no BSS has been set, unless
|
||||
* for association indication. The @changed parameter indicates which
|
||||
* of the bss parameters has changed when a call is made. This callback
|
||||
* has to be atomic.
|
||||
* of the bss parameters has changed when a call is made.
|
||||
*
|
||||
* @configure_filter: Configure the device's RX filter.
|
||||
* See the section "Frame filtering" for more information.
|
||||
|
@ -33,6 +33,8 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return IEEE80211_IF_TYPE_MESH_POINT;
|
||||
#endif
|
||||
case NL80211_IFTYPE_WDS:
|
||||
return IEEE80211_IF_TYPE_WDS;
|
||||
default:
|
||||
return IEEE80211_IF_TYPE_INVALID;
|
||||
}
|
||||
@ -718,12 +720,18 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct sta_info *sta;
|
||||
|
||||
if (mac) {
|
||||
rcu_read_lock();
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
if (!sta)
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
sta_info_unlink(&sta);
|
||||
rcu_read_unlock();
|
||||
|
||||
sta_info_destroy(sta);
|
||||
} else
|
||||
sta_info_flush(local, sdata);
|
||||
@ -740,17 +748,23 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *vlansdata;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* XXX: get sta belonging to dev */
|
||||
sta = sta_info_get(local, mac);
|
||||
if (!sta)
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (params->vlan && params->vlan != sta->sdata->dev) {
|
||||
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
|
||||
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
|
||||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
|
||||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
|
||||
ieee80211_send_layer2_update(sta);
|
||||
@ -758,6 +772,8 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||
|
||||
sta_apply_parameters(local, sta, params);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ struct ieee80211_sta_bss {
|
||||
u64 timestamp;
|
||||
int beacon_int;
|
||||
|
||||
int probe_resp;
|
||||
bool probe_resp;
|
||||
unsigned long last_update;
|
||||
|
||||
/* during assocation, we save an ERP value from a probe response so
|
||||
@ -600,8 +600,7 @@ struct ieee80211_local {
|
||||
/*
|
||||
* The lock only protects the list, hash, timer and counter
|
||||
* against manipulation, reads are done in RCU. Additionally,
|
||||
* the lock protects each BSS's TIM bitmap, a few items in
|
||||
* STA info structures and various key pointers.
|
||||
* the lock protects each BSS's TIM bitmap.
|
||||
*/
|
||||
spinlock_t sta_lock;
|
||||
unsigned long num_sta;
|
||||
@ -635,6 +634,13 @@ struct ieee80211_local {
|
||||
|
||||
struct list_head interfaces;
|
||||
|
||||
/*
|
||||
* Key lock, protects sdata's key_list and sta_info's
|
||||
* key pointers (write access, they're RCU.)
|
||||
*/
|
||||
spinlock_t key_lock;
|
||||
|
||||
|
||||
bool sta_sw_scanning;
|
||||
bool sta_hw_scanning;
|
||||
int scan_channel_idx;
|
||||
|
@ -74,9 +74,12 @@ static void add_todo(struct ieee80211_key *key, u32 flag)
|
||||
|
||||
spin_lock(&todo_lock);
|
||||
key->flags |= flag;
|
||||
/* only add if not already added */
|
||||
if (list_empty(&key->todo))
|
||||
list_add(&key->todo, &todo_list);
|
||||
/*
|
||||
* Remove again if already on the list so that we move it to the end.
|
||||
*/
|
||||
if (!list_empty(&key->todo))
|
||||
list_del(&key->todo);
|
||||
list_add_tail(&key->todo, &todo_list);
|
||||
schedule_work(&todo_work);
|
||||
spin_unlock(&todo_lock);
|
||||
}
|
||||
@ -210,9 +213,9 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sdata->local->sta_lock, flags);
|
||||
spin_lock_irqsave(&sdata->local->key_lock, flags);
|
||||
__ieee80211_set_default_key(sdata, idx);
|
||||
spin_unlock_irqrestore(&sdata->local->sta_lock, flags);
|
||||
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
@ -339,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sdata->local->sta_lock, flags);
|
||||
spin_lock_irqsave(&sdata->local->key_lock, flags);
|
||||
|
||||
if (sta)
|
||||
old_key = sta->key;
|
||||
@ -348,14 +351,26 @@ void ieee80211_key_link(struct ieee80211_key *key,
|
||||
|
||||
__ieee80211_key_replace(sdata, sta, old_key, key);
|
||||
|
||||
spin_unlock_irqrestore(&sdata->local->sta_lock, flags);
|
||||
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
|
||||
|
||||
/* free old key later */
|
||||
add_todo(old_key, KEY_FLAG_TODO_DELETE);
|
||||
|
||||
add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
|
||||
if (netif_running(sdata->dev))
|
||||
add_todo(key, KEY_FLAG_TODO_HWACCEL);
|
||||
add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
|
||||
}
|
||||
|
||||
static void __ieee80211_key_free(struct ieee80211_key *key)
|
||||
{
|
||||
/*
|
||||
* Replace key with nothingness if it was ever used.
|
||||
*/
|
||||
if (key->sdata)
|
||||
__ieee80211_key_replace(key->sdata, key->sta,
|
||||
key, NULL);
|
||||
|
||||
add_todo(key, KEY_FLAG_TODO_DELETE);
|
||||
}
|
||||
|
||||
void ieee80211_key_free(struct ieee80211_key *key)
|
||||
@ -365,51 +380,52 @@ void ieee80211_key_free(struct ieee80211_key *key)
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Replace key with nothingness if it was ever used.
|
||||
*/
|
||||
if (key->sdata) {
|
||||
spin_lock_irqsave(&key->sdata->local->sta_lock, flags);
|
||||
__ieee80211_key_replace(key->sdata, key->sta,
|
||||
key, NULL);
|
||||
spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags);
|
||||
}
|
||||
spin_lock_irqsave(&key->sdata->local->key_lock, flags);
|
||||
__ieee80211_key_free(key);
|
||||
spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
|
||||
}
|
||||
|
||||
add_todo(key, KEY_FLAG_TODO_DELETE);
|
||||
/*
|
||||
* To be safe against concurrent manipulations of the list (which shouldn't
|
||||
* actually happen) we need to hold the spinlock. But under the spinlock we
|
||||
* can't actually do much, so we defer processing to the todo list. Then run
|
||||
* the todo list to be sure the operation and possibly previously pending
|
||||
* operations are completed.
|
||||
*/
|
||||
static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
|
||||
u32 todo_flags)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
unsigned long flags;
|
||||
|
||||
might_sleep();
|
||||
|
||||
spin_lock_irqsave(&sdata->local->key_lock, flags);
|
||||
list_for_each_entry(key, &sdata->key_list, list)
|
||||
add_todo(key, todo_flags);
|
||||
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
|
||||
|
||||
ieee80211_key_todo();
|
||||
}
|
||||
|
||||
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
|
||||
might_sleep();
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (WARN_ON(!netif_running(sdata->dev)))
|
||||
return;
|
||||
|
||||
ieee80211_key_lock();
|
||||
|
||||
list_for_each_entry(key, &sdata->key_list, list)
|
||||
ieee80211_key_enable_hw_accel(key);
|
||||
|
||||
ieee80211_key_unlock();
|
||||
ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
|
||||
}
|
||||
|
||||
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
ASSERT_RTNL();
|
||||
|
||||
might_sleep();
|
||||
|
||||
ieee80211_key_lock();
|
||||
|
||||
list_for_each_entry(key, &sdata->key_list, list)
|
||||
ieee80211_key_disable_hw_accel(key);
|
||||
|
||||
ieee80211_key_unlock();
|
||||
ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
|
||||
}
|
||||
|
||||
static void __ieee80211_key_free(struct ieee80211_key *key)
|
||||
static void __ieee80211_key_destroy(struct ieee80211_key *key)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
@ -440,7 +456,8 @@ static void __ieee80211_key_todo(void)
|
||||
list_del_init(&key->todo);
|
||||
todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
|
||||
KEY_FLAG_TODO_DEFKEY |
|
||||
KEY_FLAG_TODO_HWACCEL |
|
||||
KEY_FLAG_TODO_HWACCEL_ADD |
|
||||
KEY_FLAG_TODO_HWACCEL_REMOVE |
|
||||
KEY_FLAG_TODO_DELETE);
|
||||
key->flags &= ~todoflags;
|
||||
spin_unlock(&todo_lock);
|
||||
@ -456,12 +473,16 @@ static void __ieee80211_key_todo(void)
|
||||
ieee80211_debugfs_key_add_default(key->sdata);
|
||||
work_done = true;
|
||||
}
|
||||
if (todoflags & KEY_FLAG_TODO_HWACCEL) {
|
||||
if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
|
||||
ieee80211_key_enable_hw_accel(key);
|
||||
work_done = true;
|
||||
}
|
||||
if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
|
||||
ieee80211_key_disable_hw_accel(key);
|
||||
work_done = true;
|
||||
}
|
||||
if (todoflags & KEY_FLAG_TODO_DELETE) {
|
||||
__ieee80211_key_free(key);
|
||||
__ieee80211_key_destroy(key);
|
||||
work_done = true;
|
||||
}
|
||||
|
||||
@ -482,14 +503,16 @@ void ieee80211_key_todo(void)
|
||||
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_key *key, *tmp;
|
||||
LIST_HEAD(tmp_list);
|
||||
unsigned long flags;
|
||||
|
||||
ieee80211_key_lock();
|
||||
|
||||
ieee80211_debugfs_key_remove_default(sdata);
|
||||
|
||||
spin_lock_irqsave(&sdata->local->key_lock, flags);
|
||||
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
|
||||
ieee80211_key_free(key);
|
||||
__ieee80211_key_free(key);
|
||||
spin_unlock_irqrestore(&sdata->local->key_lock, flags);
|
||||
|
||||
__ieee80211_key_todo();
|
||||
|
||||
|
@ -54,16 +54,19 @@ struct sta_info;
|
||||
* @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
|
||||
* RCU grace period, no longer be reachable other than from the
|
||||
* todo list.
|
||||
* @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration.
|
||||
* @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
|
||||
* @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
|
||||
* acceleration.
|
||||
* @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
|
||||
* @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
|
||||
*/
|
||||
enum ieee80211_internal_key_flags {
|
||||
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
|
||||
KEY_FLAG_TODO_DELETE = BIT(1),
|
||||
KEY_FLAG_TODO_HWACCEL = BIT(2),
|
||||
KEY_FLAG_TODO_DEFKEY = BIT(3),
|
||||
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4),
|
||||
KEY_FLAG_TODO_HWACCEL_ADD = BIT(2),
|
||||
KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
|
||||
KEY_FLAG_TODO_DEFKEY = BIT(4),
|
||||
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
|
||||
};
|
||||
|
||||
struct ieee80211_key {
|
||||
|
@ -1587,6 +1587,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
|
||||
spin_lock_init(&local->key_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
|
||||
|
||||
sta_info_init(local);
|
||||
|
@ -350,14 +350,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
|
||||
u8 erp_value)
|
||||
static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
|
||||
bool use_protection,
|
||||
bool use_short_preamble)
|
||||
{
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
|
||||
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
|
||||
bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
|
||||
bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
u32 changed = 0;
|
||||
|
||||
@ -388,6 +386,32 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
|
||||
return changed;
|
||||
}
|
||||
|
||||
static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
|
||||
u8 erp_value)
|
||||
{
|
||||
bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
|
||||
bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
|
||||
|
||||
return ieee80211_handle_protect_preamb(sdata,
|
||||
use_protection, use_short_preamble);
|
||||
}
|
||||
|
||||
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_bss *bss)
|
||||
{
|
||||
u32 changed = 0;
|
||||
|
||||
if (bss->has_erp_value)
|
||||
changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
|
||||
else {
|
||||
u16 capab = bss->capability;
|
||||
changed |= ieee80211_handle_protect_preamb(sdata, false,
|
||||
(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct ieee80211_ht_info *ht_info)
|
||||
{
|
||||
@ -511,9 +535,7 @@ static void ieee80211_set_associated(struct net_device *dev,
|
||||
sdata->bss_conf.beacon_int = bss->beacon_int;
|
||||
sdata->bss_conf.timestamp = bss->timestamp;
|
||||
|
||||
if (bss->has_erp_value)
|
||||
changed |= ieee80211_handle_erp_ie(
|
||||
sdata, bss->erp_value);
|
||||
changed |= ieee80211_handle_bss_capability(sdata, bss);
|
||||
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
}
|
||||
@ -2566,22 +2588,29 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
||||
#endif
|
||||
}
|
||||
|
||||
bss->band = rx_status->band;
|
||||
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
|
||||
bss->probe_resp && beacon) {
|
||||
/* STA mode:
|
||||
* Do not allow beacon to override data from Probe Response. */
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
/* save the ERP value so that it is available at association time */
|
||||
if (elems.erp_info && elems.erp_info_len >= 1) {
|
||||
bss->erp_value = elems.erp_info[0];
|
||||
bss->has_erp_value = 1;
|
||||
}
|
||||
|
||||
if (elems.ht_cap_elem &&
|
||||
(!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
|
||||
memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
|
||||
kfree(bss->ht_ie);
|
||||
bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
|
||||
if (bss->ht_ie) {
|
||||
memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
|
||||
elems.ht_cap_elem_len + 2);
|
||||
bss->ht_ie_len = elems.ht_cap_elem_len + 2;
|
||||
} else
|
||||
bss->ht_ie_len = 0;
|
||||
} else if (!elems.ht_cap_elem && bss->ht_ie) {
|
||||
kfree(bss->ht_ie);
|
||||
bss->ht_ie = NULL;
|
||||
bss->ht_ie_len = 0;
|
||||
}
|
||||
|
||||
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
|
||||
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
|
||||
|
||||
@ -2603,6 +2632,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
||||
bss->supp_rates_len += clen;
|
||||
}
|
||||
|
||||
bss->band = rx_status->band;
|
||||
|
||||
bss->timestamp = beacon_timestamp;
|
||||
bss->last_update = jiffies;
|
||||
bss->rssi = rx_status->ssi;
|
||||
bss->signal = rx_status->signal;
|
||||
bss->noise = rx_status->noise;
|
||||
if (!beacon && !bss->probe_resp)
|
||||
bss->probe_resp = true;
|
||||
|
||||
/*
|
||||
* In STA mode, the remaining parameters should not be overridden
|
||||
* by beacons because they're not necessarily accurate there.
|
||||
*/
|
||||
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
|
||||
bss->probe_resp && beacon) {
|
||||
ieee80211_rx_bss_put(dev, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
if (elems.wpa &&
|
||||
(!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
|
||||
memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
|
||||
@ -2635,6 +2684,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
||||
bss->rsn_ie_len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cf.
|
||||
* http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC
|
||||
*
|
||||
* quoting:
|
||||
*
|
||||
* In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia
|
||||
* Applications with Quality of Service in Wi-Fi Networks," Wi- Fi
|
||||
* Alliance (September 1, 2004) is incorporated by reference herein.
|
||||
* The inclusion of the WMM Parameters in probe responses and
|
||||
* association responses is mandatory for WMM enabled networks. The
|
||||
* inclusion of the WMM Parameters in beacons, however, is optional.
|
||||
*/
|
||||
|
||||
if (elems.wmm_param &&
|
||||
(!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
|
||||
memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
|
||||
@ -2651,30 +2714,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
|
||||
bss->wmm_ie = NULL;
|
||||
bss->wmm_ie_len = 0;
|
||||
}
|
||||
if (elems.ht_cap_elem &&
|
||||
(!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
|
||||
memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
|
||||
kfree(bss->ht_ie);
|
||||
bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
|
||||
if (bss->ht_ie) {
|
||||
memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
|
||||
elems.ht_cap_elem_len + 2);
|
||||
bss->ht_ie_len = elems.ht_cap_elem_len + 2;
|
||||
} else
|
||||
bss->ht_ie_len = 0;
|
||||
} else if (!elems.ht_cap_elem && bss->ht_ie) {
|
||||
kfree(bss->ht_ie);
|
||||
bss->ht_ie = NULL;
|
||||
bss->ht_ie_len = 0;
|
||||
}
|
||||
|
||||
bss->timestamp = beacon_timestamp;
|
||||
bss->last_update = jiffies;
|
||||
bss->rssi = rx_status->ssi;
|
||||
bss->signal = rx_status->signal;
|
||||
bss->noise = rx_status->noise;
|
||||
if (!beacon)
|
||||
bss->probe_resp++;
|
||||
|
||||
/* check if we need to merge IBSS */
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
|
||||
@ -2775,8 +2814,24 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
|
||||
|
||||
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
|
||||
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
|
||||
elems.wmm_param_len);
|
||||
}
|
||||
|
||||
/* Do not send changes to driver if we are scanning. This removes
|
||||
* requirement that driver's bss_info_changed function needs to be
|
||||
* atomic. */
|
||||
if (local->sta_sw_scanning || local->sta_hw_scanning)
|
||||
return;
|
||||
|
||||
if (elems.erp_info && elems.erp_info_len >= 1)
|
||||
changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
|
||||
else {
|
||||
u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info);
|
||||
changed |= ieee80211_handle_protect_preamb(sdata, false,
|
||||
(capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
|
||||
}
|
||||
|
||||
if (elems.ht_cap_elem && elems.ht_info_elem &&
|
||||
elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
|
||||
@ -2789,11 +2844,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
|
||||
&bss_info);
|
||||
}
|
||||
|
||||
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
|
||||
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
|
||||
elems.wmm_param_len);
|
||||
}
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
}
|
||||
|
||||
|
@ -236,6 +236,9 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
|
||||
case IW_MODE_ADHOC:
|
||||
type = IEEE80211_IF_TYPE_IBSS;
|
||||
break;
|
||||
case IW_MODE_REPEAT:
|
||||
type = IEEE80211_IF_TYPE_WDS;
|
||||
break;
|
||||
case IW_MODE_MONITOR:
|
||||
type = IEEE80211_IF_TYPE_MNTR;
|
||||
break;
|
||||
@ -980,6 +983,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
|
||||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
|
||||
sta = sta_info_get(local, sdata->u.sta.bssid);
|
||||
@ -996,6 +1001,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
|
||||
wstats->qual.noise = sta->last_noise;
|
||||
wstats->qual.updated = local->wstats_flags;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return wstats;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user