Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

This commit is contained in:
John W. Linville 2013-05-29 14:50:45 -04:00
commit 531efffc3e
70 changed files with 2910 additions and 549 deletions

View File

@ -2369,6 +2369,9 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
int i;
bool needreset = false;
if (!test_bit(ATH_STAT_STARTED, ah->status))
return;
mutex_lock(&ah->lock);
for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) {
@ -2676,6 +2679,7 @@ done:
mmiowb();
mutex_unlock(&ah->lock);
set_bit(ATH_STAT_STARTED, ah->status);
ieee80211_queue_delayed_work(ah->hw, &ah->tx_complete_work,
msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
@ -2737,6 +2741,7 @@ void ath5k_stop(struct ieee80211_hw *hw)
ath5k_stop_tasklets(ah);
clear_bit(ATH_STAT_STARTED, ah->status);
cancel_delayed_work_sync(&ah->tx_complete_work);
if (!ath5k_modparam_no_hw_rfkill_switch)

View File

@ -233,9 +233,9 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
{0x00009d10, 0x01834061},
{0x00009d14, 0x00c00400},
{0x00009d18, 0x00000000},
{0x00009e08, 0x0078230c},
{0x00009e24, 0x990bb515},
{0x00009e28, 0x126f0000},
{0x00009e08, 0x0038230c},
{0x00009e24, 0x9907b515},
{0x00009e28, 0x126f0600},
{0x00009e30, 0x06336f77},
{0x00009e34, 0x6af6532f},
{0x00009e38, 0x0cc80c00},
@ -337,7 +337,7 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
static const u32 ar9565_1p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a800d},
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8009},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x09143c81},
@ -345,9 +345,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
{0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
{0x00009e04, 0x00802020, 0x00802020, 0x00142020, 0x00142020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
@ -450,6 +450,8 @@ static const u32 ar9565_1p0_soc_postamble[][5] = {
static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
/* Addr allmodes */
{0x00004050, 0x00300300},
{0x0000406c, 0x00100000},
{0x0000a000, 0x00010000},
{0x0000a004, 0x00030002},
{0x0000a008, 0x00050004},
@ -498,27 +500,27 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
{0x0000a0b4, 0x00000000},
{0x0000a0b8, 0x00000000},
{0x0000a0bc, 0x00000000},
{0x0000a0c0, 0x001f0000},
{0x0000a0c4, 0x01000101},
{0x0000a0c8, 0x011e011f},
{0x0000a0cc, 0x011c011d},
{0x0000a0d0, 0x02030204},
{0x0000a0d4, 0x02010202},
{0x0000a0d8, 0x021f0200},
{0x0000a0dc, 0x0302021e},
{0x0000a0e0, 0x03000301},
{0x0000a0e4, 0x031e031f},
{0x0000a0e8, 0x0402031d},
{0x0000a0ec, 0x04000401},
{0x0000a0f0, 0x041e041f},
{0x0000a0f4, 0x0502041d},
{0x0000a0f8, 0x05000501},
{0x0000a0fc, 0x051e051f},
{0x0000a100, 0x06010602},
{0x0000a104, 0x061f0600},
{0x0000a108, 0x061d061e},
{0x0000a10c, 0x07020703},
{0x0000a110, 0x07000701},
{0x0000a0c0, 0x00bf00a0},
{0x0000a0c4, 0x11a011a1},
{0x0000a0c8, 0x11be11bf},
{0x0000a0cc, 0x11bc11bd},
{0x0000a0d0, 0x22632264},
{0x0000a0d4, 0x22612262},
{0x0000a0d8, 0x227f2260},
{0x0000a0dc, 0x4322227e},
{0x0000a0e0, 0x43204321},
{0x0000a0e4, 0x433e433f},
{0x0000a0e8, 0x4462433d},
{0x0000a0ec, 0x44604461},
{0x0000a0f0, 0x447e447f},
{0x0000a0f4, 0x5582447d},
{0x0000a0f8, 0x55805581},
{0x0000a0fc, 0x559e559f},
{0x0000a100, 0x66816682},
{0x0000a104, 0x669f6680},
{0x0000a108, 0x669d669e},
{0x0000a10c, 0x77627763},
{0x0000a110, 0x77607761},
{0x0000a114, 0x00000000},
{0x0000a118, 0x00000000},
{0x0000a11c, 0x00000000},
@ -530,27 +532,27 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
{0x0000a134, 0x00000000},
{0x0000a138, 0x00000000},
{0x0000a13c, 0x00000000},
{0x0000a140, 0x001f0000},
{0x0000a144, 0x01000101},
{0x0000a148, 0x011e011f},
{0x0000a14c, 0x011c011d},
{0x0000a150, 0x02030204},
{0x0000a154, 0x02010202},
{0x0000a158, 0x021f0200},
{0x0000a15c, 0x0302021e},
{0x0000a160, 0x03000301},
{0x0000a164, 0x031e031f},
{0x0000a168, 0x0402031d},
{0x0000a16c, 0x04000401},
{0x0000a170, 0x041e041f},
{0x0000a174, 0x0502041d},
{0x0000a178, 0x05000501},
{0x0000a17c, 0x051e051f},
{0x0000a180, 0x06010602},
{0x0000a184, 0x061f0600},
{0x0000a188, 0x061d061e},
{0x0000a18c, 0x07020703},
{0x0000a190, 0x07000701},
{0x0000a140, 0x00bf00a0},
{0x0000a144, 0x11a011a1},
{0x0000a148, 0x11be11bf},
{0x0000a14c, 0x11bc11bd},
{0x0000a150, 0x22632264},
{0x0000a154, 0x22612262},
{0x0000a158, 0x227f2260},
{0x0000a15c, 0x4322227e},
{0x0000a160, 0x43204321},
{0x0000a164, 0x433e433f},
{0x0000a168, 0x4462433d},
{0x0000a16c, 0x44604461},
{0x0000a170, 0x447e447f},
{0x0000a174, 0x5582447d},
{0x0000a178, 0x55805581},
{0x0000a17c, 0x559e559f},
{0x0000a180, 0x66816682},
{0x0000a184, 0x669f6680},
{0x0000a188, 0x669d669e},
{0x0000a18c, 0x77e677e7},
{0x0000a190, 0x77e477e5},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
@ -770,7 +772,7 @@ static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = {
static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18213ede},
{0x00018c00, 0x18212ede},
{0x00018c04, 0x000801d8},
{0x00018c08, 0x0003780c},
};
@ -889,8 +891,8 @@ static const u32 ar9565_1p0_common_wo_xlna_rx_gain_table[][2] = {
{0x0000a180, 0x66816682},
{0x0000a184, 0x669f6680},
{0x0000a188, 0x669d669e},
{0x0000a18c, 0x77627763},
{0x0000a190, 0x77607761},
{0x0000a18c, 0x77e677e7},
{0x0000a190, 0x77e477e5},
{0x0000a194, 0x00000000},
{0x0000a198, 0x00000000},
{0x0000a19c, 0x00000000},
@ -1114,7 +1116,7 @@ static const u32 ar9565_1p0_modes_high_ob_db_tx_gain_table[][5] = {
{0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84},
{0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000},
{0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050df, 0x000050df},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
{0x0000a508, 0x0b022220, 0x0b022220, 0x08000004, 0x08000004},
@ -1140,13 +1142,13 @@ static const u32 ar9565_1p0_modes_high_ob_db_tx_gain_table[][5] = {
{0x0000a558, 0x69027f56, 0x69027f56, 0x53001ce5, 0x53001ce5},
{0x0000a55c, 0x6d029f56, 0x6d029f56, 0x57001ce9, 0x57001ce9},
{0x0000a560, 0x73049f56, 0x73049f56, 0x5b001ceb, 0x5b001ceb},
{0x0000a564, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x7804ff56, 0x7804ff56, 0x5d001eec, 0x5d001eec},
{0x0000a564, 0x7804ff56, 0x7804ff56, 0x60001cf0, 0x60001cf0},
{0x0000a568, 0x7804ff56, 0x7804ff56, 0x61001cf1, 0x61001cf1},
{0x0000a56c, 0x7804ff56, 0x7804ff56, 0x62001cf2, 0x62001cf2},
{0x0000a570, 0x7804ff56, 0x7804ff56, 0x63001cf3, 0x63001cf3},
{0x0000a574, 0x7804ff56, 0x7804ff56, 0x64001cf4, 0x64001cf4},
{0x0000a578, 0x7804ff56, 0x7804ff56, 0x66001ff6, 0x66001ff6},
{0x0000a57c, 0x7804ff56, 0x7804ff56, 0x66001ff6, 0x66001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@ -1174,7 +1176,7 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = {
{0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84},
{0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000},
{0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050df, 0x000050df},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
{0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
@ -1200,13 +1202,13 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = {
{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
{0x0000a564, 0x7504ff56, 0x7504ff56, 0x59001cf0, 0x59001cf0},
{0x0000a568, 0x7504ff56, 0x7504ff56, 0x5a001cf1, 0x5a001cf1},
{0x0000a56c, 0x7504ff56, 0x7504ff56, 0x5b001cf2, 0x5b001cf2},
{0x0000a570, 0x7504ff56, 0x7504ff56, 0x5c001cf3, 0x5c001cf3},
{0x0000a574, 0x7504ff56, 0x7504ff56, 0x5d001cf4, 0x5d001cf4},
{0x0000a578, 0x7504ff56, 0x7504ff56, 0x5f001ff6, 0x5f001ff6},
{0x0000a57c, 0x7504ff56, 0x7504ff56, 0x5f001ff6, 0x5f001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},

View File

@ -226,13 +226,13 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
goto work;
ath9k_set_beacon(sc);
if (ah->opmode == NL80211_IFTYPE_STATION &&
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
} else {
ath9k_set_beacon(sc);
}
work:
ath_restart_work(sc);
@ -1331,6 +1331,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_node *an = (struct ath_node *) sta->drv_priv;
struct ieee80211_key_conf ps_key = { };
int key;
ath_node_attach(sc, sta, vif);
@ -1338,7 +1339,9 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
vif->type != NL80211_IFTYPE_AP_VLAN)
return 0;
an->ps_key = ath_key_config(common, vif, sta, &ps_key);
key = ath_key_config(common, vif, sta, &ps_key);
if (key > 0)
an->ps_key = key;
return 0;
}
@ -1355,6 +1358,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc,
return;
ath_key_delete(common, &ps_key);
an->ps_key = 0;
}
static int ath9k_sta_remove(struct ieee80211_hw *hw,

View File

@ -1728,6 +1728,25 @@ drop_recycle_buffer:
sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
}
void b43_dma_handle_rx_overflow(struct b43_dmaring *ring)
{
int current_slot, previous_slot;
B43_WARN_ON(ring->tx);
/* Device has filled all buffers, drop all packets and let TCP
* decrease speed.
* Decrement RX index by one will let the device to see all slots
* as free again
*/
/*
*TODO: How to increase rx_drop in mac80211?
*/
current_slot = ring->ops->get_current_rxslot(ring);
previous_slot = prev_slot(ring, current_slot);
ring->ops->set_current_rxslot(ring, previous_slot);
}
void b43_dma_rx(struct b43_dmaring *ring)
{
const struct b43_dma_ops *ops = ring->ops;

View File

@ -9,7 +9,7 @@
/* DMA-Interrupt reasons. */
#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
| (1 << 14) | (1 << 15))
#define B43_DMAIRQ_NONFATALMASK (1 << 13)
#define B43_DMAIRQ_RDESC_UFLOW (1 << 13)
#define B43_DMAIRQ_RX_DONE (1 << 16)
/*** 32-bit DMA Engine. ***/
@ -295,6 +295,8 @@ int b43_dma_tx(struct b43_wldev *dev,
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_dma_handle_rx_overflow(struct b43_dmaring *ring);
void b43_dma_rx(struct b43_dmaring *ring);
void b43_dma_direct_fifo_rx(struct b43_wldev *dev,

View File

@ -1902,30 +1902,18 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
}
}
if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
B43_DMAIRQ_NONFATALMASK))) {
if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
b43err(dev->wl, "Fatal DMA error: "
"0x%08X, 0x%08X, 0x%08X, "
"0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
b43err(dev->wl, "This device does not support DMA "
if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK))) {
b43err(dev->wl,
"Fatal DMA error: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
b43err(dev->wl, "This device does not support DMA "
"on your system. It will now be switched to PIO.\n");
/* Fall back to PIO transfers if we get fatal DMA errors! */
dev->use_pio = true;
b43_controller_restart(dev, "DMA error");
return;
}
if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
b43err(dev->wl, "DMA error: "
"0x%08X, 0x%08X, 0x%08X, "
"0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
}
/* Fall back to PIO transfers if we get fatal DMA errors! */
dev->use_pio = true;
b43_controller_restart(dev, "DMA error");
return;
}
if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
@ -1944,6 +1932,11 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
handle_irq_noise(dev);
/* Check the DMA reason registers for received data. */
if (dma_reason[0] & B43_DMAIRQ_RDESC_UFLOW) {
if (B43_DEBUG)
b43warn(dev->wl, "RX descriptor underrun\n");
b43_dma_handle_rx_overflow(dev->dma.rx_ring);
}
if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
if (b43_using_pio_transfers(dev))
b43_pio_rx(dev->pio.rx_queue);
@ -2001,7 +1994,7 @@ static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
return IRQ_NONE;
dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
& 0x0001DC00;
& 0x0001FC00;
dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
& 0x0000DC00;
dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
@ -3130,7 +3123,7 @@ static int b43_chip_init(struct b43_wldev *dev)
b43_write32(dev, 0x018C, 0x02000000);
}
b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001FC00);
b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);

View File

@ -5741,8 +5741,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->flags =
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N)
hw->flags |=
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |

View File

@ -76,13 +76,16 @@
#define IWL_INVALID_STATION 255
/* device operations */
extern struct iwl_lib_ops iwl1000_lib;
extern struct iwl_lib_ops iwl2000_lib;
extern struct iwl_lib_ops iwl2030_lib;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_lib_ops iwl5150_lib;
extern struct iwl_lib_ops iwl6000_lib;
extern struct iwl_lib_ops iwl6030_lib;
extern const struct iwl_dvm_cfg iwl_dvm_1000_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_2000_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_105_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_2030_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_5000_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_5150_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6000_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6005_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6050_cfg;
extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
#define TIME_UNIT 1024
@ -291,8 +294,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
{
return priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist;
return priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist;
}
#ifdef CONFIG_IWLWIFI_DEBUG

View File

@ -521,7 +521,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
if (priv->cfg->base_params->hd_v2) {
if (priv->lib->hd_v2) {
cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
@ -895,7 +895,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
continue;
}
delta_g = (priv->cfg->base_params->chain_noise_scale *
delta_g = (priv->lib->chain_noise_scale *
((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500;
@ -1051,8 +1051,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
return;
/* Analyze signal for disconnected antenna */
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
/* Disable disconnected antenna algorithm for advanced
bt coex, assuming valid antennas are connected */
data->active_chains = priv->nvm_data->valid_rx_ant;

View File

@ -838,10 +838,6 @@ struct iwl_qosparam_cmd {
#define STA_MODIFY_DELBA_TID_MSK 0x10
#define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20
/* Receiver address (actually, Rx station's index into station table),
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
/* agn */
struct iwl_keyinfo {
__le16 key_flags;

View File

@ -568,16 +568,61 @@ struct iwl_hw_params {
const struct iwl_sensitivity_ranges *sens;
};
struct iwl_lib_ops {
/* set hw dependent parameters */
/**
* struct iwl_dvm_bt_params - DVM specific BT (coex) parameters
* @advanced_bt_coexist: support advanced bt coexist
* @bt_init_traffic_load: specify initial bt traffic load
* @bt_prio_boost: default bt priority boost value
* @agg_time_limit: maximum number of uSec in aggregation
* @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
*/
struct iwl_dvm_bt_params {
bool advanced_bt_coexist;
u8 bt_init_traffic_load;
u32 bt_prio_boost;
u16 agg_time_limit;
bool bt_sco_disable;
bool bt_session_2;
};
/**
* struct iwl_dvm_cfg - DVM firmware specific device configuration
* @set_hw_params: set hardware parameters
* @set_channel_switch: send channel switch command
* @nic_config: apply device specific configuration
* @temperature: read temperature
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
* @plcp_delta_threshold: plcp error rate threshold used to trigger
* radio tuning when there is a high receiving plcp error rate
* @chain_noise_scale: default chain noise scale used for gain computation
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
* @no_idle_support: do not support idle mode
* @bt_params: pointer to BT parameters
* @need_temp_offset_calib: need to perform temperature offset calibration
* @no_xtal_calib: some devices do not need crystal calibration data,
* don't send it to those
* @temp_offset_v2: support v2 of temperature offset calibration
* @adv_pm: advanced power management
*/
struct iwl_dvm_cfg {
void (*set_hw_params)(struct iwl_priv *priv);
int (*set_channel_switch)(struct iwl_priv *priv,
struct ieee80211_channel_switch *ch_switch);
/* device specific configuration */
void (*nic_config)(struct iwl_priv *priv);
/* temperature */
void (*temperature)(struct iwl_priv *priv);
const struct iwl_dvm_bt_params *bt_params;
s32 chain_noise_scale;
u8 plcp_delta_threshold;
bool adv_thermal_throttle;
bool support_ct_kill_exit;
bool hd_v2;
bool no_idle_support;
bool need_temp_offset_calib;
bool no_xtal_calib;
bool temp_offset_v2;
bool adv_pm;
};
struct iwl_wipan_noa_data {
@ -610,7 +655,7 @@ struct iwl_priv {
struct device *dev; /* for debug prints only */
const struct iwl_cfg *cfg;
const struct iwl_fw *fw;
const struct iwl_lib_ops *lib;
const struct iwl_dvm_cfg *lib;
unsigned long status;
spinlock_t sta_lock;

View File

@ -174,10 +174,13 @@ static void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.sens = &iwl1000_sensitivity;
}
struct iwl_lib_ops iwl1000_lib = {
const struct iwl_dvm_cfg iwl_dvm_1000_cfg = {
.set_hw_params = iwl1000_hw_set_hw_params,
.nic_config = iwl1000_nic_config,
.temperature = iwlagn_temperature,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
};
@ -232,16 +235,56 @@ static void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.sens = &iwl2000_sensitivity;
}
struct iwl_lib_ops iwl2000_lib = {
const struct iwl_dvm_cfg iwl_dvm_2000_cfg = {
.set_hw_params = iwl2000_hw_set_hw_params,
.nic_config = iwl2000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.hd_v2 = true,
.need_temp_offset_calib = true,
.temp_offset_v2 = true,
};
struct iwl_lib_ops iwl2030_lib = {
const struct iwl_dvm_cfg iwl_dvm_105_cfg = {
.set_hw_params = iwl2000_hw_set_hw_params,
.nic_config = iwl2000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.hd_v2 = true,
.need_temp_offset_calib = true,
.temp_offset_v2 = true,
.adv_pm = true,
};
static const struct iwl_dvm_bt_params iwl2030_bt_params = {
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32,
.bt_sco_disable = true,
.bt_session_2 = true,
};
const struct iwl_dvm_cfg iwl_dvm_2030_cfg = {
.set_hw_params = iwl2000_hw_set_hw_params,
.nic_config = iwl2000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.hd_v2 = true,
.bt_params = &iwl2030_bt_params,
.need_temp_offset_calib = true,
.temp_offset_v2 = true,
.adv_pm = true,
};
/*
@ -420,16 +463,23 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
return iwl_dvm_send_cmd(priv, &hcmd);
}
struct iwl_lib_ops iwl5000_lib = {
const struct iwl_dvm_cfg iwl_dvm_5000_cfg = {
.set_hw_params = iwl5000_hw_set_hw_params,
.set_channel_switch = iwl5000_hw_channel_switch,
.temperature = iwlagn_temperature,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.no_idle_support = true,
};
struct iwl_lib_ops iwl5150_lib = {
const struct iwl_dvm_cfg iwl_dvm_5150_cfg = {
.set_hw_params = iwl5150_hw_set_hw_params,
.set_channel_switch = iwl5000_hw_channel_switch,
.temperature = iwl5150_temperature,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.no_idle_support = true,
.no_xtal_calib = true,
};
@ -584,16 +634,59 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
return err;
}
struct iwl_lib_ops iwl6000_lib = {
const struct iwl_dvm_cfg iwl_dvm_6000_cfg = {
.set_hw_params = iwl6000_hw_set_hw_params,
.set_channel_switch = iwl6000_hw_channel_switch,
.nic_config = iwl6000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
};
struct iwl_lib_ops iwl6030_lib = {
const struct iwl_dvm_cfg iwl_dvm_6005_cfg = {
.set_hw_params = iwl6000_hw_set_hw_params,
.set_channel_switch = iwl6000_hw_channel_switch,
.nic_config = iwl6000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.need_temp_offset_calib = true,
};
const struct iwl_dvm_cfg iwl_dvm_6050_cfg = {
.set_hw_params = iwl6000_hw_set_hw_params,
.set_channel_switch = iwl6000_hw_channel_switch,
.nic_config = iwl6000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1500,
};
static const struct iwl_dvm_bt_params iwl6000_bt_params = {
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
.bt_sco_disable = true,
};
const struct iwl_dvm_cfg iwl_dvm_6030_cfg = {
.set_hw_params = iwl6000_hw_set_hw_params,
.set_channel_switch = iwl6000_hw_channel_switch,
.nic_config = iwl6000_nic_config,
.temperature = iwlagn_temperature,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.bt_params = &iwl6000_bt_params,
.need_temp_offset_calib = true,
.adv_pm = true,
};

View File

@ -254,23 +254,23 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
sizeof(basic.bt3_lookup_table));
if (priv->cfg->bt_params) {
if (priv->lib->bt_params) {
/*
* newer generation of devices (2000 series and newer)
* use the version 2 of the bt command
* we need to make sure sending the host command
* with correct data structure to avoid uCode assert
*/
if (priv->cfg->bt_params->bt_session_2) {
if (priv->lib->bt_params->bt_session_2) {
bt_cmd_v2.prio_boost = cpu_to_le32(
priv->cfg->bt_params->bt_prio_boost);
priv->lib->bt_params->bt_prio_boost);
bt_cmd_v2.tx_prio_boost = 0;
bt_cmd_v2.rx_prio_boost = 0;
} else {
/* older version only has 8 bits */
WARN_ON(priv->cfg->bt_params->bt_prio_boost & ~0xFF);
WARN_ON(priv->lib->bt_params->bt_prio_boost & ~0xFF);
bt_cmd_v1.prio_boost =
priv->cfg->bt_params->bt_prio_boost;
priv->lib->bt_params->bt_prio_boost;
bt_cmd_v1.tx_prio_boost = 0;
bt_cmd_v1.rx_prio_boost = 0;
}
@ -330,7 +330,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
priv->bt_full_concurrent ?
"full concurrency" : "3-wire");
if (priv->cfg->bt_params->bt_session_2) {
if (priv->lib->bt_params->bt_session_2) {
memcpy(&bt_cmd_v2.basic, &basic,
sizeof(basic));
ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
@ -758,8 +758,8 @@ static bool is_single_rx_stream(struct iwl_priv *priv)
*/
static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
(priv->bt_full_concurrent ||
priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
/*
@ -830,8 +830,8 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
else
active_chains = priv->nvm_data->valid_rx_ant;
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
(priv->bt_full_concurrent ||
priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
/*

View File

@ -426,6 +426,10 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
if (ret)
goto error;
/* let the ucode operate on its own */
iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
iwl_trans_d3_suspend(priv->trans);
goto out;
@ -509,6 +513,10 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
goto out_unlock;
}
/* uCode is no longer operating by itself */
iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
base = priv->device_pointers.error_event_table;
if (!iwlagn_hw_valid_rtc_data_addr(base)) {
IWL_WARN(priv, "Invalid error table during resume!\n");
@ -1276,8 +1284,8 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->mutex);
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
if (rssi_event == RSSI_EVENT_LOW)
priv->bt_enable_pspoll = true;
else if (rssi_event == RSSI_EVENT_HIGH)
@ -1387,7 +1395,7 @@ static int iwl_setup_interface(struct iwl_priv *priv,
return err;
}
if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist &&
vif->type == NL80211_IFTYPE_ADHOC) {
/*
* pretend to have high BT traffic as long as we

View File

@ -615,7 +615,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
priv->thermal_throttle.ct_kill_toggle = false;
if (priv->cfg->base_params->support_ct_kill_exit) {
if (priv->lib->support_ct_kill_exit) {
adv_cmd.critical_temperature_enter =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
adv_cmd.critical_temperature_exit =
@ -732,10 +732,10 @@ int iwl_alive_start(struct iwl_priv *priv)
}
/* download priority table before any calibration request */
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
/* Configure Bluetooth device coexistence support */
if (priv->cfg->bt_params->bt_sco_disable)
if (priv->lib->bt_params->bt_sco_disable)
priv->bt_enable_pspoll = false;
else
priv->bt_enable_pspoll = true;
@ -873,9 +873,9 @@ void iwl_down(struct iwl_priv *priv)
priv->bt_status = 0;
priv->cur_rssi_ctx = NULL;
priv->bt_is_sco = 0;
if (priv->cfg->bt_params)
if (priv->lib->bt_params)
priv->bt_traffic_load =
priv->cfg->bt_params->bt_init_traffic_load;
priv->lib->bt_params->bt_init_traffic_load;
else
priv->bt_traffic_load = 0;
priv->bt_full_concurrent = false;
@ -1058,7 +1058,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
iwl_setup_scan_deferred_work(priv);
if (priv->cfg->bt_params)
if (priv->lib->bt_params)
iwlagn_bt_setup_deferred_work(priv);
init_timer(&priv->statistics_periodic);
@ -1072,7 +1072,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
void iwl_cancel_deferred_work(struct iwl_priv *priv)
{
if (priv->cfg->bt_params)
if (priv->lib->bt_params)
iwlagn_bt_cancel_deferred_work(priv);
cancel_work_sync(&priv->run_time_calib_work);
@ -1098,8 +1098,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->band = IEEE80211_BAND_2GHZ;
priv->plcp_delta_threshold =
priv->cfg->base_params->plcp_delta_threshold;
priv->plcp_delta_threshold = priv->lib->plcp_delta_threshold;
priv->iw_mode = NL80211_IFTYPE_STATION;
priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
@ -1116,8 +1115,8 @@ static int iwl_init_drv(struct iwl_priv *priv)
iwl_init_scan_params(priv);
/* init bt coex */
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
@ -1264,31 +1263,37 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
switch (priv->cfg->device_family) {
case IWL_DEVICE_FAMILY_1000:
case IWL_DEVICE_FAMILY_100:
priv->lib = &iwl1000_lib;
priv->lib = &iwl_dvm_1000_cfg;
break;
case IWL_DEVICE_FAMILY_2000:
priv->lib = &iwl_dvm_2000_cfg;
break;
case IWL_DEVICE_FAMILY_105:
priv->lib = &iwl2000_lib;
priv->lib = &iwl_dvm_105_cfg;
break;
case IWL_DEVICE_FAMILY_2030:
case IWL_DEVICE_FAMILY_135:
priv->lib = &iwl2030_lib;
priv->lib = &iwl_dvm_2030_cfg;
break;
case IWL_DEVICE_FAMILY_5000:
priv->lib = &iwl5000_lib;
priv->lib = &iwl_dvm_5000_cfg;
break;
case IWL_DEVICE_FAMILY_5150:
priv->lib = &iwl5150_lib;
priv->lib = &iwl_dvm_5150_cfg;
break;
case IWL_DEVICE_FAMILY_6000:
case IWL_DEVICE_FAMILY_6005:
case IWL_DEVICE_FAMILY_6000i:
priv->lib = &iwl_dvm_6000_cfg;
break;
case IWL_DEVICE_FAMILY_6005:
priv->lib = &iwl_dvm_6005_cfg;
break;
case IWL_DEVICE_FAMILY_6050:
case IWL_DEVICE_FAMILY_6150:
priv->lib = &iwl6000_lib;
priv->lib = &iwl_dvm_6050_cfg;
break;
case IWL_DEVICE_FAMILY_6030:
priv->lib = &iwl6030_lib;
priv->lib = &iwl_dvm_6030_cfg;
break;
default:
break;

View File

@ -163,7 +163,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
u8 skip;
u32 slp_itrvl;
if (priv->cfg->adv_pm) {
if (priv->lib->adv_pm) {
table = apm_range_2;
if (period <= IWL_DTIM_RANGE_1_MAX)
table = apm_range_1;
@ -217,7 +217,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
if (iwl_advanced_bt_coexist(priv)) {
if (!priv->cfg->bt_params->bt_sco_disable)
if (!priv->lib->bt_params->bt_sco_disable)
cmd->flags |= IWL_POWER_BT_SCO_ENA;
else
cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
@ -293,7 +293,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
if (priv->wowlan)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
else if (!priv->cfg->base_params->no_idle_support &&
else if (!priv->lib->no_idle_support &&
priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
else if (iwl_tt_is_low_power_state(priv)) {

View File

@ -1088,7 +1088,7 @@ done:
(priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
rs_program_fix_rate(priv, lq_sta);
#endif
if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist)
rs_bt_update_lq(priv, ctx, lq_sta);
}
@ -3064,11 +3064,11 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
* overwrite if needed, pass aggregation time limit
* to uCode in uSec
*/
if (priv && priv->cfg->bt_params &&
priv->cfg->bt_params->agg_time_limit &&
if (priv && priv->lib->bt_params &&
priv->lib->bt_params->agg_time_limit &&
priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
lq_cmd->agg_params.agg_time_limit =
cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
cpu_to_le16(priv->lib->bt_params->agg_time_limit);
}
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)

View File

@ -1102,7 +1102,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
iwl_notification_wait_init(&priv->notif_wait);
/* Set up BT Rx handlers */
if (priv->cfg->bt_params)
if (priv->lib->bt_params)
iwlagn_bt_rx_handler_setup(priv);
}

View File

@ -801,8 +801,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
* Internal scans are passive, so we can indiscriminately set
* the BT ignore flag on 2.4 GHz since it applies to TX only.
*/
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist)
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist)
scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
break;
case IEEE80211_BAND_5GHZ:
@ -844,8 +844,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
band = priv->scan_band;
if (band == IEEE80211_BAND_2GHZ &&
priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
/* transmit 2.4 GHz probes only on first antenna */
scan_tx_antennas = first_antenna(scan_tx_antennas);
}
@ -873,8 +873,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
rx_ant = first_antenna(active_chains);
}
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
rx_ant = first_antenna(rx_ant);

View File

@ -735,7 +735,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
memcpy(&lq, priv->stations[i].lq,
sizeof(struct iwl_link_quality_cmd));
if (!memcmp(&lq, &zero_lq, sizeof(lq)))
if (memcmp(&lq, &zero_lq, sizeof(lq)))
send_lq = true;
}
spin_unlock_bh(&priv->sta_lock);

View File

@ -627,7 +627,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
if (priv->cfg->base_params->adv_thermal_throttle) {
if (priv->lib->adv_thermal_throttle) {
IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
tt->restriction = kcalloc(IWL_TI_STATE_MAX,
sizeof(struct iwl_tt_restriction),

View File

@ -83,8 +83,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
else if (ieee80211_is_back_req(fc))
tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
else if (info->band == IEEE80211_BAND_2GHZ &&
priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
(ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
ieee80211_is_reassoc_req(fc) ||
skb->protocol == cpu_to_be16(ETH_P_PAE)))
@ -202,8 +202,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
rate_flags |= RATE_MCS_CCK_MSK;
/* Set up antennas */
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
@ -986,8 +986,8 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
* notification again.
*/
if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
}

View File

@ -132,8 +132,8 @@ int iwl_init_alive_start(struct iwl_priv *priv)
{
int ret;
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
/*
* Tell uCode we are ready to perform calibration
* need to perform this before any calibration
@ -155,8 +155,8 @@ int iwl_init_alive_start(struct iwl_priv *priv)
* temperature offset calibration is only needed for runtime ucode,
* so prepare the value now.
*/
if (priv->cfg->need_temp_offset_calib) {
if (priv->cfg->temp_offset_v2)
if (priv->lib->need_temp_offset_calib) {
if (priv->lib->temp_offset_v2)
return iwl_set_temperature_offset_calib_v2(priv);
else
return iwl_set_temperature_offset_calib(priv);
@ -277,7 +277,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
if (ret)
return ret;
if (!priv->cfg->no_xtal_calib) {
if (!priv->lib->no_xtal_calib) {
ret = iwl_set_Xtal_calib(priv);
if (ret)
return ret;

View File

@ -60,9 +60,6 @@ static const struct iwl_base_params iwl1000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
.led_compensation = 51,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_WATCHDOG_DISABLED,
.max_event_log_size = 128,
};

View File

@ -72,14 +72,9 @@ static const struct iwl_base_params iwl2000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 51,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
.hd_v2 = true,
};
@ -90,14 +85,9 @@ static const struct iwl_base_params iwl2030_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 57,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
.hd_v2 = true,
};
static const struct iwl_ht_params iwl2000_ht_params = {
@ -106,16 +96,6 @@ static const struct iwl_ht_params iwl2000_ht_params = {
.ht40_bands = BIT(IEEE80211_BAND_2GHZ),
};
static const struct iwl_bt_params iwl2030_bt_params = {
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32,
.bt_sco_disable = true,
.bt_session_2 = true,
};
static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
.regulatory_bands = {
EEPROM_REG_BAND_1_CHANNELS,
@ -137,12 +117,10 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
.device_family = IWL_DEVICE_FAMILY_2000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.nvm_ver = EEPROM_2000_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.nvm_ver = EEPROM_2000_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.base_params = &iwl2000_base_params, \
.eeprom_params = &iwl20x0_eeprom_params, \
.need_temp_offset_calib = true, \
.temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl2000_2bgn_cfg = {
@ -168,12 +146,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = {
.nvm_ver = EEPROM_2000_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \
.eeprom_params = &iwl20x0_eeprom_params, \
.need_temp_offset_calib = true, \
.temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl2030_2bgn_cfg = {
.name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
@ -193,10 +167,7 @@ const struct iwl_cfg iwl2030_2bgn_cfg = {
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.base_params = &iwl2000_base_params, \
.eeprom_params = &iwl20x0_eeprom_params, \
.need_temp_offset_calib = true, \
.temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
.rx_with_siso_diversity = true
const struct iwl_cfg iwl105_bgn_cfg = {
@ -222,12 +193,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = {
.nvm_ver = EEPROM_2000_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \
.eeprom_params = &iwl20x0_eeprom_params, \
.need_temp_offset_calib = true, \
.temp_offset_v2 = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true, \
.rx_with_siso_diversity = true
const struct iwl_cfg iwl135_bgn_cfg = {

View File

@ -59,11 +59,8 @@ static const struct iwl_base_params iwl5000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
.led_compensation = 51,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_WATCHDOG_DISABLED,
.max_event_log_size = 512,
.no_idle_support = true,
};
static const struct iwl_ht_params iwl5000_ht_params = {
@ -159,7 +156,6 @@ const struct iwl_cfg iwl5350_agn_cfg = {
.nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
.base_params = &iwl5000_base_params, \
.eeprom_params = &iwl5000_eeprom_params, \
.no_xtal_calib = true, \
.led_mode = IWL_LED_BLINK, \
.internal_wimax_coex = true

View File

@ -82,10 +82,6 @@ static const struct iwl_base_params iwl6000_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 51,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
@ -98,10 +94,6 @@ static const struct iwl_base_params iwl6050_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.led_compensation = 51,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1500,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 1024,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
@ -114,10 +106,6 @@ static const struct iwl_base_params iwl6000_g2_base_params = {
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 57,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
@ -129,15 +117,6 @@ static const struct iwl_ht_params iwl6000_ht_params = {
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
static const struct iwl_bt_params iwl6000_bt_params = {
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
.bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
.bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
.bt_sco_disable = true,
};
static const struct iwl_eeprom_params iwl6000_eeprom_params = {
.regulatory_bands = {
EEPROM_REG_BAND_1_CHANNELS,
@ -163,7 +142,6 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = {
.nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
.base_params = &iwl6000_g2_base_params, \
.eeprom_params = &iwl6000_eeprom_params, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl6005_2agn_cfg = {
@ -217,11 +195,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
.nvm_ver = EEPROM_6030_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
.base_params = &iwl6000_g2_base_params, \
.bt_params = &iwl6000_bt_params, \
.eeprom_params = &iwl6000_eeprom_params, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true \
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl6030_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
@ -256,11 +231,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = {
.nvm_ver = EEPROM_6030_EEPROM_VERSION, \
.nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
.base_params = &iwl6000_g2_base_params, \
.bt_params = &iwl6000_bt_params, \
.eeprom_params = &iwl6000_eeprom_params, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl6035_2agn_cfg = {
.name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",

View File

@ -96,13 +96,9 @@ static const struct iwl_base_params iwl7000_base_params = {
.pll_cfg_val = 0,
.shadow_ram_support = true,
.led_compensation = 57,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
.shadow_reg_enable = true,
};
static const struct iwl_ht_params iwl7000_ht_params = {
@ -118,14 +114,11 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \
/* TODO: .bt_params? */ \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
.adv_pm = true \
.led_mode = IWL_LED_RF_STATE
const struct iwl_cfg iwl7260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC7260",
.name = "Intel(R) Dual Band Wireless AC 7260",
.fw_name_pre = IWL7260_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
@ -133,8 +126,44 @@ const struct iwl_cfg iwl7260_2ac_cfg = {
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
};
const struct iwl_cfg iwl3160_ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC3160",
const struct iwl_cfg iwl7260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7260",
.fw_name_pre = IWL7260_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL7260_NVM_VERSION,
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
};
const struct iwl_cfg iwl7260_n_cfg = {
.name = "Intel(R) Wireless N 7260",
.fw_name_pre = IWL7260_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL7260_NVM_VERSION,
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
};
const struct iwl_cfg iwl3160_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 3160",
.fw_name_pre = IWL3160_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL3160_NVM_VERSION,
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
};
const struct iwl_cfg iwl3160_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 3160",
.fw_name_pre = IWL3160_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL3160_NVM_VERSION,
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
};
const struct iwl_cfg iwl3160_n_cfg = {
.name = "Intel(R) Wireless N 3160",
.fw_name_pre = IWL3160_FW_PRE,
IWL_DEVICE_7000,
.ht_params = &iwl7000_ht_params,

View File

@ -136,17 +136,9 @@ enum iwl_led_mode {
* @led_compensation: compensate on the led on/off time per HW according
* to the deviation to achieve the desired led frequency.
* The detail algorithm is described in iwl-led.c
* @chain_noise_num_beacons: number of beacons used to compute chain noise
* @adv_thermal_throttle: support advance thermal throttle
* @support_ct_kill_exit: support ct kill exit condition
* @plcp_delta_threshold: plcp error rate threshold used to trigger
* radio tuning when there is a high receiving plcp error rate
* @chain_noise_scale: default chain noise scale used for gain computation
* @wd_timeout: TX queues watchdog timeout
* @max_event_log_size: size of event log buffer size for ucode event logging
* @shadow_reg_enable: HW shadow register support
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
* @no_idle_support: do not support idle mode
*/
struct iwl_base_params {
int eeprom_size;
@ -157,31 +149,9 @@ struct iwl_base_params {
const u16 max_ll_items;
const bool shadow_ram_support;
u16 led_compensation;
bool adv_thermal_throttle;
bool support_ct_kill_exit;
u8 plcp_delta_threshold;
s32 chain_noise_scale;
unsigned int wd_timeout;
u32 max_event_log_size;
const bool shadow_reg_enable;
const bool hd_v2;
const bool no_idle_support;
};
/*
* @advanced_bt_coexist: support advanced bt coexist
* @bt_init_traffic_load: specify initial bt traffic load
* @bt_prio_boost: default bt priority boost value
* @agg_time_limit: maximum number of uSec in aggregation
* @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
*/
struct iwl_bt_params {
bool advanced_bt_coexist;
u8 bt_init_traffic_load;
u32 bt_prio_boost;
u16 agg_time_limit;
bool bt_sco_disable;
bool bt_session_2;
};
/*
@ -231,16 +201,10 @@ struct iwl_eeprom_params {
* @nvm_calib_ver: NVM calibration version
* @lib: pointer to the lib ops
* @base_params: pointer to basic parameters
* @ht_params: point to ht patameters
* @bt_params: pointer to bt parameters
* @need_temp_offset_calib: need to perform temperature offset calibration
* @no_xtal_calib: some devices do not need crystal calibration data,
* don't send it to those
* @ht_params: point to ht parameters
* @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
* @adv_pm: advance power management
* @rx_with_siso_diversity: 1x1 device with rx antenna diversity
* @internal_wimax_coex: internal wifi/wimax combo device
* @temp_offset_v2: support v2 of temperature offset calibration
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@ -264,15 +228,10 @@ struct iwl_cfg {
const struct iwl_base_params *base_params;
/* params likely to change within a device family */
const struct iwl_ht_params *ht_params;
const struct iwl_bt_params *bt_params;
const struct iwl_eeprom_params *eeprom_params;
const bool need_temp_offset_calib; /* if used set to true */
const bool no_xtal_calib;
enum iwl_led_mode led_mode;
const bool adv_pm;
const bool rx_with_siso_diversity;
const bool internal_wimax_coex;
const bool temp_offset_v2;
};
/*
@ -320,6 +279,10 @@ extern const struct iwl_cfg iwl105_bgn_cfg;
extern const struct iwl_cfg iwl105_bgn_d_cfg;
extern const struct iwl_cfg iwl135_bgn_cfg;
extern const struct iwl_cfg iwl7260_2ac_cfg;
extern const struct iwl_cfg iwl3160_ac_cfg;
extern const struct iwl_cfg iwl7260_2n_cfg;
extern const struct iwl_cfg iwl7260_n_cfg;
extern const struct iwl_cfg iwl3160_2ac_cfg;
extern const struct iwl_cfg iwl3160_2n_cfg;
extern const struct iwl_cfg iwl3160_n_cfg;
#endif /* __IWL_CONFIG_H__ */

View File

@ -472,4 +472,23 @@
#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/
/* Diode Results Register Structure: */
enum dtd_diode_reg {
DTS_DIODE_REG_DIG_VAL = 0x000000FF, /* bits [7:0] */
DTS_DIODE_REG_VREF_LOW = 0x0000FF00, /* bits [15:8] */
DTS_DIODE_REG_VREF_HIGH = 0x00FF0000, /* bits [23:16] */
DTS_DIODE_REG_VREF_ID = 0x03000000, /* bits [25:24] */
DTS_DIODE_REG_PASS_ONCE = 0x80000000, /* bits [31:31] */
DTS_DIODE_REG_FLAGS_MSK = 0xFF000000, /* bits [31:24] */
/* Those are the masks INSIDE the flags bit-field: */
DTS_DIODE_REG_FLAGS_VREFS_ID_POS = 0,
DTS_DIODE_REG_FLAGS_VREFS_ID = 0x00000003, /* bits [1:0] */
DTS_DIODE_REG_FLAGS_PASS_ONCE_POS = 7,
DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */
};
#endif /* !__iwl_csr_h__ */

View File

@ -1234,6 +1234,9 @@ MODULE_PARM_DESC(wd_disable,
"Disable stuck queue watchdog timer 0=system default, "
"1=disable, 2=enable (default: 0)");
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
MODULE_PARM_DESC(nvm_file, "NVM file name");
/*
* set bt_coex_active to true, uCode will do kill/defer
* every time the priority line is asserted (BT is sending signals on the

View File

@ -732,17 +732,16 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data,
void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_ht_cap *ht_info,
enum ieee80211_band band)
enum ieee80211_band band,
u8 tx_chains, u8 rx_chains)
{
int max_bit_rate = 0;
u8 rx_chains;
u8 tx_chains;
tx_chains = hweight8(data->valid_tx_ant);
tx_chains = hweight8(tx_chains);
if (cfg->rx_with_siso_diversity)
rx_chains = 1;
else
rx_chains = hweight8(data->valid_rx_ant);
rx_chains = hweight8(rx_chains);
if (!(data->sku_cap_11n_enable) || !cfg->ht_params) {
ht_info->ht_supported = false;
@ -806,7 +805,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
sband->n_bitrates = N_RATES_24;
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_2GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
data->valid_tx_ant, data->valid_rx_ant);
sband = &data->bands[IEEE80211_BAND_5GHZ];
sband->band = IEEE80211_BAND_5GHZ;
@ -814,7 +814,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
sband->n_bitrates = N_RATES_52;
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
data->valid_tx_ant, data->valid_rx_ant);
if (n_channels != n_used)
IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n",

View File

@ -133,6 +133,7 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data,
void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_ht_cap *ht_info,
enum ieee80211_band band);
enum ieee80211_band band,
u8 tx_chains, u8 rx_chains);
#endif /* __iwl_eeprom_parse_h__ */

View File

@ -106,11 +106,14 @@ enum iwl_ucode_type {
/*
* enumeration of ucode section.
* This enumeration is used for legacy tlv style (before 16.0 uCode).
* This enumeration is used directly for older firmware (before 16.0).
* For new firmware, there can be up to 4 sections (see below) but the
* first one packaged into the firmware file is the DATA section and
* some debugging code accesses that.
*/
enum iwl_ucode_sec {
IWL_UCODE_SECTION_INST,
IWL_UCODE_SECTION_DATA,
IWL_UCODE_SECTION_INST,
};
/*
* For 16.0 uCode and above, there is no differentiation between sections,

View File

@ -119,6 +119,7 @@ struct iwl_mod_params {
int ant_coupling;
bool bt_ch_announce;
bool auto_agg;
char *nvm_file;
};
#endif /* #__iwl_modparams_h__ */

View File

@ -89,6 +89,7 @@ enum nvm_sku_bits {
NVM_SKU_CAP_BAND_24GHZ = BIT(0),
NVM_SKU_CAP_BAND_52GHZ = BIT(1),
NVM_SKU_CAP_11N_ENABLE = BIT(2),
NVM_SKU_CAP_11AC_ENABLE = BIT(3),
};
/* radio config bits (actual values from NVM definition) */
@ -258,8 +259,6 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap)
{
/* For now, assume new devices with NVM are VHT capable */
vht_cap->vht_supported = true;
vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
@ -292,7 +291,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
}
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, const __le16 *nvm_sw)
struct iwl_nvm_data *data, const __le16 *nvm_sw,
bool enable_vht, u8 tx_chains, u8 rx_chains)
{
int n_channels = iwl_init_channel_map(dev, cfg, data,
&nvm_sw[NVM_CHANNELS]);
@ -305,7 +305,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
sband->n_bitrates = N_RATES_24;
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_2GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
tx_chains, rx_chains);
sband = &data->bands[IEEE80211_BAND_5GHZ];
sband->band = IEEE80211_BAND_5GHZ;
@ -313,8 +314,10 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
sband->n_bitrates = N_RATES_52;
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
tx_chains, rx_chains);
if (enable_vht)
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
@ -324,7 +327,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
struct iwl_nvm_data *
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
const __le16 *nvm_calib)
const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
{
struct iwl_nvm_data *data;
u8 hw_addr[ETH_ALEN];
@ -380,7 +383,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
data->hw_addr[4] = hw_addr[5];
data->hw_addr[5] = hw_addr[4];
iwl_init_sbands(dev, cfg, data, nvm_sw);
iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
tx_chains, rx_chains);
data->calib_version = 255; /* TODO:
this value will prevent some checks from

View File

@ -75,6 +75,6 @@
struct iwl_nvm_data *
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw,
const __le16 *nvm_calib);
const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains);
#endif /* __iwl_nvm_parse_h__ */

View File

@ -100,6 +100,18 @@
/* Device system time */
#define DEVICE_SYSTEM_TIME_REG 0xA0206C
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
*****************************************************************************/
#define SHR_MISC_WFM_DTS_EN (0x00a10024)
#define DTSC_CFG_MODE (0x00a10604)
#define DTSC_VREF_AVG (0x00a10648)
#define DTSC_VREF5_AVG (0x00a1064c)
#define DTSC_CFG_MODE_PERIODIC (0x2)
#define DTSC_PTAT_AVG (0x00a10650)
/**
* Tx Scheduler
*

View File

@ -189,7 +189,8 @@ enum CMD_MODE {
CMD_SYNC = 0,
CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1),
CMD_ON_DEMAND = BIT(2),
CMD_SEND_IN_RFKILL = BIT(2),
CMD_ON_DEMAND = BIT(3),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@ -455,7 +456,7 @@ struct iwl_trans_ops {
int (*read_mem)(struct iwl_trans *trans, u32 addr,
void *buf, int dwords);
int (*write_mem)(struct iwl_trans *trans, u32 addr,
void *buf, int dwords);
const void *buf, int dwords);
void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state);
@ -761,7 +762,7 @@ static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
}
static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
const void *buf, int dwords)
{
return trans->ops->write_mem(trans, addr, buf, dwords);
}

View File

@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o bt-coex.o
iwlmvm-y += led.o
iwlmvm-y += led.o tt.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o

View File

@ -351,6 +351,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
enum ieee80211_band band;
int ave_rssi;
lockdep_assert_held(&mvm->mutex);
if (vif->type != NL80211_IFTYPE_STATION)
return;
@ -365,7 +366,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
smps_mode = IEEE80211_SMPS_AUTOMATIC;
if (band != IEEE80211_BAND_2GHZ) {
ieee80211_request_smps(vif, smps_mode);
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
smps_mode);
return;
}
@ -380,7 +382,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
mvmvif->id, data->notif->bt_status,
data->notif->bt_traffic_load, smps_mode);
ieee80211_request_smps(vif, smps_mode);
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
/* don't reduce the Tx power if in loose scheme */
if (is_loose_coex())

View File

@ -1007,6 +1007,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (ret)
goto out;
ret = iwl_mvm_power_update_mode(mvm, vif);
if (ret)
goto out;
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
sizeof(d3_cfg_cmd), &d3_cfg_cmd);
@ -1214,6 +1218,26 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
iwl_free_resp(&cmd);
}
static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
{
#ifdef CONFIG_IWLWIFI_DEBUGFS
const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN];
u32 len = img->sec[IWL_UCODE_SECTION_DATA].len;
u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset;
if (!mvm->store_d3_resume_sram)
return;
if (!mvm->d3_resume_sram) {
mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL);
if (!mvm->d3_resume_sram)
return;
}
iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len);
#endif
}
int iwl_mvm_resume(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@ -1245,6 +1269,9 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
goto out_unlock;
}
/* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram(mvm);
iwl_mvm_query_wakeup_reasons(mvm, vif);
out_unlock:

View File

@ -145,15 +145,18 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
char *buf;
u8 *ptr;
if (!mvm->ucode_loaded)
return -EINVAL;
/* default is to dump the entire data segment */
if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
mvm->dbgfs_sram_offset = 0x800000;
if (!mvm->ucode_loaded)
return -EINVAL;
img = &mvm->fw->img[mvm->cur_ucode];
mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
len = img->sec[IWL_UCODE_SECTION_DATA].len;
} else {
ofs = mvm->dbgfs_sram_offset;
len = mvm->dbgfs_sram_len;
}
len = mvm->dbgfs_sram_len;
bufsz = len * 4 + 256;
buf = kzalloc(bufsz, GFP_KERNEL);
@ -167,12 +170,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
}
pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
mvm->dbgfs_sram_offset);
pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs);
iwl_trans_read_mem_bytes(mvm->trans,
mvm->dbgfs_sram_offset,
ptr, len);
iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
for (ofs = 0; ofs < len; ofs += 16) {
pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
@ -300,6 +300,146 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
return count;
}
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
enum iwl_dbgfs_pm_mask param, int val)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
dbgfs_pm->mask |= param;
switch (param) {
case MVM_DEBUGFS_PM_KEEP_ALIVE: {
struct ieee80211_hw *hw = mvm->hw;
int dtimper = hw->conf.ps_dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
if (val * MSEC_PER_SEC < 3 * dtimper_msec) {
IWL_WARN(mvm,
"debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
val * MSEC_PER_SEC, 3 * dtimper_msec);
}
dbgfs_pm->keep_alive_seconds = val;
break;
}
case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
val ? "enabled" : "disabled");
dbgfs_pm->skip_over_dtim = val;
break;
case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
dbgfs_pm->skip_dtim_periods = val;
break;
case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
dbgfs_pm->rx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
dbgfs_pm->tx_data_timeout = val;
break;
case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
dbgfs_pm->disable_power_off = val;
break;
}
}
static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
enum iwl_dbgfs_pm_mask param;
char buf[32] = {};
int val;
int ret;
if (copy_from_user(buf, user_buf, sizeof(buf)))
return -EFAULT;
if (!strncmp("keep_alive=", buf, 11)) {
if (sscanf(buf + 11, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_KEEP_ALIVE;
} else if (!strncmp("skip_over_dtim=", buf, 15)) {
if (sscanf(buf + 15, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
} else if (!strncmp("skip_dtim_periods=", buf, 18)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
} else if (!strncmp("rx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
} else if (!strncmp("tx_data_timeout=", buf, 16)) {
if (sscanf(buf + 16, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
} else if (!strncmp("disable_power_off=", buf, 18)) {
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_pm(mvm, vif, param, val);
ret = iwl_mvm_power_update_mode(mvm, vif);
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
struct iwl_powertable_cmd cmd = {};
char buf[256];
int bufsz = sizeof(buf);
int pos = 0;
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
0 : 1);
pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
le32_to_cpu(cmd.skip_dtim_periods));
pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
iwlmvm_mod_params.power_scheme);
pos += scnprintf(buf+pos, bufsz-pos, "flags = %d\n",
le16_to_cpu(cmd.flags));
pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
cmd.keep_alive_seconds);
if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
(cmd.flags &
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
1 : 0);
pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
le32_to_cpu(cmd.rx_data_timeout));
pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
le32_to_cpu(cmd.tx_data_timeout));
}
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@ -481,6 +621,255 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
return count;
}
static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
enum iwl_dbgfs_bf_mask param, int value)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
dbgfs_bf->mask |= param;
switch (param) {
case MVM_DEBUGFS_BF_ENERGY_DELTA:
dbgfs_bf->bf_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
dbgfs_bf->bf_roaming_energy_delta = value;
break;
case MVM_DEBUGFS_BF_ROAMING_STATE:
dbgfs_bf->bf_roaming_state = value;
break;
case MVM_DEBUGFS_BF_TEMPERATURE_DELTA:
dbgfs_bf->bf_temperature_delta = value;
break;
case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
dbgfs_bf->bf_enable_beacon_filter = value;
break;
case MVM_DEBUGFS_BF_DEBUG_FLAG:
dbgfs_bf->bf_debug_flag = value;
break;
case MVM_DEBUGFS_BF_ESCAPE_TIMER:
dbgfs_bf->bf_escape_timer = value;
break;
case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
dbgfs_bf->ba_enable_beacon_abort = value;
break;
case MVM_DEBUGFS_BA_ESCAPE_TIMER:
dbgfs_bf->ba_escape_timer = value;
break;
}
}
static ssize_t iwl_dbgfs_bf_params_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
enum iwl_dbgfs_bf_mask param;
char buf[256];
int buf_size;
int value;
int ret = 0;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (!strncmp("bf_energy_delta=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ENERGY_DELTA_MIN ||
value > IWL_BF_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
} else if (!strncmp("bf_roaming_state=", buf, 17)) {
if (sscanf(buf+17, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ROAMING_STATE_MIN ||
value > IWL_BF_ROAMING_STATE_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ROAMING_STATE;
} else if (!strncmp("bf_temperature_delta=", buf, 21)) {
if (sscanf(buf+21, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_TEMPERATURE_DELTA_MIN ||
value > IWL_BF_TEMPERATURE_DELTA_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_TEMPERATURE_DELTA;
} else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
if (sscanf(buf+24, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
} else if (!strncmp("bf_debug_flag=", buf, 14)) {
if (sscanf(buf+14, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BF_DEBUG_FLAG;
} else if (!strncmp("bf_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BF_ESCAPE_TIMER_MIN ||
value > IWL_BF_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
} else if (!strncmp("ba_escape_timer=", buf, 16)) {
if (sscanf(buf+16, "%d", &value) != 1)
return -EINVAL;
if (value < IWL_BA_ESCAPE_TIMER_MIN ||
value > IWL_BA_ESCAPE_TIMER_MAX)
return -EINVAL;
param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
} else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
if (sscanf(buf+23, "%d", &value) != 1)
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
} else {
return -EINVAL;
}
mutex_lock(&mvm->mutex);
iwl_dbgfs_update_bf(vif, param, value);
if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) {
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
} else {
if (mvmvif->bf_enabled)
ret = iwl_mvm_enable_beacon_filter(mvm, vif);
else
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
}
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[256];
int pos = 0;
const size_t bufsz = sizeof(buf);
struct iwl_beacon_filter_cmd cmd = {
.bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT,
.bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT,
.bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT,
.bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT,
.bf_enable_beacon_filter = IWL_BF_ENABLE_BEACON_FILTER_DEFAULT,
.bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT,
.bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT),
.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT),
.ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT,
};
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
if (mvmvif->bf_enabled)
cmd.bf_enable_beacon_filter = 1;
else
cmd.bf_enable_beacon_filter = 0;
pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
cmd.bf_energy_delta);
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
cmd.bf_roaming_energy_delta);
pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
cmd.bf_roaming_state);
pos += scnprintf(buf+pos, bufsz-pos, "bf_temperature_delta = %d\n",
cmd.bf_temperature_delta);
pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
cmd.bf_enable_beacon_filter);
pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
cmd.bf_debug_flag);
pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
cmd.bf_escape_timer);
pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
cmd.ba_escape_timer);
pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
cmd.ba_enable_beacon_abort);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
#ifdef CONFIG_PM_SLEEP
static ssize_t iwl_dbgfs_d3_sram_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
char buf[8] = {};
int store;
if (copy_from_user(buf, user_buf, sizeof(buf)))
return -EFAULT;
if (sscanf(buf, "%d", &store) != 1)
return -EINVAL;
mvm->store_d3_resume_sram = store;
return count;
}
static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
const struct fw_img *img;
int ofs, len, pos = 0;
size_t bufsz, ret;
char *buf;
u8 *ptr = mvm->d3_resume_sram;
img = &mvm->fw->img[IWL_UCODE_WOWLAN];
len = img->sec[IWL_UCODE_SECTION_DATA].len;
bufsz = len * 4 + 256;
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
mvm->store_d3_resume_sram ? "en" : "dis");
if (ptr) {
for (ofs = 0; ofs < len; ofs += 16) {
pos += scnprintf(buf + pos, bufsz - pos,
"0x%.4x ", ofs);
hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
bufsz - pos, false);
pos += strlen(buf + pos);
if (bufsz - pos > 0)
buf[pos++] = '\n';
}
} else {
pos += scnprintf(buf + pos, bufsz - pos,
"(no data captured)\n");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
}
#endif
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
@ -524,9 +913,14 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram);
#endif
/* Interface specific debugfs entries */
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params);
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
@ -542,6 +936,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
#ifdef CONFIG_PM_SLEEP
MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
#endif
/*
* Create a symlink with mac80211. It will be removed when mac80211
@ -577,9 +974,19 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return;
}
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p)
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
S_IRUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under

View File

@ -75,13 +75,15 @@ enum iwl_d3_wakeup_flags {
* struct iwl_d3_manager_config - D3 manager configuration command
* @min_sleep_time: minimum sleep time (in usec)
* @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags
* @wakeup_host_timer: force wakeup after this many seconds
*
* The structure is used for the D3_CONFIG_CMD command.
*/
struct iwl_d3_manager_config {
__le32 min_sleep_time;
__le32 wakeup_flags;
} __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */
__le32 wakeup_host_timer;
} __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_4 */
/* TODO: OFFLOADS_QUERY_API_S_VER_1 */

View File

@ -101,20 +101,107 @@ enum iwl_power_flags {
* @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
* PSM transition - legacy PM
* @sleep_interval: not in use
* @keep_alive_beacons: not in use
* @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag
* is set. For example, if it is required to skip over
* one DTIM, this value need to be set to 2 (DTIM periods).
* @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
* Default: 80dbm
*/
struct iwl_powertable_cmd {
/* PM_POWER_TABLE_CMD_API_S_VER_5 */
/* PM_POWER_TABLE_CMD_API_S_VER_6 */
__le16 flags;
u8 keep_alive_seconds;
u8 debug_flags;
__le32 rx_data_timeout;
__le32 tx_data_timeout;
__le32 sleep_interval[IWL_POWER_VEC_SIZE];
__le32 keep_alive_beacons;
__le32 skip_dtim_periods;
__le32 lprx_rssi_threshold;
} __packed;
/**
* struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
* @id_and_color: MAC contex identifier
* @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon
* to driver if delta in Energy values calculated for this and last
* passed beacon is greater than this threshold. Zero value means that
* the Energy change is ignored for beacon filtering, and beacon will
* not be forced to be sent to driver regardless of this delta. Typical
* energy delta 5dB.
* @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state.
* Send beacon to driver if delta in Energy values calculated for this
* and last passed beacon is greater than this threshold. Zero value
* means that the Energy change is ignored for beacon filtering while in
* Roaming state, typical energy delta 1dB.
* @bf_roaming_state: Used for RSSI filtering. If absolute Energy values
* calculated for current beacon is less than the threshold, use
* Roaming Energy Delta Threshold, otherwise use normal Energy Delta
* Threshold. Typical energy threshold is -72dBm.
* @bf_temperature_delta: Send Beacon to driver if delta in temperature values
* calculated for this and the last passed beacon is greater than this
* threshold. Zero value means that the temperature changeis ignored for
* beacon filtering; beacons will not be forced to be sent to driver
* regardless of whether its temerature has been changed.
* @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled.
* @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed
* for a specific period of time. Units: Beacons.
* @ba_escape_timer: Fully receive and parse beacon if no beacons were passed
* for a longer period of time then this escape-timeout. Units: Beacons.
* @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled.
*/
struct iwl_beacon_filter_cmd {
u8 bf_energy_delta;
u8 bf_roaming_energy_delta;
u8 bf_roaming_state;
u8 bf_temperature_delta;
u8 bf_enable_beacon_filter;
u8 bf_debug_flag;
__le16 reserved1;
__le32 bf_escape_timer;
__le32 ba_escape_timer;
u8 ba_enable_beacon_abort;
u8 reserved2[3];
} __packed;
/* Beacon filtering and beacon abort */
#define IWL_BF_ENERGY_DELTA_DEFAULT 5
#define IWL_BF_ENERGY_DELTA_MAX 255
#define IWL_BF_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1
#define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255
#define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0
#define IWL_BF_ROAMING_STATE_DEFAULT 72
#define IWL_BF_ROAMING_STATE_MAX 255
#define IWL_BF_ROAMING_STATE_MIN 0
#define IWL_BF_TEMPERATURE_DELTA_DEFAULT 5
#define IWL_BF_TEMPERATURE_DELTA_MAX 255
#define IWL_BF_TEMPERATURE_DELTA_MIN 0
#define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1
#define IWL_BF_DEBUG_FLAG_DEFAULT 0
#define IWL_BF_ESCAPE_TIMER_DEFAULT 50
#define IWL_BF_ESCAPE_TIMER_MAX 1024
#define IWL_BF_ESCAPE_TIMER_MIN 0
#define IWL_BA_ESCAPE_TIMER_DEFAULT 3
#define IWL_BA_ESCAPE_TIMER_MAX 1024
#define IWL_BA_ESCAPE_TIMER_MIN 0
#define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1
#define IWL_BF_CMD_CONFIG_DEFAULTS \
.bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, \
.bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, \
.bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, \
.bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, \
.bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, \
.bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \
.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT)
#endif

View File

@ -134,6 +134,7 @@ enum iwl_tx_flags {
#define TX_CMD_SEC_WEP 0x01
#define TX_CMD_SEC_CCM 0x02
#define TX_CMD_SEC_TKIP 0x03
#define TX_CMD_SEC_MSK 0x07
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
#define TX_CMD_SEC_KEY128 0x08

View File

@ -139,6 +139,9 @@ enum {
/* Power */
POWER_TABLE_CMD = 0x77,
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
/* Scanning */
SCAN_REQUEST_CMD = 0x80,
SCAN_ABORT_CMD = 0x81,
@ -161,6 +164,8 @@ enum {
CARD_STATE_CMD = 0xa0,
CARD_STATE_NOTIFICATION = 0xa1,
MISSED_BEACONS_NOTIFICATION = 0xa2,
REPLY_RX_PHY_CMD = 0xc0,
REPLY_RX_MPDU_CMD = 0xc1,
BA_NOTIF = 0xc5,
@ -170,9 +175,13 @@ enum {
BT_COEX_PROT_ENV = 0xcd,
BT_PROFILE_NOTIFICATION = 0xce,
REPLY_BEACON_FILTERING_CMD = 0xd2,
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
MCAST_FILTER_CMD = 0xd0,
/* D3 commands/notifications */
D3_CONFIG_CMD = 0xd3,
PROT_OFFLOAD_CONFIG_CMD = 0xd4,
@ -935,6 +944,24 @@ struct iwl_card_state_notif {
__le32 flags;
} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */
/**
* struct iwl_missed_beacons_notif - information on missed beacons
* ( MISSED_BEACONS_NOTIFICATION = 0xa2 )
* @mac_id: interface ID
* @consec_missed_beacons_since_last_rx: number of consecutive missed
* beacons since last RX.
* @consec_missed_beacons: number of consecutive missed beacons
* @num_expected_beacons:
* @num_recvd_beacons:
*/
struct iwl_missed_beacons_notif {
__le32 mac_id;
__le32 consec_missed_beacons_since_last_rx;
__le32 consec_missed_beacons;
__le32 num_expected_beacons;
__le32 num_recvd_beacons;
} __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */
/**
* struct iwl_set_calib_default_cmd - set default value for calibration.
* ( SET_CALIB_DEFAULT_CMD = 0x8e )
@ -948,4 +975,237 @@ struct iwl_set_calib_default_cmd {
u8 data[0];
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
#define MAX_PORT_ID_NUM 2
/**
* struct iwl_mcast_filter_cmd - configure multicast filter.
* @filter_own: Set 1 to filter out multicast packets sent by station itself
* @port_id: Multicast MAC addresses array specifier. This is a strange way
* to identify network interface adopted in host-device IF.
* It is used by FW as index in array of addresses. This array has
* MAX_PORT_ID_NUM members.
* @count: Number of MAC addresses in the array
* @pass_all: Set 1 to pass all multicast packets.
* @bssid: current association BSSID.
* @addr_list: Place holder for array of MAC addresses.
* IMPORTANT: add padding if necessary to ensure DWORD alignment.
*/
struct iwl_mcast_filter_cmd {
u8 filter_own;
u8 port_id;
u8 count;
u8 pass_all;
u8 bssid[6];
u8 reserved[2];
u8 addr_list[0];
} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
struct mvm_statistics_dbg {
__le32 burst_check;
__le32 burst_count;
__le32 wait_for_silence_timeout_cnt;
__le32 reserved[3];
} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
struct mvm_statistics_div {
__le32 tx_on_a;
__le32 tx_on_b;
__le32 exec_time;
__le32 probe_time;
__le32 rssi_ant;
__le32 reserved2;
} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
struct mvm_statistics_general_common {
__le32 temperature; /* radio temperature */
__le32 temperature_m; /* radio voltage */
struct mvm_statistics_dbg dbg;
__le32 sleep_time;
__le32 slots_out;
__le32 slots_idle;
__le32 ttl_timestamp;
struct mvm_statistics_div div;
__le32 rx_enable_counter;
/*
* num_of_sos_states:
* count the number of times we have to re-tune
* in order to get out of bad PHY status
*/
__le32 num_of_sos_states;
} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
struct mvm_statistics_rx_non_phy {
__le32 bogus_cts; /* CTS received when not expecting CTS */
__le32 bogus_ack; /* ACK received when not expecting ACK */
__le32 non_bssid_frames; /* number of frames with BSSID that
* doesn't belong to the STA BSSID */
__le32 filtered_frames; /* count frames that were dumped in the
* filtering process */
__le32 non_channel_beacons; /* beacons with our bss id but not on
* our serving channel */
__le32 channel_beacons; /* beacons with our bss id and in our
* serving channel */
__le32 num_missed_bcon; /* number of missed beacons */
__le32 adc_rx_saturation_time; /* count in 0.8us units the time the
* ADC was in saturation */
__le32 ina_detection_search_time;/* total time (in 0.8us) searched
* for INA */
__le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
__le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
__le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
__le32 interference_data_flag; /* flag for interference data
* availability. 1 when data is
* available. */
__le32 channel_load; /* counts RX Enable time in uSec */
__le32 dsp_false_alarms; /* DSP false alarm (both OFDM
* and CCK) counter */
__le32 beacon_rssi_a;
__le32 beacon_rssi_b;
__le32 beacon_rssi_c;
__le32 beacon_energy_a;
__le32 beacon_energy_b;
__le32 beacon_energy_c;
__le32 num_bt_kills;
__le32 mac_id;
__le32 directed_data_mpdu;
} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */
struct mvm_statistics_rx_phy {
__le32 ina_cnt;
__le32 fina_cnt;
__le32 plcp_err;
__le32 crc32_err;
__le32 overrun_err;
__le32 early_overrun_err;
__le32 crc32_good;
__le32 false_alarm_cnt;
__le32 fina_sync_err_cnt;
__le32 sfd_timeout;
__le32 fina_timeout;
__le32 unresponded_rts;
__le32 rxe_frame_limit_overrun;
__le32 sent_ack_cnt;
__le32 sent_cts_cnt;
__le32 sent_ba_rsp_cnt;
__le32 dsp_self_kill;
__le32 mh_format_err;
__le32 re_acq_main_rssi_sum;
__le32 reserved;
} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */
struct mvm_statistics_rx_ht_phy {
__le32 plcp_err;
__le32 overrun_err;
__le32 early_overrun_err;
__le32 crc32_good;
__le32 crc32_err;
__le32 mh_format_err;
__le32 agg_crc32_good;
__le32 agg_mpdu_cnt;
__le32 agg_cnt;
__le32 unsupport_mcs;
} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */
#define MAX_CHAINS 3
struct mvm_statistics_tx_non_phy_agg {
__le32 ba_timeout;
__le32 ba_reschedule_frames;
__le32 scd_query_agg_frame_cnt;
__le32 scd_query_no_agg;
__le32 scd_query_agg;
__le32 scd_query_mismatch;
__le32 frame_not_ready;
__le32 underrun;
__le32 bt_prio_kill;
__le32 rx_ba_rsp_cnt;
__s8 txpower[MAX_CHAINS];
__s8 reserved;
__le32 reserved2;
} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */
struct mvm_statistics_tx_channel_width {
__le32 ext_cca_narrow_ch20[1];
__le32 ext_cca_narrow_ch40[2];
__le32 ext_cca_narrow_ch80[3];
__le32 ext_cca_narrow_ch160[4];
__le32 last_tx_ch_width_indx;
__le32 rx_detected_per_ch_width[4];
__le32 success_per_ch_width[4];
__le32 fail_per_ch_width[4];
}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */
struct mvm_statistics_tx {
__le32 preamble_cnt;
__le32 rx_detected_cnt;
__le32 bt_prio_defer_cnt;
__le32 bt_prio_kill_cnt;
__le32 few_bytes_cnt;
__le32 cts_timeout;
__le32 ack_timeout;
__le32 expected_ack_cnt;
__le32 actual_ack_cnt;
__le32 dump_msdu_cnt;
__le32 burst_abort_next_frame_mismatch_cnt;
__le32 burst_abort_missing_next_frame_cnt;
__le32 cts_timeout_collision;
__le32 ack_or_ba_timeout_collision;
struct mvm_statistics_tx_non_phy_agg agg;
struct mvm_statistics_tx_channel_width channel_width;
} __packed; /* STATISTICS_TX_API_S_VER_4 */
struct mvm_statistics_bt_activity {
__le32 hi_priority_tx_req_cnt;
__le32 hi_priority_tx_denied_cnt;
__le32 lo_priority_tx_req_cnt;
__le32 lo_priority_tx_denied_cnt;
__le32 hi_priority_rx_req_cnt;
__le32 hi_priority_rx_denied_cnt;
__le32 lo_priority_rx_req_cnt;
__le32 lo_priority_rx_denied_cnt;
} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */
struct mvm_statistics_general {
struct mvm_statistics_general_common common;
__le32 beacon_filtered;
__le32 missed_beacons;
__s8 beacon_filter_everage_energy;
__s8 beacon_filter_reason;
__s8 beacon_filter_current_energy;
__s8 beacon_filter_reserved;
__le32 beacon_filter_delta_time;
struct mvm_statistics_bt_activity bt_activity;
} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
struct mvm_statistics_rx {
struct mvm_statistics_rx_phy ofdm;
struct mvm_statistics_rx_phy cck;
struct mvm_statistics_rx_non_phy general;
struct mvm_statistics_rx_ht_phy ofdm_ht;
} __packed; /* STATISTICS_RX_API_S_VER_3 */
/*
* STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
*
* By default, uCode issues this notification after receiving a beacon
* while associated. To disable this behavior, set DISABLE_NOTIF flag in the
* REPLY_STATISTICS_CMD 0x9c, above.
*
* Statistics counters continue to increment beacon after beacon, but are
* cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
* 0x9c with CLEAR_STATS bit set (see above).
*
* uCode also issues this notification during scans. uCode clears statistics
* appropriately so that each notification contains statistics for only the
* one channel that has just been scanned.
*/
struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
__le32 flag;
struct mvm_statistics_rx rx;
struct mvm_statistics_tx tx;
struct mvm_statistics_general general;
} __packed;
#endif /* __fw_api_h__ */

View File

@ -326,6 +326,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
WARN_ON(ret);
/*
* abort after reading the nvm in case RF Kill is on, we will complete
* the init seq later when RF kill will switch to off
*/
if (iwl_mvm_is_radio_killed(mvm)) {
IWL_DEBUG_RF_KILL(mvm,
"jump over all phy activities due to RF kill\n");
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
return 1;
}
/* Send TX valid antennas before triggering calibrations */
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
@ -388,6 +399,8 @@ out:
int iwl_mvm_up(struct iwl_mvm *mvm)
{
int ret, i;
struct ieee80211_channel *chan;
struct cfg80211_chan_def chandef;
lockdep_assert_held(&mvm->mutex);
@ -400,8 +413,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = iwl_run_init_mvm_ucode(mvm, false);
if (ret && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
/* this can't happen */
if (WARN_ON(ret > 0))
ret = -ERFKILL;
goto error;
}
/* should stop & start HW since that INIT image just loaded */
iwl_trans_stop_hw(mvm->trans, false);
ret = iwl_trans_start_hw(mvm->trans);
if (ret)
return ret;
}
if (iwlmvm_mod_params.init_dbg)
@ -443,8 +464,22 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
goto error;
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
/* Add all the PHY contexts */
chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
for (i = 0; i < NUM_PHY_CTX; i++) {
/*
* The channel used here isn't relevant as it's
* going to be overwritten in the other flows.
* For now use the first channel we have.
*/
ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i],
&chandef, 1, 1);
if (ret)
goto error;
}
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:
iwl_trans_stop_device(mvm->trans);

View File

@ -227,7 +227,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
.found_vif = false,
};
u32 ac;
int ret;
int ret, i;
/*
* Allocate a MAC ID and a TSF for this MAC, along with the queues
@ -335,6 +335,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT;
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++)
mvmvif->smps_requests[i] = IEEE80211_SMPS_AUTOMATIC;
return 0;
exit_fail:
@ -586,10 +589,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
*/
static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_data_sta *ctxt_sta)
struct iwl_mac_data_sta *ctxt_sta,
bool force_assoc_off)
{
/* We need the dtim_period to set the MAC as associated */
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) {
if (vif->bss_conf.assoc && vif->bss_conf.dtim_period &&
!force_assoc_off) {
u32 dtim_offs;
/*
@ -659,7 +664,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
/* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta,
action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@ -677,7 +683,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta);
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta,
action == FW_CTXT_ACTION_ADD);
cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
@ -1043,3 +1050,28 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
rate);
return 0;
}
static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
u16 *id = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (mvmvif->id == *id)
ieee80211_beacon_loss(vif);
}
int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data;
u16 id = (u16)le32_to_cpu(missed_beacons->mac_id);
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_beacon_loss_iterator,
&id);
return 0;
}

View File

@ -127,6 +127,17 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
};
#endif
static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
{
int i;
memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts));
for (i = 0; i < NUM_PHY_CTX; i++) {
mvm->phy_ctxts[i].id = i;
mvm->phy_ctxts[i].ref = 0;
}
}
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
@ -141,7 +152,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TIMING_BEACON_ONLY;
IEEE80211_HW_TIMING_BEACON_ONLY |
IEEE80211_HW_CONNECTION_MONITOR;
hw->queues = IWL_MVM_FIRST_AGG_QUEUE;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@ -158,7 +170,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->sta_data_size = sizeof(struct iwl_mvm_sta);
hw->vif_data_size = sizeof(struct iwl_mvm_vif);
hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt);
hw->chanctx_data_size = sizeof(u16);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
@ -193,6 +205,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->n_addresses++;
}
iwl_mvm_reset_phy_ctxts(mvm);
/* we create the 802.11 header and a max-length SSID element */
hw->wiphy->max_scan_ie_len =
mvm->fw->ucode_capa.max_probe_length - 24 - 34;
@ -252,8 +266,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) {
IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n");
if (iwl_mvm_is_radio_killed(mvm)) {
IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
goto drop;
}
@ -345,8 +359,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
spin_unlock_bh(&mvm->time_event_lock);
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvmvif->phy_ctxt = NULL;
mvmvif->phy_ctxt = NULL;
}
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
@ -363,6 +376,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
iwl_mvm_cleanup_iterator, mvm);
mvm->p2p_device_vif = NULL;
iwl_mvm_reset_phy_ctxts(mvm);
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
@ -456,6 +472,20 @@ static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
iwl_mvm_power_update_mode(mvm, vif);
}
static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
{
u16 i;
lockdep_assert_held(&mvm->mutex);
for (i = 0; i < NUM_PHY_CTX; i++)
if (!mvm->phy_ctxts[i].ref)
return &mvm->phy_ctxts[i];
IWL_ERR(mvm, "No available PHY context\n");
return NULL;
}
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -530,32 +560,34 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
*/
iwl_mvm_power_update_mode(mvm, vif);
/* beacon filtering */
if (!mvm->bf_allowed_vif &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p){
mvm->bf_allowed_vif = mvmvif;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
}
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
if (ret)
goto out_release;
/*
* P2P_DEVICE interface does not have a channel context assigned to it,
* so a dedicated PHY context is allocated to it and the corresponding
* MAC context is bound to it at this stage.
*/
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
struct ieee80211_channel *chan;
struct cfg80211_chan_def chandef;
mvmvif->phy_ctxt = &mvm->phy_ctxt_roc;
/*
* The channel used here isn't relevant as it's
* going to be overwritten as part of the ROC flow.
* For now use the first channel we have.
*/
chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt,
&chandef, 1, 1);
if (ret)
mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
if (!mvmvif->phy_ctxt) {
ret = -ENOSPC;
goto out_remove_mac;
}
iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
ret = iwl_mvm_binding_add_vif(mvm, vif);
if (ret)
goto out_remove_phy;
goto out_unref_phy;
ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
if (ret)
@ -571,8 +603,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
out_unbind:
iwl_mvm_binding_remove_vif(mvm, vif);
out_remove_phy:
iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
out_unref_phy:
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
out_remove_mac:
mvmvif->phy_ctxt = NULL;
iwl_mvm_mac_ctxt_remove(mvm, vif);
@ -646,6 +678,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
if (mvm->bf_allowed_vif == mvmvif) {
mvm->bf_allowed_vif = NULL;
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
}
iwl_mvm_vif_dbgfs_clean(mvm, vif);
/*
@ -661,7 +698,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvm->p2p_device_vif = NULL;
iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
iwl_mvm_binding_remove_vif(mvm, vif);
iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
mvmvif->phy_ctxt = NULL;
}
@ -701,6 +738,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
*total_flags = 0;
}
static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mcast_filter_cmd mcast_filter_cmd = {
.pass_all = 1,
};
memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
sizeof(mcast_filter_cmd),
&mcast_filter_cmd);
}
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@ -722,6 +773,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
return;
}
iwl_mvm_bt_coex_vif_assoc(mvm, vif);
iwl_mvm_configure_mcast_filter(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@ -931,7 +983,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
switch (cmd) {
case STA_NOTIFY_SLEEP:
if (atomic_read(&mvmsta->pending_frames) > 0)
if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
ieee80211_sta_block_awake(hw, sta, true);
/*
* The fw updates the STA to be asleep. Tx packets on the Tx
@ -984,9 +1036,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
mvmvif->phy_ctxt->channel->band);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {
/* enable beacon filtering */
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif));
ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
/* disable beacon filtering */
WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif));
ret = 0;
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH) {
@ -1152,29 +1208,107 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
enum ieee80211_roc_type type)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct cfg80211_chan_def chandef;
int ret;
struct iwl_mvm_phy_ctxt *phy_ctxt;
int ret, i;
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
duration, type);
if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
return -EINVAL;
}
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
duration, type);
mutex_lock(&mvm->mutex);
cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc,
&chandef, 1, 1);
for (i = 0; i < NUM_PHY_CTX; i++) {
phy_ctxt = &mvm->phy_ctxts[i];
if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
continue;
if (phy_ctxt->ref && channel == phy_ctxt->channel) {
/*
* Unbind the P2P_DEVICE from the current PHY context,
* and if the PHY context is not used remove it.
*/
ret = iwl_mvm_binding_remove_vif(mvm, vif);
if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
goto out_unlock;
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
/* Bind the P2P_DEVICE to the current PHY Context */
mvmvif->phy_ctxt = phy_ctxt;
ret = iwl_mvm_binding_add_vif(mvm, vif);
if (WARN(ret, "Failed binding P2P_DEVICE\n"))
goto out_unlock;
iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
goto schedule_time_event;
}
}
/* Need to update the PHY context only if the ROC channel changed */
if (channel == mvmvif->phy_ctxt->channel)
goto schedule_time_event;
cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
/*
* Change the PHY context configuration as it is currently referenced
* only by the P2P Device MAC
*/
if (mvmvif->phy_ctxt->ref == 1) {
ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt,
&chandef, 1, 1);
if (ret)
goto out_unlock;
} else {
/*
* The PHY context is shared with other MACs. Need to remove the
* P2P Device from the binding, allocate an new PHY context and
* create a new binding
*/
phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
if (!phy_ctxt) {
ret = -ENOSPC;
goto out_unlock;
}
ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef,
1, 1);
if (ret) {
IWL_ERR(mvm, "Failed to change PHY context\n");
goto out_unlock;
}
/* Unbind the P2P_DEVICE from the current PHY context */
ret = iwl_mvm_binding_remove_vif(mvm, vif);
if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
goto out_unlock;
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
/* Bind the P2P_DEVICE to the new allocated PHY context */
mvmvif->phy_ctxt = phy_ctxt;
ret = iwl_mvm_binding_add_vif(mvm, vif);
if (WARN(ret, "Failed binding P2P_DEVICE\n"))
goto out_unlock;
iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
}
schedule_time_event:
/* Schedule the time events */
ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);
out_unlock:
mutex_unlock(&mvm->mutex);
IWL_DEBUG_MAC80211(mvm, "leave\n");
return ret;
}
@ -1196,15 +1330,30 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt;
int ret;
mutex_lock(&mvm->mutex);
IWL_DEBUG_MAC80211(mvm, "Add channel context\n");
IWL_DEBUG_MAC80211(mvm, "Add PHY context\n");
ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
mutex_lock(&mvm->mutex);
phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
if (!phy_ctxt) {
ret = -ENOSPC;
goto out;
}
ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
if (ret) {
IWL_ERR(mvm, "Failed to add PHY context\n");
goto out;
}
iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt);
*phy_ctxt_id = phy_ctxt->id;
out:
mutex_unlock(&mvm->mutex);
return ret;
}
@ -1213,10 +1362,11 @@ static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
mutex_lock(&mvm->mutex);
iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt);
iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt);
mutex_unlock(&mvm->mutex);
}
@ -1225,7 +1375,16 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
u32 changed)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
if (WARN_ONCE((phy_ctxt->ref > 1) &&
(changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
IEEE80211_CHANCTX_CHANGE_RADAR)),
"Cannot change PHY. Ref=%d, changed=0x%X\n",
phy_ctxt->ref, changed))
return;
mutex_lock(&mvm->mutex);
iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
@ -1239,13 +1398,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv;
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
mutex_lock(&mvm->mutex);
mvmvif->phy_ctxt = phyctx;
mvmvif->phy_ctxt = phy_ctxt;
switch (vif->type) {
case NL80211_IFTYPE_AP:

View File

@ -109,6 +109,7 @@ extern struct iwl_mvm_mod_params iwlmvm_mod_params;
struct iwl_mvm_phy_ctxt {
u16 id;
u16 color;
u32 ref;
/*
* TODO: This should probably be removed. Currently here only for rate
@ -149,6 +150,60 @@ enum iwl_power_scheme {
#define IWL_CONN_MAX_LISTEN_INTERVAL 70
#ifdef CONFIG_IWLWIFI_DEBUGFS
enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0),
MVM_DEBUGFS_PM_SKIP_OVER_DTIM = BIT(1),
MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2),
MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3),
MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4),
MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5),
};
struct iwl_dbgfs_pm {
u8 keep_alive_seconds;
u32 rx_data_timeout;
u32 tx_data_timeout;
bool skip_over_dtim;
u8 skip_dtim_periods;
bool disable_power_off;
int mask;
};
/* beacon filtering */
enum iwl_dbgfs_bf_mask {
MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0),
MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1),
MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2),
MVM_DEBUGFS_BF_TEMPERATURE_DELTA = BIT(3),
MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(4),
MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(5),
MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(6),
MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(7),
MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(8),
};
struct iwl_dbgfs_bf {
u8 bf_energy_delta;
u8 bf_roaming_energy_delta;
u8 bf_roaming_state;
u8 bf_temperature_delta;
u8 bf_enable_beacon_filter;
u8 bf_debug_flag;
u32 bf_escape_timer;
u32 ba_escape_timer;
u8 ba_enable_beacon_abort;
int mask;
};
#endif
enum iwl_mvm_smps_type_request {
IWL_MVM_SMPS_REQ_BT_COEX,
IWL_MVM_SMPS_REQ_TT,
NUM_IWL_MVM_SMPS_REQ,
};
/**
* struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
* @id: between 0 and 3
@ -163,6 +218,8 @@ enum iwl_power_scheme {
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template
* @smps_requests: the requests of of differents parts of the driver, regard
the desired smps mode.
*/
struct iwl_mvm_vif {
u16 id;
@ -172,6 +229,8 @@ struct iwl_mvm_vif {
bool uploaded;
bool ap_active;
bool monitor_active;
/* indicate whether beacon filtering is enabled */
bool bf_enabled;
u32 ap_beacon_time;
@ -214,7 +273,11 @@ struct iwl_mvm_vif {
struct dentry *dbgfs_dir;
struct dentry *dbgfs_slink;
void *dbgfs_data;
struct iwl_dbgfs_pm dbgfs_pm;
struct iwl_dbgfs_bf dbgfs_bf;
#endif
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
};
static inline struct iwl_mvm_vif *
@ -223,12 +286,6 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
return (void *)vif->drv_priv;
}
enum iwl_mvm_status {
IWL_MVM_STATUS_HW_RFKILL,
IWL_MVM_STATUS_ROC_RUNNING,
IWL_MVM_STATUS_IN_HW_RESTART,
};
enum iwl_scan_status {
IWL_MVM_SCAN_NONE,
IWL_MVM_SCAN_OS,
@ -246,6 +303,63 @@ struct iwl_nvm_section {
const u8 *data;
};
/*
* Tx-backoff threshold
* @temperature: The threshold in Celsius
* @backoff: The tx-backoff in uSec
*/
struct iwl_tt_tx_backoff {
s32 temperature;
u32 backoff;
};
#define TT_TX_BACKOFF_SIZE 6
/**
* struct iwl_tt_params - thermal throttling parameters
* @ct_kill_entry: CT Kill entry threshold
* @ct_kill_exit: CT Kill exit threshold
* @ct_kill_duration: The time intervals (in uSec) in which the driver needs
* to checks whether to exit CT Kill.
* @dynamic_smps_entry: Dynamic SMPS entry threshold
* @dynamic_smps_exit: Dynamic SMPS exit threshold
* @tx_protection_entry: TX protection entry threshold
* @tx_protection_exit: TX protection exit threshold
* @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
* @support_ct_kill: Support CT Kill?
* @support_dynamic_smps: Support dynamic SMPS?
* @support_tx_protection: Support tx protection?
* @support_tx_backoff: Support tx-backoff?
*/
struct iwl_tt_params {
s32 ct_kill_entry;
s32 ct_kill_exit;
u32 ct_kill_duration;
s32 dynamic_smps_entry;
s32 dynamic_smps_exit;
s32 tx_protection_entry;
s32 tx_protection_exit;
struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
bool support_ct_kill;
bool support_dynamic_smps;
bool support_tx_protection;
bool support_tx_backoff;
};
/**
* struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure
* @ct_kill_exit: worker to exit thermal kill
* @dynamic_smps: Is thermal throttling enabled dynamic_smps?
* @tx_backoff: The current thremal throttling tx backoff in uSec.
* @params: Parameters to configure the thermal throttling algorithm.
*/
struct iwl_mvm_tt_mgmt {
struct delayed_work ct_kill_exit;
bool dynamic_smps;
u32 tx_backoff;
const struct iwl_tt_params *params;
};
struct iwl_mvm {
/* for logger access */
struct device *dev;
@ -266,6 +380,12 @@ struct iwl_mvm {
unsigned long status;
/*
* for beacon filtering -
* currently only one interface can be supported
*/
struct iwl_mvm_vif *bf_allowed_vif;
enum iwl_ucode_type cur_ucode;
bool ucode_loaded;
bool init_ucode_run;
@ -292,6 +412,7 @@ struct iwl_mvm {
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
struct work_struct sta_drained_wk;
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
/* configured by mac80211 */
u32 rts_threshold;
@ -312,7 +433,7 @@ struct iwl_mvm {
bool prevent_power_down_d3;
#endif
struct iwl_mvm_phy_ctxt phy_ctxt_roc;
struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
struct list_head time_event_list;
spinlock_t time_event_lock;
@ -337,11 +458,19 @@ struct iwl_mvm {
#ifdef CONFIG_PM_SLEEP
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
#ifdef CONFIG_IWLWIFI_DEBUGFS
bool store_d3_resume_sram;
void *d3_resume_sram;
#endif
#endif
/* BT-Coex */
u8 bt_kill_msk;
struct iwl_bt_coex_profile_notif last_bt_notif;
/* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle;
s32 temperature; /* Celsius */
};
/* Extract MVM priv from op_mode and _hw */
@ -351,6 +480,19 @@ struct iwl_mvm {
#define IWL_MAC80211_GET_MVM(_hw) \
IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv))
enum iwl_mvm_status {
IWL_MVM_STATUS_HW_RFKILL,
IWL_MVM_STATUS_HW_CTKILL,
IWL_MVM_STATUS_ROC_RUNNING,
IWL_MVM_STATUS_IN_HW_RESTART,
};
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
{
return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) ||
test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
}
extern const u8 iwl_mvm_ac_to_tx_fifo[];
struct iwl_rate_info {
@ -442,8 +584,10 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic);
void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt);
void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt);
void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt);
/* MAC (virtual interface) programming */
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -458,6 +602,9 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -533,4 +680,36 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event);
void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
/* beacon filtering */
#ifdef CONFIG_IWLWIFI_DEBUGFS
void
iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
struct iwl_beacon_filter_cmd *cmd);
int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm);
#else
static inline void
iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
struct iwl_beacon_filter_cmd *cmd)
{}
static inline int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm)
{
return 0;
}
#endif
int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
/* SMPS */
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request);
/* Thermal management and CT-kill */
void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
#endif /* __IWL_MVM_H__ */

View File

@ -60,6 +60,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include <linux/firmware.h>
#include "iwl-trans.h"
#include "mvm.h"
#include "iwl-eeprom-parse.h"
@ -75,31 +76,56 @@ static const int nvm_to_read[] = {
};
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE 6000
static inline void iwl_nvm_fill_read(struct iwl_nvm_access_cmd *cmd,
u16 offset, u16 length, u16 section)
#define NVM_WRITE_OPCODE 1
#define NVM_READ_OPCODE 0
/*
* prepare the NVM host command w/ the pointers to the nvm buffer
* and send it to fw
*/
static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section,
u16 offset, u16 length, const u8 *data)
{
cmd->offset = cpu_to_le16(offset);
cmd->length = cpu_to_le16(length);
cmd->type = cpu_to_le16(section);
struct iwl_nvm_access_cmd nvm_access_cmd = {
.offset = cpu_to_le16(offset),
.length = cpu_to_le16(length),
.type = cpu_to_le16(section),
.op_code = NVM_WRITE_OPCODE,
};
struct iwl_host_cmd cmd = {
.id = NVM_ACCESS_CMD,
.len = { sizeof(struct iwl_nvm_access_cmd), length },
.flags = CMD_SYNC | CMD_SEND_IN_RFKILL,
.data = { &nvm_access_cmd, data },
/* data may come from vmalloc, so use _DUP */
.dataflags = { 0, IWL_HCMD_DFL_DUP },
};
return iwl_mvm_send_cmd(mvm, &cmd);
}
static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
u16 offset, u16 length, u8 *data)
{
struct iwl_nvm_access_cmd nvm_access_cmd = {};
struct iwl_nvm_access_cmd nvm_access_cmd = {
.offset = cpu_to_le16(offset),
.length = cpu_to_le16(length),
.type = cpu_to_le16(section),
.op_code = NVM_READ_OPCODE,
};
struct iwl_nvm_access_resp *nvm_resp;
struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = NVM_ACCESS_CMD,
.flags = CMD_SYNC | CMD_WANT_SKB,
.flags = CMD_SYNC | CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
.data = { &nvm_access_cmd, },
};
int ret, bytes_read, offset_read;
u8 *resp_data;
iwl_nvm_fill_read(&nvm_access_cmd, offset, length, section);
cmd.len[0] = sizeof(struct iwl_nvm_access_cmd);
ret = iwl_mvm_send_cmd(mvm, &cmd);
@ -144,6 +170,30 @@ exit:
return ret;
}
static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section,
const u8 *data, u16 length)
{
int offset = 0;
/* copy data in chunks of 2k (and remainder if any) */
while (offset < length) {
int chunk_size, ret;
chunk_size = min(IWL_NVM_DEFAULT_CHUNK_SIZE,
length - offset);
ret = iwl_nvm_write_chunk(mvm, section, offset,
chunk_size, data + offset);
if (ret < 0)
return ret;
offset += chunk_size;
}
return 0;
}
/*
* Reads an NVM section completely.
* NICs prior to 7000 family doesn't have a real NVM, but just read
@ -177,7 +227,8 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
offset += ret;
}
IWL_INFO(mvm, "NVM section %d read completed\n", section);
IWL_DEBUG_EEPROM(mvm->trans->dev,
"NVM section %d read completed\n", section);
return offset;
}
@ -200,7 +251,130 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data;
sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib);
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
iwl_fw_valid_tx_ant(mvm->fw),
iwl_fw_valid_rx_ant(mvm->fw));
}
#define MAX_NVM_FILE_LEN 16384
/*
* HOW TO CREATE THE NVM FILE FORMAT:
* ------------------------------
* 1. create hex file, format:
* 3800 -> header
* 0000 -> header
* 5a40 -> data
*
* rev - 6 bit (word1)
* len - 10 bit (word1)
* id - 4 bit (word2)
* rsv - 12 bit (word2)
*
* 2. flip 8bits with 8 bits per line to get the right NVM file format
*
* 3. create binary file from the hex file
*
* 4. save as "iNVM_xxx.bin" under /lib/firmware
*/
static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
{
int ret, section_id, section_size;
const struct firmware *fw_entry;
const struct {
__le16 word1;
__le16 word2;
u8 data[];
} *file_sec;
const u8 *eof;
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12)
/*
* Obtain NVM image via request_firmware. Since we already used
* request_firmware_nowait() for the firmware binary load and only
* get here after that we assume the NVM request can be satisfied
* synchronously.
*/
ret = request_firmware(&fw_entry, iwlwifi_mod_params.nvm_file,
mvm->trans->dev);
if (ret) {
IWL_ERR(mvm, "ERROR: %s isn't available %d\n",
iwlwifi_mod_params.nvm_file, ret);
return ret;
}
IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n",
iwlwifi_mod_params.nvm_file, fw_entry->size);
if (fw_entry->size < sizeof(*file_sec)) {
IWL_ERR(mvm, "NVM file too small\n");
ret = -EINVAL;
goto out;
}
if (fw_entry->size > MAX_NVM_FILE_LEN) {
IWL_ERR(mvm, "NVM file too large\n");
ret = -EINVAL;
goto out;
}
eof = fw_entry->data + fw_entry->size;
file_sec = (void *)fw_entry->data;
while (true) {
if (file_sec->data > eof) {
IWL_ERR(mvm,
"ERROR - NVM file too short for section header\n");
ret = -EINVAL;
break;
}
/* check for EOF marker */
if (!file_sec->word1 && !file_sec->word2) {
ret = 0;
break;
}
section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
IWL_ERR(mvm, "ERROR - section too large (%d)\n",
section_size);
ret = -EINVAL;
break;
}
if (!section_size) {
IWL_ERR(mvm, "ERROR - section empty\n");
ret = -EINVAL;
break;
}
if (file_sec->data + section_size > eof) {
IWL_ERR(mvm,
"ERROR - NVM file too short for section (%d bytes)\n",
section_size);
ret = -EINVAL;
break;
}
ret = iwl_nvm_write_section(mvm, section_id, file_sec->data,
section_size);
if (ret < 0) {
IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
break;
}
/* advance to the next section */
file_sec = (void *)(file_sec->data + section_size);
}
out:
release_firmware(fw_entry);
return ret;
}
int iwl_nvm_init(struct iwl_mvm *mvm)
@ -208,6 +382,17 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
int ret, i, section;
u8 *nvm_buffer, *temp;
/* load external NVM if configured */
if (iwlwifi_mod_params.nvm_file) {
/* move to External NVM flow */
ret = iwl_mvm_load_external_nvm(mvm);
if (ret)
return ret;
}
/* Read From FW NVM */
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
/* TODO: find correct NVM max size for a section */
nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
GFP_KERNEL);
@ -231,8 +416,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
if (ret < 0)
return ret;
ret = 0;
mvm->nvm_data = iwl_parse_nvm_sections(mvm);
if (!mvm->nvm_data)
return -ENODATA;
return ret;
return 0;
}

View File

@ -222,10 +222,14 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true),
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif,
false),
RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
};
#undef RX_HANDLER
@ -288,10 +292,14 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(NET_DETECT_HOTSPOTS_CMD),
CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
CMD(CARD_STATE_NOTIFICATION),
CMD(MISSED_BEACONS_NOTIFICATION),
CMD(BT_COEX_PRIO_TABLE),
CMD(BT_COEX_PROT_ENV),
CMD(BT_PROFILE_NOTIFICATION),
CMD(BT_CONFIG),
CMD(MCAST_FILTER_CMD),
CMD(REPLY_BEACON_FILTERING_CMD),
CMD(REPLY_THERMAL_MNG_BACKOFF),
};
#undef CMD
@ -392,10 +400,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (err)
goto out_free;
iwl_mvm_tt_initialize(mvm);
mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true);
mutex_unlock(&mvm->mutex);
if (err && !iwlmvm_mod_params.init_dbg) {
/* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free;
}
@ -438,10 +449,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_mvm_leds_exit(mvm);
iwl_mvm_tt_exit(mvm);
ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
#endif
iwl_trans_stop_hw(mvm->trans, true);
iwl_phy_db_free(mvm->phy_db);
@ -588,6 +605,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
ieee80211_wake_queue(mvm->hw, mq);
}
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
{
if (state)
set_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
else
clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
}
static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
@ -597,7 +624,7 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
else
clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
}
static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)

View File

@ -195,21 +195,6 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
return ret;
}
struct phy_ctx_used_data {
unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)];
};
static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
void *_data)
{
struct phy_ctx_used_data *data = _data;
struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
__set_bit(phy_ctxt->id, data->used);
}
/*
* Send a command to add a PHY context based on the current HW configuration.
*/
@ -217,34 +202,27 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
{
struct phy_ctx_used_data data = {
.used = { },
};
/*
* If this is a regular PHY context (not the ROC one)
* skip the ROC PHY context's ID.
*/
if (ctxt != &mvm->phy_ctxt_roc)
__set_bit(mvm->phy_ctxt_roc.id, data.used);
int ret;
WARN_ON(ctxt->ref);
lockdep_assert_held(&mvm->mutex);
ctxt->color++;
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
ieee80211_iter_chan_contexts_atomic(
mvm->hw, iwl_mvm_phy_ctx_used_iter, &data);
ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX);
if (WARN_ONCE(ctxt->id == NUM_PHY_CTX,
"Failed to init PHY context - no free ID!\n"))
return -EIO;
}
ctxt->channel = chandef->chan;
return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
chains_static, chains_dynamic,
FW_CTXT_ACTION_ADD, 0);
ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
chains_static, chains_dynamic,
FW_CTXT_ACTION_ADD, 0);
return ret;
}
/*
* Update the number of references to the given PHY context. This is valid only
* in case the PHY context was already created, i.e., its reference count > 0.
*/
void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
{
lockdep_assert_held(&mvm->mutex);
ctxt->ref++;
}
/*
@ -264,23 +242,12 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
FW_CTXT_ACTION_MODIFY, 0);
}
/*
* Send a command to the FW to remove the given phy context.
* Once the command is sent, regardless of success or failure, the context is
* marked as invalid
*/
void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
{
struct iwl_phy_context_cmd cmd;
int ret;
lockdep_assert_held(&mvm->mutex);
iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0);
ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC,
sizeof(struct iwl_phy_context_cmd),
&cmd);
if (ret)
IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n",
ctxt->id);
if (WARN_ON_ONCE(!ctxt))
return;
ctxt->ref--;
}

View File

@ -75,6 +75,54 @@
#define POWER_KEEP_ALIVE_PERIOD_SEC 25
static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
struct iwl_beacon_filter_cmd *cmd)
{
int ret;
ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC,
sizeof(struct iwl_beacon_filter_cmd), cmd);
if (!ret) {
IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
cmd->ba_enable_beacon_abort);
IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
cmd->ba_escape_timer);
IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
cmd->bf_debug_flag);
IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
cmd->bf_enable_beacon_filter);
IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
cmd->bf_energy_delta);
IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
cmd->bf_escape_timer);
IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
cmd->bf_roaming_energy_delta);
IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
cmd->bf_roaming_state);
IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n",
cmd->bf_temperature_delta);
}
return ret;
}
static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, bool enable)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_beacon_filter_cmd cmd = {
IWL_BF_CMD_CONFIG_DEFAULTS,
.bf_enable_beacon_filter = 1,
.ba_enable_beacon_abort = enable,
};
if (!mvmvif->bf_enabled)
return 0;
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
}
static void iwl_mvm_power_log(struct iwl_mvm *mvm,
struct iwl_powertable_cmd *cmd)
{
@ -91,6 +139,9 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
le32_to_cpu(cmd->tx_data_timeout));
IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
cmd->lprx_rssi_threshold);
if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))
IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",
le32_to_cpu(cmd->skip_dtim_periods));
}
}
@ -103,6 +154,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int dtimper, dtimper_msec;
int keep_alive;
bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif);
/*
* Regardless of power management state the driver must set
@ -116,6 +169,11 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
mvmvif->dbgfs_pm.disable_power_off)
cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
if (!vif->bss_conf.ps)
return;
@ -135,8 +193,11 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) &&
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP))
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP ||
mvm->cur_ucode == IWL_UCODE_WOWLAN)) {
cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
cmd->skip_dtim_periods = cpu_to_le32(3);
}
/* Check that keep alive period is at least 3 * DTIM */
dtimper_msec = dtimper * vif->bss_conf.beacon_int;
@ -145,12 +206,41 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = keep_alive;
cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
if (mvm->cur_ucode != IWL_UCODE_WOWLAN) {
cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
} else {
cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds;
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) {
if (mvmvif->dbgfs_pm.skip_over_dtim)
cmd->flags |=
cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
else
cmd->flags &=
cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK);
}
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT)
cmd->rx_data_timeout =
cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout);
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT)
cmd->tx_data_timeout =
cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout);
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)
cmd->skip_dtim_periods =
cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods);
#endif /* CONFIG_IWLWIFI_DEBUGFS */
}
int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
int ret;
bool ba_enable;
struct iwl_powertable_cmd cmd = {};
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
@ -159,13 +249,22 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
iwl_mvm_power_log(mvm, &cmd);
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
sizeof(cmd), &cmd);
ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
sizeof(cmd), &cmd);
if (ret)
return ret;
ba_enable = !!(cmd.flags &
cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable);
}
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_powertable_cmd cmd = {};
struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif);
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
@ -173,8 +272,82 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
mvmvif->dbgfs_pm.disable_power_off)
cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
iwl_mvm_power_log(mvm, &cmd);
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
sizeof(cmd), &cmd);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
void
iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
struct iwl_beacon_filter_cmd *cmd)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA)
cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA)
cmd->bf_roaming_energy_delta =
dbgfs_bf->bf_roaming_energy_delta;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE)
cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA)
cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG)
cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag;
if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER)
cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer);
if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER)
cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer);
if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT)
cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort;
}
#endif
int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_beacon_filter_cmd cmd = {
IWL_BF_CMD_CONFIG_DEFAULTS,
.bf_enable_beacon_filter = 1,
};
int ret;
if (mvmvif != mvm->bf_allowed_vif ||
vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
if (!ret)
mvmvif->bf_enabled = true;
return ret;
}
int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_beacon_filter_cmd cmd = {};
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
if (!ret)
mvmvif->bf_enabled = false;
return ret;
}

View File

@ -3080,3 +3080,29 @@ void iwl_mvm_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&rs_mvm_ops);
}
/**
* iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable
* Tx protection, according to this rquest and previous requests,
* and send the LQ command.
* @lq: The LQ command
* @mvmsta: The station
* @enable: Enable Tx protection?
*/
int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
struct iwl_mvm_sta *mvmsta, bool enable)
{
lockdep_assert_held(&mvm->mutex);
if (enable) {
if (mvmsta->tx_protection == 0)
lq->flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK;
mvmsta->tx_protection++;
} else {
mvmsta->tx_protection--;
if (mvmsta->tx_protection == 0)
lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK;
}
return iwl_mvm_send_lq_cmd(mvm, lq, CMD_ASYNC, false);
}

View File

@ -390,4 +390,9 @@ extern int iwl_mvm_rate_control_register(void);
*/
extern void iwl_mvm_rate_control_unregister(void);
struct iwl_mvm_sta;
int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
struct iwl_mvm_sta *mvmsta, bool enable);
#endif /* __rs__ */

View File

@ -363,3 +363,25 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
rxb, &rx_status);
return 0;
}
/*
* iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler
*
* TODO: This handler is implemented partially.
* It only gets the NIC's temperature.
*/
int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_notif_statistics *stats = (void *)&pkt->data;
struct mvm_statistics_general_common *common = &stats->general.common;
if (mvm->temperature != le32_to_cpu(common->temperature)) {
mvm->temperature = le32_to_cpu(common->temperature);
iwl_mvm_tt_handler(mvm);
}
return 0;
}

View File

@ -64,6 +64,7 @@
#include "mvm.h"
#include "sta.h"
#include "rs.h"
static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
{
@ -217,9 +218,11 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
mvmvif->color);
mvm_sta->vif = vif;
mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
mvm_sta->tx_protection = 0;
mvm_sta->tt_tx_protection = false;
/* HW restart, don't assume the memory has been zeroed */
atomic_set(&mvm_sta->pending_frames, 0);
atomic_set(&mvm->pending_frames[sta_id], 0);
mvm_sta->tid_disable_agg = 0;
mvm_sta->tfd_queue_msk = 0;
for (i = 0; i < IEEE80211_NUM_ACS; i++)
@ -406,15 +409,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
}
/*
* Make sure that the tx response code sees the station as -EBUSY and
* calls the drain worker.
*/
spin_lock_bh(&mvm_sta->lock);
/*
* There are frames pending on the AC queues for this station.
* We need to wait until all the frames are drained...
*/
if (atomic_read(&mvm_sta->pending_frames)) {
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
ERR_PTR(-EBUSY));
spin_unlock_bh(&mvm_sta->lock);
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
} else {
spin_unlock_bh(&mvm_sta->lock);
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
}
@ -791,21 +801,23 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
min(mvmsta->max_agg_bufsize, buf_size);
mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid);
if (mvm->cfg->ht_params->use_rts_for_aggregation) {
/*
* switch to RTS/CTS if it is the prefer protection
* method for HT traffic
* this function also sends the LQ command
*/
mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK;
return iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq,
mvmsta, true);
/*
* TODO: remove the TLC_RTS flag when we tear down the last
* AGG session (agg_tids_count in DVM)
*/
}
IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid);
return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false);
}

View File

@ -274,8 +274,9 @@ struct iwl_mvm_tid_data {
* @bt_reduced_txpower: is reduced tx power enabled for this station
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock.
* @pending_frames: number of frames for this STA on the shared Tx queues.
* @tid_data: per tid data. Look at %iwl_mvm_tid_data.
* @tx_protection: reference counter for controlling the Tx protection.
* @tt_tx_protection: is thermal throttling enable Tx protection?
*
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is placed in that
@ -290,7 +291,6 @@ struct iwl_mvm_sta {
u8 max_agg_bufsize;
bool bt_reduced_txpower;
spinlock_t lock;
atomic_t pending_frames;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
struct iwl_lq_sta lq_sta;
struct ieee80211_vif *vif;
@ -298,6 +298,10 @@ struct iwl_mvm_sta {
#ifdef CONFIG_PM_SLEEP
u16 last_seq_ctl;
#endif
/* Temporary, until the new TLC will control the Tx protection */
s8 tx_protection;
bool tt_tx_protection;
};
/**

View File

@ -0,0 +1,509 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "mvm.h"
#include "iwl-config.h"
#include "iwl-io.h"
#include "iwl-csr.h"
#include "iwl-prph.h"
#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/
/* VBG - Voltage Band Gap error data (temperature offset) */
#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2)
#define MEAS_VBG_MIN_VAL 2300
#define MEAS_VBG_MAX_VAL 3000
#define MEAS_VBG_DEFAULT_VAL 2700
#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE)
#define MIN_TEMPERATURE 0
#define MAX_TEMPERATURE 125
#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1)
#define PTAT_DIGITAL_VALUE_MIN_VALUE 0
#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF
#define DTS_VREFS_NUM 5
static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags)
{
return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >>
DTS_DIODE_REG_FLAGS_VREFS_ID_POS;
}
#define CALC_VREFS_MIN_DIFF 43
#define CALC_VREFS_MAX_DIFF 51
#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF)
#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF
#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23
/*
* @digital_value: The diode's digital-value sampled (temperature/voltage)
* @vref_low: The lower voltage-reference (the vref just below the diode's
* sampled digital-value)
* @vref_high: The higher voltage-reference (the vref just above the diode's
* sampled digital-value)
* @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref)
* bits[6:2]: Reserved.
* bits[7:7]: Indicates completion of at least 1 successful sample
* since last DTS reset.
*/
struct iwl_mvm_dts_diode_bits {
u8 digital_value;
u8 vref_low;
u8 vref_high;
u8 flags;
} __packed;
union dts_diode_results {
u32 reg_value;
struct iwl_mvm_dts_diode_bits bits;
} __packed;
static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm)
{
struct iwl_nvm_section calib_sec;
const __le16 *calib;
u16 vbg;
/* TODO: move parsing to NVM code */
calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION];
calib = (__le16 *)calib_sec.data;
vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]);
if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL)
vbg = MEAS_VBG_DEFAULT_VAL;
return vbg;
}
static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
{
const u8 *calib;
u8 ptat, pa1, pa2, median;
/* TODO: move parsing to NVM code */
calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
ptat = calib[OTP_DTS_DIODE_DEVIATION];
pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1];
pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2];
/* get the median: */
if (ptat > pa1) {
if (ptat > pa2)
median = (pa1 > pa2) ? pa1 : pa2;
else
median = ptat;
} else {
if (pa1 > pa2)
median = (ptat > pa2) ? ptat : pa2;
else
median = pa1;
}
return ptat - median;
}
static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value)
{
/* Calibrate the PTAT digital value, based on PTAT deviation data: */
s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm);
if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE)
new_val = PTAT_DIGITAL_VALUE_MAX_VALUE;
else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE)
new_val = PTAT_DIGITAL_VALUE_MIN_VALUE;
return new_val;
}
static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm,
union dts_diode_results *avg_ptat)
{
u8 vrefs_results[DTS_VREFS_NUM];
u8 low_vref_index = 0, flags;
u32 reg;
reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG);
memcpy(vrefs_results, &reg, sizeof(reg));
reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG);
vrefs_results[4] = reg & 0xff;
if (avg_ptat->bits.digital_value < vrefs_results[0] ||
avg_ptat->bits.digital_value > vrefs_results[4])
return false;
if (avg_ptat->bits.digital_value > vrefs_results[3])
low_vref_index = 3;
else if (avg_ptat->bits.digital_value > vrefs_results[2])
low_vref_index = 2;
else if (avg_ptat->bits.digital_value > vrefs_results[1])
low_vref_index = 1;
avg_ptat->bits.vref_low = vrefs_results[low_vref_index];
avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1];
flags = avg_ptat->bits.flags;
avg_ptat->bits.flags =
(flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) |
(low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID);
return true;
}
/*
* return true it the results are valid, and false otherwise.
*/
static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm,
union dts_diode_results *avg_ptat)
{
u32 reg;
u8 tmp;
/* fill the diode value and pass_once with avg-reg results */
reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG);
reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE;
avg_ptat->reg_value = reg;
/* calibrate the PTAT digital value */
tmp = avg_ptat->bits.digital_value;
tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp);
avg_ptat->bits.digital_value = tmp;
/*
* fill vrefs fields, based on the avgVrefs results
* and the diode value
*/
return dts_get_adjacent_vrefs(mvm, avg_ptat) &&
DTS_DIODE_VALID(avg_ptat->bits.flags);
}
static s32 calculate_nic_temperature(union dts_diode_results avg_ptat,
u16 volt_band_gap)
{
u32 tmp_result;
u8 vrefs_diff;
/*
* For temperature calculation (at the end, shift right by 23)
* LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) }
* (D2-D1) == 43 44 45 46 47 48 49 50 51
*/
static const u16 calc_lut[CALC_LUT_SIZE] = {
2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828,
};
/*
* The diff between the high and low voltage-references is assumed
* to be strictly be in range of [60,68]
*/
vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low;
if (vrefs_diff < CALC_VREFS_MIN_DIFF ||
vrefs_diff > CALC_VREFS_MAX_DIFF)
return TEMPERATURE_ERROR;
/* calculate the result: */
tmp_result =
vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9);
tmp_result += avg_ptat.bits.digital_value;
tmp_result -= avg_ptat.bits.vref_high;
/* multiply by the LUT value (based on the diff) */
tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET];
/*
* Get the BandGap (the voltage refereces source) error data
* (temperature offset)
*/
tmp_result *= volt_band_gap;
/*
* here, tmp_result value can be up to 32-bits. We want to right-shift
* it *without* sign-extend.
*/
tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET;
/*
* at this point, tmp_result should be in the range:
* 200 <= tmp_result <= 365
*/
return (s16)tmp_result - 240;
}
static s32 check_nic_temperature(struct iwl_mvm *mvm)
{
u16 volt_band_gap;
union dts_diode_results avg_ptat;
volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm);
/* disable DTS */
iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
/* SV initialization */
iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1);
iwl_write_prph(mvm->trans, DTSC_CFG_MODE,
DTSC_CFG_MODE_PERIODIC);
/* wait for results */
msleep(100);
if (!dts_read_ptat_avg_results(mvm, &avg_ptat))
return TEMPERATURE_ERROR;
/* disable DTS */
iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
return calculate_nic_temperature(avg_ptat, volt_band_gap);
}
static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
{
u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
IWL_ERR(mvm, "Enter CT Kill\n");
iwl_mvm_set_hw_ctkill_state(mvm, true);
schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
round_jiffies_relative(duration * HZ));
}
static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
{
IWL_ERR(mvm, "Exit CT Kill\n");
iwl_mvm_set_hw_ctkill_state(mvm, false);
}
static void check_exit_ctkill(struct work_struct *work)
{
struct iwl_mvm_tt_mgmt *tt;
struct iwl_mvm *mvm;
u32 duration;
s32 temp;
tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
duration = tt->params->ct_kill_duration;
iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm);
iwl_trans_stop_hw(mvm->trans, false);
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
goto reschedule;
}
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
if (temp <= tt->params->ct_kill_exit) {
iwl_mvm_exit_ctkill(mvm);
return;
}
reschedule:
schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
round_jiffies(duration * HZ));
}
static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = _data;
enum ieee80211_smps_mode smps_mode;
lockdep_assert_held(&mvm->mutex);
if (mvm->thermal_throttle.dynamic_smps)
smps_mode = IEEE80211_SMPS_DYNAMIC;
else
smps_mode = IEEE80211_SMPS_AUTOMATIC;
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
}
static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
{
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
int i, err;
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
lockdep_is_held(&mvm->mutex));
if (IS_ERR_OR_NULL(sta))
continue;
mvmsta = (void *)sta->drv_priv;
if (enable == mvmsta->tt_tx_protection)
continue;
err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq,
mvmsta, enable);
if (err) {
IWL_ERR(mvm, "Failed to %s Tx protection\n",
enable ? "enable" : "disable");
} else {
IWL_DEBUG_TEMP(mvm, "%s Tx protection\n",
enable ? "Enable" : "Disable");
mvmsta->tt_tx_protection = enable;
}
}
}
static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
{
struct iwl_host_cmd cmd = {
.id = REPLY_THERMAL_MNG_BACKOFF,
.len = { sizeof(u32), },
.data = { &backoff, },
.flags = CMD_SYNC,
};
if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
backoff);
mvm->thermal_throttle.tx_backoff = backoff;
} else {
IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n");
}
}
void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
{
const struct iwl_tt_params *params = mvm->thermal_throttle.params;
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
s32 temperature = mvm->temperature;
int i;
u32 tx_backoff;
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature);
if (params->support_ct_kill && temperature >= params->ct_kill_entry) {
iwl_mvm_enter_ctkill(mvm);
return;
}
if (params->support_dynamic_smps) {
if (!tt->dynamic_smps &&
temperature >= params->dynamic_smps_entry) {
IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n");
tt->dynamic_smps = true;
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_tt_smps_iterator, mvm);
} else if (tt->dynamic_smps &&
temperature <= params->dynamic_smps_exit) {
IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n");
tt->dynamic_smps = false;
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_tt_smps_iterator, mvm);
}
}
if (params->support_tx_protection) {
if (temperature >= params->tx_protection_entry)
iwl_mvm_tt_tx_protection(mvm, true);
else if (temperature <= params->tx_protection_exit)
iwl_mvm_tt_tx_protection(mvm, false);
}
if (params->support_tx_backoff) {
tx_backoff = 0;
for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
if (temperature < params->tx_backoff[i].temperature)
break;
tx_backoff = params->tx_backoff[i].backoff;
}
if (tt->tx_backoff != tx_backoff)
iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
}
}
static const struct iwl_tt_params iwl7000_tt_params = {
.ct_kill_entry = 118,
.ct_kill_exit = 96,
.ct_kill_duration = 5,
.dynamic_smps_entry = 114,
.dynamic_smps_exit = 110,
.tx_protection_entry = 114,
.tx_protection_exit = 108,
.tx_backoff = {
{.temperature = 112, .backoff = 200},
{.temperature = 113, .backoff = 600},
{.temperature = 114, .backoff = 1200},
{.temperature = 115, .backoff = 2000},
{.temperature = 116, .backoff = 4000},
{.temperature = 117, .backoff = 10000},
},
.support_ct_kill = true,
.support_dynamic_smps = true,
.support_tx_protection = true,
.support_tx_backoff = true,
};
void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
tt->params = &iwl7000_tt_params;
INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
}
void iwl_mvm_tt_exit(struct iwl_mvm *mvm)
{
cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
}

View File

@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock(&mvmsta->lock);
if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
txq_id < IWL_MVM_FIRST_AGG_QUEUE)
atomic_inc(&mvmsta->pending_frames);
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE)
atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
return 0;
@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/*
* If the txq is not an AMPDU queue, there is no chance we freed
* several skbs. Check that out...
* If there are no pending frames for this STA, notify mac80211 that
* this station can go to sleep in its STA table.
*/
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta &&
!WARN_ON(skb_freed > 1) &&
mvmsta->vif->type == NL80211_IFTYPE_AP &&
atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
ieee80211_sta_block_awake(mvm->hw, sta, false);
set_bit(sta_id, mvm->sta_drained);
schedule_work(&mvm->sta_drained_wk);
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) &&
atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
if (mvmsta) {
/*
* If there are no pending frames for this STA, notify
* mac80211 that this station can go to sleep in its
* STA table.
*/
if (mvmsta->vif->type == NL80211_IFTYPE_AP)
ieee80211_sta_block_awake(mvm->hw, sta, false);
/*
* We might very well have taken mvmsta pointer while
* the station was being removed. The remove flow might
* have seen a pending_frame (because we didn't take
* the lock) even if now the queues are drained. So make
* really sure now that this the station is not being
* removed. If it is, run the drain worker to remove it.
*/
spin_lock_bh(&mvmsta->lock);
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
if (IS_ERR_OR_NULL(sta)) {
/*
* Station disappeared in the meantime:
* so we are draining.
*/
set_bit(sta_id, mvm->sta_drained);
schedule_work(&mvm->sta_drained_wk);
}
spin_unlock_bh(&mvmsta->lock);
} else if (!mvmsta) {
/* Tx response without STA, so we are draining */
set_bit(sta_id, mvm->sta_drained);
schedule_work(&mvm->sta_drained_wk);
}
}
rcu_read_unlock();

View File

@ -471,3 +471,34 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
return iwl_mvm_send_cmd(mvm, &cmd);
}
/**
* iwl_mvm_update_smps - Get a requst to change the SMPS mode
* @req_type: The part of the driver who call for a change.
* @smps_requests: The request to change the SMPS mode.
*
* Get a requst to change the SMPS mode,
* and change it according to all other requests in the driver.
*/
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request)
{
struct iwl_mvm_vif *mvmvif;
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
int i;
lockdep_assert_held(&mvm->mutex);
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC) {
smps_mode = IEEE80211_SMPS_STATIC;
break;
}
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC)
smps_mode = IEEE80211_SMPS_DYNAMIC;
}
ieee80211_request_smps(vif, smps_mode);
}

View File

@ -256,10 +256,54 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
/* 7000 Series */
{IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4162, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0x4270, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0x4260, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0x4262, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4470, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4460, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4462, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4870, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x486E, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4A70, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4A6E, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4A6C, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0x4420, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC170, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC060, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC160, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC062, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC162, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0xC262, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC470, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC460, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC462, iwl7260_n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC020, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B2, 0xC220, iwl7260_2n_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC420, iwl7260_2n_cfg)},
/* 3160 Series */
{IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0170, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0060, iwl3160_2n_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0062, iwl3160_n_cfg)},
{IWL_PCI_DEVICE(0x08B4, 0x0270, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0470, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8170, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8060, iwl3160_2n_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)},
{IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)},
{0}
};

View File

@ -405,20 +405,27 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
{
u8 *v_addr;
dma_addr_t p_addr;
u32 offset;
u32 offset, chunk_sz = section->len;
int ret = 0;
IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
section_num);
v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL);
if (!v_addr)
return -ENOMEM;
v_addr = dma_alloc_coherent(trans->dev, chunk_sz, &p_addr,
GFP_KERNEL | __GFP_NOWARN);
if (!v_addr) {
IWL_DEBUG_INFO(trans, "Falling back to small chunks of DMA\n");
chunk_sz = PAGE_SIZE;
v_addr = dma_alloc_coherent(trans->dev, chunk_sz,
&p_addr, GFP_KERNEL);
if (!v_addr)
return -ENOMEM;
}
for (offset = 0; offset < section->len; offset += PAGE_SIZE) {
for (offset = 0; offset < section->len; offset += chunk_sz) {
u32 copy_size;
copy_size = min_t(u32, PAGE_SIZE, section->len - offset);
copy_size = min_t(u32, chunk_sz, section->len - offset);
memcpy(v_addr, (u8 *)section->data + offset, copy_size);
ret = iwl_pcie_load_firmware_chunk(trans,
@ -432,7 +439,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
}
}
dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr);
dma_free_coherent(trans->dev, chunk_sz, v_addr, p_addr);
return ret;
}
@ -573,10 +580,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
{
/* let the ucode operate on its own */
iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
iwl_disable_interrupts(trans);
iwl_pcie_disable_ict(trans);
@ -636,9 +639,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
return ret;
}
iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
*status = IWL_D3_STATUS_ALIVE;
return 0;
}
@ -917,11 +917,11 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
}
static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
const void *buf, int dwords)
{
unsigned long flags;
int offs, ret = 0;
u32 *vals = buf;
const u32 *vals = buf;
if (iwl_trans_grab_nic_access(trans, false, &flags)) {
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);

View File

@ -1045,6 +1045,10 @@ static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
/* Receiver address (actually, Rx station's index into station table),
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
int sta_id, int tid, int frame_limit, u16 ssn)
{
@ -1518,6 +1522,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) {
IWL_ERR(trans, "FW error in SYNC CMD %s\n",
get_cmd_string(trans_pcie, cmd->id));
dump_stack();
ret = -EIO;
goto cancel;
}
@ -1564,7 +1569,8 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
return -EIO;
if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL, &trans_pcie->status)) {
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
cmd->id);
return -ERFKILL;

View File

@ -2282,9 +2282,6 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(wdev->netdev);
if (wdev->netdev->reg_state == NETREG_UNREGISTERED)
free_netdev(wdev->netdev);
/* Clear the priv in adapter */
priv->netdev = NULL;

View File

@ -1192,6 +1192,7 @@ mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
adapter->if_ops.wakeup(adapter);
adapter->hs_activated = false;
adapter->is_hs_configured = false;
adapter->is_suspended = false;
mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY),
false);

View File

@ -669,6 +669,7 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
dev->destructor = free_netdev;
/* Initialize private structure */
priv->current_key_index = 0;
priv->media_connected = false;

View File

@ -96,7 +96,7 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
} else {
/* Multicast */
priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
dev_dbg(priv->adapter->dev,
"info: Enabling All Multicast!\n");
priv->curr_pkt_filter |=
@ -108,20 +108,11 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev,
"info: Set multicast list=%d\n",
mcast_list->num_multicast_addr);
/* Set multicast addresses to firmware */
if (old_pkt_filter == priv->curr_pkt_filter) {
/* Send request to firmware */
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_MAC_MULTICAST_ADR,
HostCmd_ACT_GEN_SET, 0,
mcast_list);
} else {
/* Send request to firmware */
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_MAC_MULTICAST_ADR,
HostCmd_ACT_GEN_SET, 0,
mcast_list);
}
/* Send multicast addresses to firmware */
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_MAC_MULTICAST_ADR,
HostCmd_ACT_GEN_SET, 0,
mcast_list);
}
}
}