提交 7d7f5d04 编写于 作者: D David S. Miller

Merge tag 'wireless-drivers-next-for-davem-2016-01-09' of...

Merge tag 'wireless-drivers-next-for-davem-2016-01-09' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next

Kalle Valo says:

====================
brcmfmac

* query features through firmware command
* ARP offload through inet notifier
* force probe to succeed for debugging purposes
* random mac support for scheduled scan
* support wowl upon net detect

iwlwifi

* bug fixes and improvements for firmware debug system
* advertise support for Rx A-MSDU in A-MPDU
* support -20.ucode
* fix WoWLAN for iwldvm
* preparations towards multiple Rx queues
* platform power improvements for GO mode when no clients are associated
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -3860,7 +3860,8 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) ...@@ -3860,7 +3860,8 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT; ht_cap.cap |=
WLAN_HT_CAP_SM_PS_DISABLED << IEEE80211_HT_CAP_SM_PS_SHIFT;
if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI) if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
......
...@@ -487,6 +487,9 @@ static int ath10k_pci_force_wake(struct ath10k *ar) ...@@ -487,6 +487,9 @@ static int ath10k_pci_force_wake(struct ath10k *ar)
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
if (ar_pci->pci_ps)
return ret;
spin_lock_irqsave(&ar_pci->ps_lock, flags); spin_lock_irqsave(&ar_pci->ps_lock, flags);
if (!ar_pci->ps_awake) { if (!ar_pci->ps_awake) {
...@@ -2480,12 +2483,10 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) ...@@ -2480,12 +2483,10 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
u32 val; u32 val;
int ret = 0; int ret = 0;
if (ar_pci->pci_ps == 0) { ret = ath10k_pci_force_wake(ar);
ret = ath10k_pci_force_wake(ar); if (ret) {
if (ret) { ath10k_err(ar, "failed to wake up target: %d\n", ret);
ath10k_err(ar, "failed to wake up target: %d\n", ret); return ret;
return ret;
}
} }
/* Suspend/Resume resets the PCI configuration space, so we have to /* Suspend/Resume resets the PCI configuration space, so we have to
...@@ -2592,13 +2593,10 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) ...@@ -2592,13 +2593,10 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret; int ret;
if (ar_pci->pci_ps == 0) { ret = ath10k_pci_force_wake(ar);
ret = ath10k_pci_force_wake(ar); if (ret) {
if (ret) { ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
ath10k_warn(ar, "failed to wake device up on irq: %d\n", return IRQ_NONE;
ret);
return IRQ_NONE;
}
} }
if (ar_pci->num_msi_intrs == 0) { if (ar_pci->num_msi_intrs == 0) {
...@@ -3071,17 +3069,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ...@@ -3071,17 +3069,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_sleep; goto err_sleep;
} }
ret = ath10k_pci_force_wake(ar);
if (ret) {
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
goto err_free_pipes;
}
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
ath10k_pci_irq_disable(ar); ath10k_pci_irq_disable(ar);
if (ar_pci->pci_ps == 0) {
ret = ath10k_pci_force_wake(ar);
if (ret) {
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
goto err_free_pipes;
}
}
ret = ath10k_pci_init_irq(ar); ret = ath10k_pci_init_irq(ar);
if (ret) { if (ret) {
ath10k_err(ar, "failed to init irqs: %d\n", ret); ath10k_err(ar, "failed to init irqs: %d\n", ret);
......
...@@ -206,7 +206,7 @@ bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev) ...@@ -206,7 +206,7 @@ bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n", ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_ver(ah),
ah->eep_ops->get_eeprom_rev(ah)); ah->eep_ops->get_eeprom_rev(ah));
return -EINVAL; return false;
} }
return true; return true;
......
...@@ -834,7 +834,7 @@ void ath9k_htc_ani_work(struct work_struct *work) ...@@ -834,7 +834,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
if (longcal || shortcal) if (longcal || shortcal)
common->ani.caldone = common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan, ath9k_hw_calibrate(ah, ah->curchan,
ah->rxchainmask, longcal); ah->rxchainmask, longcal) > 0;
ath9k_htc_ps_restore(priv); ath9k_htc_ps_restore(priv);
} }
......
...@@ -828,6 +828,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -828,6 +828,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, RX_INCLUDES_FCS);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
if (ath9k_ps_enable) if (ath9k_ps_enable)
ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_PS);
......
...@@ -474,36 +474,37 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, ...@@ -474,36 +474,37 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
struct wcn36xx_dxe_desc *dxe = ctl->desc; struct wcn36xx_dxe_desc *dxe = ctl->desc;
dma_addr_t dma_addr; dma_addr_t dma_addr;
struct sk_buff *skb; struct sk_buff *skb;
int ret = 0, int_mask;
u32 value;
if (ch->ch_type == WCN36XX_DXE_CH_RX_L) {
value = WCN36XX_DXE_CTRL_RX_L;
int_mask = WCN36XX_DXE_INT_CH1_MASK;
} else {
value = WCN36XX_DXE_CTRL_RX_H;
int_mask = WCN36XX_DXE_INT_CH3_MASK;
}
while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
skb = ctl->skb; skb = ctl->skb;
dma_addr = dxe->dst_addr_l; dma_addr = dxe->dst_addr_l;
wcn36xx_dxe_fill_skb(wcn->dev, ctl); ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
if (0 == ret) {
switch (ch->ch_type) { /* new skb allocation ok. Use the new one and queue
case WCN36XX_DXE_CH_RX_L: * the old one to network system.
dxe->ctrl = WCN36XX_DXE_CTRL_RX_L; */
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
WCN36XX_DXE_INT_CH1_MASK); DMA_FROM_DEVICE);
break; wcn36xx_rx_skb(wcn, skb);
case WCN36XX_DXE_CH_RX_H: } /* else keep old skb not submitted and use it for rx DMA */
dxe->ctrl = WCN36XX_DXE_CTRL_RX_H;
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, dxe->ctrl = value;
WCN36XX_DXE_INT_CH3_MASK);
break;
default:
wcn36xx_warn("Unknown channel\n");
}
dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
DMA_FROM_DEVICE);
wcn36xx_rx_skb(wcn, skb);
ctl = ctl->next; ctl = ctl->next;
dxe = ctl->desc; dxe = ctl->desc;
} }
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask);
ch->head_blk_ctl = ctl; ch->head_blk_ctl = ctl;
return 0; return 0;
} }
......
...@@ -394,9 +394,13 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) ...@@ -394,9 +394,13 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
wil_fw_core_dump(wil); wil_fw_core_dump(wil);
wil_notify_fw_error(wil); wil_notify_fw_error(wil);
isr &= ~ISR_MISC_FW_ERROR; isr &= ~ISR_MISC_FW_ERROR;
wil_fw_error_recovery(wil); if (wil->platform_ops.notify_crash) {
wil_err(wil, "notify platform driver about FW crash");
wil->platform_ops.notify_crash(wil->platform_handle);
} else {
wil_fw_error_recovery(wil);
}
} }
if (isr & ISR_MISC_MBOX_EVT) { if (isr & ISR_MISC_MBOX_EVT) {
wil_dbg_irq(wil, "MBOX event\n"); wil_dbg_irq(wil, "MBOX event\n");
wmi_recv_cmd(wil); wmi_recv_cmd(wil);
......
...@@ -987,7 +987,7 @@ int __wil_down(struct wil6210_priv *wil) ...@@ -987,7 +987,7 @@ int __wil_down(struct wil6210_priv *wil)
} }
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
if (!iter) if (iter < 0)
wil_err(wil, "timeout waiting for idle FW/HW\n"); wil_err(wil, "timeout waiting for idle FW/HW\n");
wil_reset(wil, false); wil_reset(wil, false);
......
/* /*
* Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -125,11 +125,37 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil) ...@@ -125,11 +125,37 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil)
return 0; return 0;
} }
static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size)
{
struct wil6210_priv *wil = wil_handle;
if (!wil)
return -EINVAL;
return wil_fw_copy_crash_dump(wil, buf, size);
}
static int wil_platform_rop_fw_recovery(void *wil_handle)
{
struct wil6210_priv *wil = wil_handle;
if (!wil)
return -EINVAL;
wil_fw_error_recovery(wil);
return 0;
}
static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct wil6210_priv *wil; struct wil6210_priv *wil;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int rc; int rc;
const struct wil_platform_rops rops = {
.ramdump = wil_platform_rop_ramdump,
.fw_recovery = wil_platform_rop_fw_recovery,
};
/* check HW */ /* check HW */
dev_info(&pdev->dev, WIL_NAME dev_info(&pdev->dev, WIL_NAME
...@@ -154,7 +180,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -154,7 +180,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* rollback to if_free */ /* rollback to if_free */
wil->platform_handle = wil->platform_handle =
wil_platform_init(&pdev->dev, &wil->platform_ops); wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil);
if (!wil->platform_handle) { if (!wil->platform_handle) {
rc = -ENODEV; rc = -ENODEV;
wil_err(wil, "wil_platform_init failed\n"); wil_err(wil, "wil_platform_init failed\n");
......
...@@ -261,9 +261,19 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, ...@@ -261,9 +261,19 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
struct wil_tid_ampdu_rx *r) struct wil_tid_ampdu_rx *r)
{ {
int i;
if (!r) if (!r)
return; return;
wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
/* Do not pass remaining frames to the network stack - it may be
* not expecting to get any more Rx. Rx from here may lead to
* kernel OOPS since some per-socket accounting info was already
* released.
*/
for (i = 0; i < r->buf_size; i++)
kfree_skb(r->reorder_buf[i]);
kfree(r->reorder_buf); kfree(r->reorder_buf);
kfree(r->reorder_time); kfree(r->reorder_time);
kfree(r); kfree(r);
......
...@@ -828,6 +828,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); ...@@ -828,6 +828,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_resume(struct wil6210_priv *wil, bool is_runtime); int wil_resume(struct wil6210_priv *wil, bool is_runtime);
int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size);
void wil_fw_core_dump(struct wil6210_priv *wil); void wil_fw_core_dump(struct wil6210_priv *wil);
#endif /* __WIL6210_H__ */ #endif /* __WIL6210_H__ */
...@@ -51,8 +51,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, ...@@ -51,8 +51,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
return 0; return 0;
} }
static int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
u32 size)
{ {
int i; int i;
const struct fw_map *map; const struct fw_map *map;
......
...@@ -33,7 +33,8 @@ void wil_platform_modexit(void) ...@@ -33,7 +33,8 @@ void wil_platform_modexit(void)
* It returns a handle which is used with the rest of the API * It returns a handle which is used with the rest of the API
* *
*/ */
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops,
const struct wil_platform_rops *rops, void *wil_handle)
{ {
void *handle = ops; /* to return some non-NULL for 'void' impl. */ void *handle = ops; /* to return some non-NULL for 'void' impl. */
......
/* /*
* Copyright (c) 2014 Qualcomm Atheros, Inc. * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -20,16 +20,48 @@ ...@@ -20,16 +20,48 @@
struct device; struct device;
/** /**
* struct wil_platform_ops - wil platform module callbacks * struct wil_platform_ops - wil platform module calls from this
* driver to platform driver
*/ */
struct wil_platform_ops { struct wil_platform_ops {
int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
int (*suspend)(void *handle); int (*suspend)(void *handle);
int (*resume)(void *handle); int (*resume)(void *handle);
void (*uninit)(void *handle); void (*uninit)(void *handle);
int (*notify_crash)(void *handle);
}; };
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); /**
* struct wil_platform_rops - wil platform module callbacks from
* platform driver to this driver
* @ramdump: store a ramdump from the wil firmware. The platform
* driver may add additional data to the ramdump to
* generate the final crash dump.
* @fw_recovery: start a firmware recovery process. Called as
* part of a crash recovery process which may include other
* related platform subsystems.
*/
struct wil_platform_rops {
int (*ramdump)(void *wil_handle, void *buf, uint32_t size);
int (*fw_recovery)(void *wil_handle);
};
/**
* wil_platform_init - initialize the platform driver
*
* @dev - pointer to the wil6210 device
* @ops - structure with platform driver operations. Platform
* driver will fill this structure with function pointers.
* @rops - structure with callbacks from platform driver to
* this driver. The platform driver copies the structure to
* its own storage. Can be NULL if this driver does not
* support crash recovery.
* @wil_handle - context for this driver that will be passed
* when platform driver invokes one of the callbacks in
* rops. May be NULL if rops is NULL.
*/
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops,
const struct wil_platform_rops *rops, void *wil_handle);
int __init wil_platform_modinit(void); int __init wil_platform_modinit(void);
void wil_platform_modexit(void); void wil_platform_modexit(void);
......
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#include "debug.h" #include "debug.h"
#include "sdio.h" #include "sdio.h"
#include "of.h" #include "of.h"
#include "core.h"
#include "common.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2 #define SDIOH_API_ACCESS_RETRY_LIMIT 2
...@@ -57,7 +59,6 @@ ...@@ -57,7 +59,6 @@
/* Maximum milliseconds to wait for F2 to come up */ /* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000 #define SDIO_WAIT_F2RDY 3000
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */ #define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
struct brcmf_sdiod_freezer { struct brcmf_sdiod_freezer {
...@@ -68,10 +69,6 @@ struct brcmf_sdiod_freezer { ...@@ -68,10 +69,6 @@ struct brcmf_sdiod_freezer {
struct completion resumed; struct completion resumed;
}; };
static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id) static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
{ {
struct brcmf_bus *bus_if = dev_get_drvdata(dev_id); struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
...@@ -890,7 +887,8 @@ static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) ...@@ -890,7 +887,8 @@ static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
if (!sdiodev->sg_support) if (!sdiodev->sg_support)
return; return;
nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz); nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
sdiodev->bus_if->drvr->settings->sdiod_txglomsz);
nents += (nents >> 4) + 1; nents += (nents >> 4) + 1;
WARN_ON(nents > sdiodev->max_segment_count); WARN_ON(nents > sdiodev->max_segment_count);
...@@ -902,7 +900,7 @@ static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) ...@@ -902,7 +900,7 @@ static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
sdiodev->sg_support = false; sdiodev->sg_support = false;
} }
sdiodev->txglomsz = brcmf_sdiod_txglomsz; sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "cfg80211.h" #include "cfg80211.h"
/* T1 start SCO/eSCO priority suppression */ /* T1 start SCO/eSCO priority suppression */
#define BRCMF_BTCOEX_OPPR_WIN_TIME 2000 #define BRCMF_BTCOEX_OPPR_WIN_TIME msecs_to_jiffies(2000)
/* BT registers values during DHCP */ /* BT registers values during DHCP */
#define BRCMF_BT_DHCP_REG50 0x8022 #define BRCMF_BT_DHCP_REG50 0x8022
...@@ -314,8 +314,7 @@ static void brcmf_btcoex_handler(struct work_struct *work) ...@@ -314,8 +314,7 @@ static void brcmf_btcoex_handler(struct work_struct *work)
} else { } else {
btci->timeout -= BRCMF_BTCOEX_OPPR_WIN_TIME; btci->timeout -= BRCMF_BTCOEX_OPPR_WIN_TIME;
mod_timer(&btci->timer, mod_timer(&btci->timer,
jiffies + jiffies + BRCMF_BTCOEX_OPPR_WIN_TIME);
msecs_to_jiffies(BRCMF_BTCOEX_OPPR_WIN_TIME));
} }
btci->timer_on = true; btci->timer_on = true;
break; break;
...@@ -328,12 +327,11 @@ static void brcmf_btcoex_handler(struct work_struct *work) ...@@ -328,12 +327,11 @@ static void brcmf_btcoex_handler(struct work_struct *work)
/* DHCP is not over yet, start lowering BT priority */ /* DHCP is not over yet, start lowering BT priority */
brcmf_dbg(INFO, "DHCP T1:%d expired\n", brcmf_dbg(INFO, "DHCP T1:%d expired\n",
BRCMF_BTCOEX_OPPR_WIN_TIME); jiffies_to_msecs(BRCMF_BTCOEX_OPPR_WIN_TIME));
brcmf_btcoex_boost_wifi(btci, true); brcmf_btcoex_boost_wifi(btci, true);
btci->bt_state = BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT; btci->bt_state = BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT;
mod_timer(&btci->timer, mod_timer(&btci->timer, jiffies + btci->timeout);
jiffies + msecs_to_jiffies(btci->timeout));
btci->timer_on = true; btci->timer_on = true;
break; break;
...@@ -477,7 +475,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif, ...@@ -477,7 +475,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
return -EBUSY; return -EBUSY;
/* Start BT timer only for SCO connection */ /* Start BT timer only for SCO connection */
if (brcmf_btcoex_is_sco_active(ifp)) { if (brcmf_btcoex_is_sco_active(ifp)) {
btci->timeout = duration; btci->timeout = msecs_to_jiffies(duration);
btci->vif = vif; btci->vif = vif;
brcmf_btcoex_dhcp_start(btci); brcmf_btcoex_dhcp_start(btci);
} }
......
...@@ -75,6 +75,8 @@ ...@@ -75,6 +75,8 @@
#define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2 #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2
#define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF 4 #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_OFF 4
#define BRCMF_VIF_EVENT_TIMEOUT msecs_to_jiffies(1500)
/** /**
* enum brcmf_scan_status - scan engine status * enum brcmf_scan_status - scan engine status
* *
...@@ -226,6 +228,27 @@ struct brcmf_cfg80211_vif_event { ...@@ -226,6 +228,27 @@ struct brcmf_cfg80211_vif_event {
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_vif *vif;
}; };
/**
* struct brcmf_cfg80211_wowl - wowl related information.
*
* @active: set on suspend, cleared on resume.
* @pre_pmmode: firmware PM mode at entering suspend.
* @nd: net dectect data.
* @nd_info: helper struct to pass to cfg80211.
* @nd_data_wait: wait queue to sync net detect data.
* @nd_data_completed: completion for net detect data.
* @nd_enabled: net detect enabled.
*/
struct brcmf_cfg80211_wowl {
bool active;
u32 pre_pmmode;
struct cfg80211_wowlan_nd_match *nd;
struct cfg80211_wowlan_nd_info *nd_info;
wait_queue_head_t nd_data_wait;
bool nd_data_completed;
bool nd_enabled;
};
/** /**
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
* *
...@@ -259,8 +282,7 @@ struct brcmf_cfg80211_vif_event { ...@@ -259,8 +282,7 @@ struct brcmf_cfg80211_vif_event {
* @vif_list: linked list of vif instances. * @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances. * @vif_cnt: number of vif instances.
* @vif_event: vif event signalling. * @vif_event: vif event signalling.
* @wowl_enabled; set during suspend, is wowl used. * @wowl: wowl related information.
* @pre_wowl_pmmode: intermediate storage of pm mode during wowl.
*/ */
struct brcmf_cfg80211_info { struct brcmf_cfg80211_info {
struct wiphy *wiphy; struct wiphy *wiphy;
...@@ -292,9 +314,8 @@ struct brcmf_cfg80211_info { ...@@ -292,9 +314,8 @@ struct brcmf_cfg80211_info {
struct brcmf_cfg80211_vif_event vif_event; struct brcmf_cfg80211_vif_event vif_event;
struct completion vif_disabled; struct completion vif_disabled;
struct brcmu_d11inf d11inf; struct brcmu_d11inf d11inf;
bool wowl_enabled;
u32 pre_wowl_pmmode;
struct brcmf_assoclist_le assoclist; struct brcmf_assoclist_le assoclist;
struct brcmf_cfg80211_wowl wowl;
}; };
/** /**
......
...@@ -35,6 +35,47 @@ const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ...@@ -35,6 +35,47 @@ const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* boost value for RSSI_DELTA in preferred join selection */ /* boost value for RSSI_DELTA in preferred join selection */
#define BRCMF_JOIN_PREF_RSSI_BOOST 8 #define BRCMF_JOIN_PREF_RSSI_BOOST 8
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
/* Debug level configuration. See debug.h for bits, sysfs modifiable */
int brcmf_msg_level;
module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(debug, "Level of debug output");
static int brcmf_p2p_enable;
module_param_named(p2pon, brcmf_p2p_enable, int, 0);
MODULE_PARM_DESC(p2pon, "Enable legacy p2p management functionality");
static int brcmf_feature_disable;
module_param_named(feature_disable, brcmf_feature_disable, int, 0);
MODULE_PARM_DESC(feature_disable, "Disable features");
static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
module_param_string(alternative_fw_path, brcmf_firmware_path,
BRCMF_FW_ALTPATH_LEN, S_IRUSR);
MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
static int brcmf_fcmode;
module_param_named(fcmode, brcmf_fcmode, int, 0);
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
static int brcmf_roamoff;
module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
#ifdef DEBUG
/* always succeed brcmf_bus_start() */
static int brcmf_ignore_probe_fail;
module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
#endif
struct brcmf_mp_global_t brcmf_mp_global;
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{ {
s8 eventmask[BRCMF_EVENTING_MASK_LEN]; s8 eventmask[BRCMF_EVENTING_MASK_LEN];
...@@ -178,3 +219,34 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...) ...@@ -178,3 +219,34 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
va_end(args); va_end(args);
} }
#endif #endif
void brcmf_mp_attach(void)
{
strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
BRCMF_FW_ALTPATH_LEN);
}
int brcmf_mp_device_attach(struct brcmf_pub *drvr)
{
drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
if (!drvr->settings) {
brcmf_err("Failed to alloca storage space for settings\n");
return -ENOMEM;
}
drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz;
drvr->settings->p2p_enable = !!brcmf_p2p_enable;
drvr->settings->feature_disable = brcmf_feature_disable;
drvr->settings->fcmode = brcmf_fcmode;
drvr->settings->roamoff = !!brcmf_roamoff;
#ifdef DEBUG
drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif
return 0;
}
void brcmf_mp_device_detach(struct brcmf_pub *drvr)
{
kfree(drvr->settings);
}
...@@ -17,6 +17,62 @@ ...@@ -17,6 +17,62 @@
extern const u8 ALLFFMAC[ETH_ALEN]; extern const u8 ALLFFMAC[ETH_ALEN];
#define BRCMF_FW_ALTPATH_LEN 256
/* Definitions for the module global and device specific settings are defined
* here. Two structs are used for them. brcmf_mp_global_t and brcmf_mp_device.
* The mp_global is instantiated once in a global struct and gets initialized
* by the common_attach function which should be called before any other
* (module) initiliazation takes place. The device specific settings is part
* of the drvr struct and should be initialized on every brcmf_attach.
*/
/**
* struct brcmf_mp_global_t - Global module paramaters.
*
* @firmware_path: Alternative firmware path.
*/
struct brcmf_mp_global_t {
char firmware_path[BRCMF_FW_ALTPATH_LEN];
};
extern struct brcmf_mp_global_t brcmf_mp_global;
/**
* struct brcmf_mp_device - Device module paramaters.
*
* @sdiod_txglomsz: SDIO txglom size.
* @joinboost_5g_rssi: 5g rssi booost for preferred join selection.
* @p2p_enable: Legacy P2P0 enable (old wpa_supplicant).
* @feature_disable: Feature_disable bitmask.
* @fcmode: FWS flow control.
* @roamoff: Firmware roaming off?
*/
struct brcmf_mp_device {
int sdiod_txglomsz;
int joinboost_5g_rssi;
bool p2p_enable;
int feature_disable;
int fcmode;
bool roamoff;
bool ignore_probe_fail;
};
void brcmf_mp_attach(void);
int brcmf_mp_device_attach(struct brcmf_pub *drvr);
void brcmf_mp_device_detach(struct brcmf_pub *drvr);
#ifdef DEBUG
static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
{
return drvr->settings->ignore_probe_fail;
}
#else
static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
{
return false;
}
#endif
/* Sets dongle media info (drv_version, mac address). */ /* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/inetdevice.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <brcmu_utils.h> #include <brcmu_utils.h>
...@@ -39,7 +40,7 @@ MODULE_AUTHOR("Broadcom Corporation"); ...@@ -39,7 +40,7 @@ MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */ #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(50)
/* AMPDU rx reordering definitions */ /* AMPDU rx reordering definitions */
#define BRCMF_RXREORDER_FLOWID_OFFSET 0 #define BRCMF_RXREORDER_FLOWID_OFFSET 0
...@@ -56,16 +57,6 @@ MODULE_LICENSE("Dual BSD/GPL"); ...@@ -56,16 +57,6 @@ MODULE_LICENSE("Dual BSD/GPL");
#define BRCMF_BSSIDX_INVALID -1 #define BRCMF_BSSIDX_INVALID -1
/* Error bits */
int brcmf_msg_level;
module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(debug, "level of debug output");
/* P2P0 enable */
static int brcmf_p2p_enable;
module_param_named(p2pon, brcmf_p2p_enable, int, 0);
MODULE_PARM_DESC(p2pon, "enable legacy p2p management functionality");
char *brcmf_ifname(struct brcmf_if *ifp) char *brcmf_ifname(struct brcmf_if *ifp)
{ {
if (!ifp) if (!ifp)
...@@ -620,6 +611,8 @@ static int brcmf_netdev_stop(struct net_device *ndev) ...@@ -620,6 +611,8 @@ static int brcmf_netdev_stop(struct net_device *ndev)
brcmf_cfg80211_down(ndev); brcmf_cfg80211_down(ndev);
brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
brcmf_net_setcarrier(ifp, false); brcmf_net_setcarrier(ifp, false);
return 0; return 0;
...@@ -824,7 +817,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, ...@@ -824,7 +817,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
} }
} }
if (!brcmf_p2p_enable && is_p2pdev) { if (!drvr->settings->p2p_enable && is_p2pdev) {
/* this is P2P_DEVICE interface */ /* this is P2P_DEVICE interface */
brcmf_dbg(INFO, "allocate non-netdev interface\n"); brcmf_dbg(INFO, "allocate non-netdev interface\n");
ifp = kzalloc(sizeof(*ifp), GFP_KERNEL); ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
...@@ -940,6 +933,98 @@ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) ...@@ -940,6 +933,98 @@ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
return available ? bsscfgidx : -ENOMEM; return available ? bsscfgidx : -ENOMEM;
} }
#ifdef CONFIG_INET
#define ARPOL_MAX_ENTRIES 8
static int brcmf_inetaddr_changed(struct notifier_block *nb,
unsigned long action, void *data)
{
struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
inetaddr_notifier);
struct in_ifaddr *ifa = data;
struct net_device *ndev = ifa->ifa_dev->dev;
struct brcmf_if *ifp;
int idx, i, ret;
u32 val;
__be32 addr_table[ARPOL_MAX_ENTRIES] = {0};
/* Find out if the notification is meant for us */
for (idx = 0; idx < BRCMF_MAX_IFS; idx++) {
ifp = drvr->iflist[idx];
if (ifp && ifp->ndev == ndev)
break;
if (idx == BRCMF_MAX_IFS - 1)
return NOTIFY_DONE;
}
/* check if arp offload is supported */
ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
if (ret)
return NOTIFY_OK;
/* old version only support primary index */
ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
if (ret)
val = 1;
if (val == 1)
ifp = drvr->iflist[0];
/* retrieve the table from firmware */
ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
sizeof(addr_table));
if (ret) {
brcmf_err("fail to get arp ip table err:%d\n", ret);
return NOTIFY_OK;
}
for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
if (ifa->ifa_address == addr_table[i])
break;
switch (action) {
case NETDEV_UP:
if (i == ARPOL_MAX_ENTRIES) {
brcmf_dbg(TRACE, "add %pI4 to arp table\n",
&ifa->ifa_address);
/* set it directly */
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
&ifa->ifa_address, sizeof(ifa->ifa_address));
if (ret)
brcmf_err("add arp ip err %d\n", ret);
}
break;
case NETDEV_DOWN:
if (i < ARPOL_MAX_ENTRIES) {
addr_table[i] = 0;
brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
&ifa->ifa_address);
/* clear the table in firmware */
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
NULL, 0);
if (ret) {
brcmf_err("fail to clear arp ip table err:%d\n",
ret);
return NOTIFY_OK;
}
for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
if (addr_table[i] != 0) {
brcmf_fil_iovar_data_set(ifp,
"arp_hostip", &addr_table[i],
sizeof(addr_table[i]));
if (ret)
brcmf_err("add arp ip err %d\n",
ret);
}
}
}
break;
default:
break;
}
return NOTIFY_OK;
}
#endif
int brcmf_attach(struct device *dev) int brcmf_attach(struct device *dev)
{ {
struct brcmf_pub *drvr = NULL; struct brcmf_pub *drvr = NULL;
...@@ -963,6 +1048,10 @@ int brcmf_attach(struct device *dev) ...@@ -963,6 +1048,10 @@ int brcmf_attach(struct device *dev)
drvr->bus_if = dev_get_drvdata(dev); drvr->bus_if = dev_get_drvdata(dev);
drvr->bus_if->drvr = drvr; drvr->bus_if->drvr = drvr;
/* Initialize device specific settings */
if (brcmf_mp_device_attach(drvr))
goto fail;
/* attach debug facilities */ /* attach debug facilities */
brcmf_debug_attach(drvr); brcmf_debug_attach(drvr);
...@@ -1055,7 +1144,7 @@ int brcmf_bus_start(struct device *dev) ...@@ -1055,7 +1144,7 @@ int brcmf_bus_start(struct device *dev)
brcmf_fws_add_interface(ifp); brcmf_fws_add_interface(ifp);
drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev, drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
brcmf_p2p_enable); drvr->settings->p2p_enable);
if (drvr->config == NULL) { if (drvr->config == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
...@@ -1063,11 +1152,20 @@ int brcmf_bus_start(struct device *dev) ...@@ -1063,11 +1152,20 @@ int brcmf_bus_start(struct device *dev)
ret = brcmf_net_attach(ifp, false); ret = brcmf_net_attach(ifp, false);
if ((!ret) && (brcmf_p2p_enable)) { if ((!ret) && (drvr->settings->p2p_enable)) {
p2p_ifp = drvr->iflist[1]; p2p_ifp = drvr->iflist[1];
if (p2p_ifp) if (p2p_ifp)
ret = brcmf_net_p2p_attach(p2p_ifp); ret = brcmf_net_p2p_attach(p2p_ifp);
} }
if (ret)
goto fail;
#ifdef CONFIG_INET
drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
#endif
fail: fail:
if (ret < 0) { if (ret < 0) {
brcmf_err("failed: %d\n", ret); brcmf_err("failed: %d\n", ret);
...@@ -1085,6 +1183,8 @@ int brcmf_bus_start(struct device *dev) ...@@ -1085,6 +1183,8 @@ int brcmf_bus_start(struct device *dev)
brcmf_net_detach(p2p_ifp->ndev); brcmf_net_detach(p2p_ifp->ndev);
drvr->iflist[0] = NULL; drvr->iflist[0] = NULL;
drvr->iflist[1] = NULL; drvr->iflist[1] = NULL;
if (brcmf_ignoring_probe_fail(drvr))
ret = 0;
return ret; return ret;
} }
return 0; return 0;
...@@ -1133,6 +1233,10 @@ void brcmf_detach(struct device *dev) ...@@ -1133,6 +1233,10 @@ void brcmf_detach(struct device *dev)
if (drvr == NULL) if (drvr == NULL)
return; return;
#ifdef CONFIG_INET
unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
#endif
/* stop firmware event handling */ /* stop firmware event handling */
brcmf_fweh_detach(drvr); brcmf_fweh_detach(drvr);
if (drvr->config) if (drvr->config)
...@@ -1152,6 +1256,8 @@ void brcmf_detach(struct device *dev) ...@@ -1152,6 +1256,8 @@ void brcmf_detach(struct device *dev)
brcmf_proto_detach(drvr); brcmf_proto_detach(drvr);
brcmf_mp_device_detach(drvr);
brcmf_debug_detach(drvr); brcmf_debug_detach(drvr);
bus_if->drvr = NULL; bus_if->drvr = NULL;
kfree(drvr); kfree(drvr);
...@@ -1176,7 +1282,7 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp) ...@@ -1176,7 +1282,7 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
err = wait_event_timeout(ifp->pend_8021x_wait, err = wait_event_timeout(ifp->pend_8021x_wait,
!brcmf_get_pend_8021x_cnt(ifp), !brcmf_get_pend_8021x_cnt(ifp),
msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); MAX_WAIT_FOR_8021X_TX);
WARN_ON(!err); WARN_ON(!err);
......
...@@ -69,8 +69,8 @@ struct brcmf_ampdu_rx_reorder { ...@@ -69,8 +69,8 @@ struct brcmf_ampdu_rx_reorder {
/* Forward decls for struct brcmf_pub (see below) */ /* Forward decls for struct brcmf_pub (see below) */
struct brcmf_proto; /* device communication protocol info */ struct brcmf_proto; /* device communication protocol info */
struct brcmf_cfg80211_dev; /* cfg80211 device info */ struct brcmf_fws_info; /* firmware signalling info */
struct brcmf_fws_info; /* firmware signalling info */ struct brcmf_mp_device; /* module paramateres, device specific */
/* /*
* struct brcmf_rev_info * struct brcmf_rev_info
...@@ -141,6 +141,9 @@ struct brcmf_pub { ...@@ -141,6 +141,9 @@ struct brcmf_pub {
#ifdef DEBUG #ifdef DEBUG
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
#endif #endif
struct notifier_block inetaddr_notifier;
struct brcmf_mp_device *settings;
}; };
/* forward declarations */ /* forward declarations */
......
...@@ -18,18 +18,16 @@ ...@@ -18,18 +18,16 @@
#include <linux/module.h> #include <linux/module.h>
#include <brcm_hw_ids.h> #include <brcm_hw_ids.h>
#include <brcmu_wifi.h>
#include "core.h" #include "core.h"
#include "bus.h" #include "bus.h"
#include "debug.h" #include "debug.h"
#include "fwil.h" #include "fwil.h"
#include "fwil_types.h"
#include "feature.h" #include "feature.h"
#include "common.h"
/* Module param feature_disable (global for all devices) */
static int brcmf_feature_disable;
module_param_named(feature_disable, brcmf_feature_disable, int, 0);
MODULE_PARM_DESC(feature_disable, "Disable features");
/* /*
* expand feature list to array of feature strings. * expand feature list to array of feature strings.
*/ */
...@@ -40,6 +38,17 @@ static const char *brcmf_feat_names[] = { ...@@ -40,6 +38,17 @@ static const char *brcmf_feat_names[] = {
}; };
#undef BRCMF_FEAT_DEF #undef BRCMF_FEAT_DEF
struct brcmf_feat_fwcap {
enum brcmf_feat_id feature;
const char * const fwcap_id;
};
static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
{ BRCMF_FEAT_MBSS, "mbss" },
{ BRCMF_FEAT_MCHAN, "mchan" },
{ BRCMF_FEAT_P2P, "p2p" },
};
#ifdef DEBUG #ifdef DEBUG
/* /*
* expand quirk list to array of quirk strings. * expand quirk list to array of quirk strings.
...@@ -104,46 +113,53 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, ...@@ -104,46 +113,53 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
} }
} }
/** static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
* brcmf_feat_iovar_int_set() - determine feature through iovar set.
*
* @ifp: interface to query.
* @id: feature id.
* @name: iovar name.
*/
static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp,
enum brcmf_feat_id id, char *name, u32 val)
{ {
int err; char caps[256];
enum brcmf_feat_id id;
err = brcmf_fil_iovar_int_set(ifp, name, val); int i;
if (err == 0) {
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps));
ifp->drvr->feat_flags |= BIT(id); brcmf_dbg(INFO, "[ %s]\n", caps);
} else {
brcmf_dbg(TRACE, "%s feature check failed: %d\n", for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) {
brcmf_feat_names[id], err); if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) {
id = brcmf_fwcap_map[i].feature;
brcmf_dbg(INFO, "enabling feature: %s\n",
brcmf_feat_names[id]);
ifp->drvr->feat_flags |= BIT(id);
}
} }
} }
void brcmf_feat_attach(struct brcmf_pub *drvr) void brcmf_feat_attach(struct brcmf_pub *drvr)
{ {
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
struct brcmf_pno_macaddr_le pfn_mac;
s32 err;
brcmf_feat_firmware_capabilities(ifp);
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
if (drvr->bus_if->wowl_supported) if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID) /* MBSS does not work for 43362 */
brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p"); ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
if (brcmf_feature_disable) { pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
sizeof(pfn_mac));
if (!err)
ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
if (drvr->settings->feature_disable) {
brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
ifp->drvr->feat_flags, brcmf_feature_disable); ifp->drvr->feat_flags,
ifp->drvr->feat_flags &= ~brcmf_feature_disable; drvr->settings->feature_disable);
ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
} }
/* set chip related quirks */ /* set chip related quirks */
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* P2P: peer-to-peer * P2P: peer-to-peer
* RSDB: Real Simultaneous Dual Band * RSDB: Real Simultaneous Dual Band
* TDLS: Tunneled Direct Link Setup * TDLS: Tunneled Direct Link Setup
* SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan.
*/ */
#define BRCMF_FEAT_LIST \ #define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \ BRCMF_FEAT_DEF(MBSS) \
...@@ -34,7 +35,8 @@ ...@@ -34,7 +35,8 @@
BRCMF_FEAT_DEF(WOWL) \ BRCMF_FEAT_DEF(WOWL) \
BRCMF_FEAT_DEF(P2P) \ BRCMF_FEAT_DEF(P2P) \
BRCMF_FEAT_DEF(RSDB) \ BRCMF_FEAT_DEF(RSDB) \
BRCMF_FEAT_DEF(TDLS) BRCMF_FEAT_DEF(TDLS) \
BRCMF_FEAT_DEF(SCAN_RANDOM_MAC)
/* /*
* Quirks: * Quirks:
......
...@@ -23,15 +23,13 @@ ...@@ -23,15 +23,13 @@
#include "debug.h" #include "debug.h"
#include "firmware.h" #include "firmware.h"
#include "core.h"
#include "common.h"
#define BRCMF_FW_MAX_NVRAM_SIZE 64000 #define BRCMF_FW_MAX_NVRAM_SIZE 64000
#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */ #define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
#define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */ #define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
static char brcmf_firmware_path[BRCMF_FW_NAME_LEN];
module_param_string(alternative_fw_path, brcmf_firmware_path,
BRCMF_FW_NAME_LEN, 0440);
enum nvram_parser_state { enum nvram_parser_state {
IDLE, IDLE,
KEY, KEY,
...@@ -559,13 +557,15 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, ...@@ -559,13 +557,15 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
} }
/* check if firmware path is provided by module parameter */ /* check if firmware path is provided by module parameter */
if (brcmf_firmware_path[0] != '\0') { if (brcmf_mp_global.firmware_path[0] != '\0') {
strlcpy(fw_name, brcmf_firmware_path, BRCMF_FW_NAME_LEN); strlcpy(fw_name, brcmf_mp_global.firmware_path,
BRCMF_FW_NAME_LEN);
if ((nvram_name) && (mapping_table[i].nvram)) if ((nvram_name) && (mapping_table[i].nvram))
strlcpy(nvram_name, brcmf_firmware_path, strlcpy(nvram_name, brcmf_mp_global.firmware_path,
BRCMF_FW_NAME_LEN); BRCMF_FW_NAME_LEN);
end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1]; end = brcmf_mp_global.firmware_path[
strlen(brcmf_mp_global.firmware_path) - 1];
if (end != '/') { if (end != '/') {
strlcat(fw_name, "/", BRCMF_FW_NAME_LEN); strlcat(fw_name, "/", BRCMF_FW_NAME_LEN);
if ((nvram_name) && (mapping_table[i].nvram)) if ((nvram_name) && (mapping_table[i].nvram))
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#define BRCMF_C_SET_WSEC 134 #define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135 #define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136 #define BRCMF_C_GET_BSS_INFO 136
#define BRCMF_C_GET_GET_PKTCNTS 137
#define BRCMF_C_GET_BANDLIST 140 #define BRCMF_C_GET_BANDLIST 140
#define BRCMF_C_SET_SCB_TIMEOUT 158 #define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_ASSOCLIST 159 #define BRCMF_C_GET_ASSOCLIST 159
......
...@@ -110,6 +110,8 @@ ...@@ -110,6 +110,8 @@
#define BRCMF_WOWL_UNASSOC (1 << 24) #define BRCMF_WOWL_UNASSOC (1 << 24)
/* Wakeup if received matched secured pattern: */ /* Wakeup if received matched secured pattern: */
#define BRCMF_WOWL_SECURE (1 << 25) #define BRCMF_WOWL_SECURE (1 << 25)
/* Wakeup on finding preferred network */
#define BRCMF_WOWL_PFN_FOUND (1 << 26)
/* Link Down indication in WoWL mode: */ /* Link Down indication in WoWL mode: */
#define BRCMF_WOWL_LINKDOWN (1 << 31) #define BRCMF_WOWL_LINKDOWN (1 << 31)
...@@ -128,6 +130,10 @@ ...@@ -128,6 +130,10 @@
#define BRCMF_MAXPMKID 16 /* max # PMKID cache entries */ #define BRCMF_MAXPMKID 16 /* max # PMKID cache entries */
#define BRCMF_PFN_MACADDR_CFG_VER 1
#define BRCMF_PFN_MAC_OUI_ONLY BIT(0)
#define BRCMF_PFN_SET_MAC_UNASSOC BIT(1)
/* join preference types for join_pref iovar */ /* join preference types for join_pref iovar */
enum brcmf_join_pref_types { enum brcmf_join_pref_types {
BRCMF_JOIN_PREF_RSSI = 1, BRCMF_JOIN_PREF_RSSI = 1,
...@@ -751,4 +757,34 @@ struct brcmf_pno_scanresults_le { ...@@ -751,4 +757,34 @@ struct brcmf_pno_scanresults_le {
__le32 count; __le32 count;
}; };
/**
* struct brcmf_pno_macaddr_le - to configure PNO macaddr randomization.
*
* @version: PNO version identifier.
* @flags: Flags defining how mac addrss should be used.
* @mac: MAC address.
*/
struct brcmf_pno_macaddr_le {
u8 version;
u8 flags;
u8 mac[ETH_ALEN];
};
/**
* struct brcmf_pktcnt_le - packet counters.
*
* @rx_good_pkt: packets (MSDUs & MMPDUs) received from this station
* @rx_bad_pkt: failed rx packets
* @tx_good_pkt: packets (MSDUs & MMPDUs) transmitted to this station
* @tx_bad_pkt: failed tx packets
* @rx_ocast_good_pkt: unicast packets destined for others
*/
struct brcmf_pktcnt_le {
__le32 rx_good_pkt;
__le32 rx_bad_pkt;
__le32 tx_good_pkt;
__le32 tx_bad_pkt;
__le32 rx_ocast_good_pkt;
};
#endif /* FWIL_TYPES_H_ */ #endif /* FWIL_TYPES_H_ */
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "p2p.h" #include "p2p.h"
#include "cfg80211.h" #include "cfg80211.h"
#include "proto.h" #include "proto.h"
#include "common.h"
/** /**
* DOC: Firmware Signalling * DOC: Firmware Signalling
...@@ -521,10 +522,6 @@ static const int brcmf_fws_prio2fifo[] = { ...@@ -521,10 +522,6 @@ static const int brcmf_fws_prio2fifo[] = {
BRCMF_FWS_FIFO_AC_VO BRCMF_FWS_FIFO_AC_VO
}; };
static int fcmode;
module_param(fcmode, int, S_IRUSR);
MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
#define BRCMF_FWS_TLV_DEF(name, id, len) \ #define BRCMF_FWS_TLV_DEF(name, id, len) \
case BRCMF_FWS_TYPE_ ## name: \ case BRCMF_FWS_TYPE_ ## name: \
return len; return len;
...@@ -2134,10 +2131,10 @@ int brcmf_fws_init(struct brcmf_pub *drvr) ...@@ -2134,10 +2131,10 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
/* set linkage back */ /* set linkage back */
fws->drvr = drvr; fws->drvr = drvr;
fws->fcmode = fcmode; fws->fcmode = drvr->settings->fcmode;
if ((drvr->bus_if->always_use_fws_queue == false) && if ((drvr->bus_if->always_use_fws_queue == false) &&
(fcmode == BRCMF_FWS_FCMODE_NONE)) { (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
fws->avoid_queueing = true; fws->avoid_queueing = true;
brcmf_dbg(INFO, "FWS queueing will be avoided\n"); brcmf_dbg(INFO, "FWS queueing will be avoided\n");
return 0; return 0;
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "tracepoint.h" #include "tracepoint.h"
#define MSGBUF_IOCTL_RESP_TIMEOUT 2000 #define MSGBUF_IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
#define MSGBUF_TYPE_GEN_STATUS 0x1 #define MSGBUF_TYPE_GEN_STATUS 0x1
#define MSGBUF_TYPE_RING_STATUS 0x2 #define MSGBUF_TYPE_RING_STATUS 0x2
...@@ -466,7 +466,7 @@ static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf) ...@@ -466,7 +466,7 @@ static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf)
{ {
return wait_event_timeout(msgbuf->ioctl_resp_wait, return wait_event_timeout(msgbuf->ioctl_resp_wait,
msgbuf->ctl_completed, msgbuf->ctl_completed,
msecs_to_jiffies(MSGBUF_IOCTL_RESP_TIMEOUT)); MSGBUF_IOCTL_RESP_TIMEOUT);
} }
......
...@@ -71,10 +71,10 @@ ...@@ -71,10 +71,10 @@
#define P2P_AF_MED_DWELL_TIME 400 #define P2P_AF_MED_DWELL_TIME 400
#define P2P_AF_LONG_DWELL_TIME 1000 #define P2P_AF_LONG_DWELL_TIME 1000
#define P2P_AF_TX_MAX_RETRY 1 #define P2P_AF_TX_MAX_RETRY 1
#define P2P_AF_MAX_WAIT_TIME 2000 #define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)
#define P2P_INVALID_CHANNEL -1 #define P2P_INVALID_CHANNEL -1
#define P2P_CHANNEL_SYNC_RETRY 5 #define P2P_CHANNEL_SYNC_RETRY 5
#define P2P_AF_FRM_SCAN_MAX_WAIT 1500 #define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(1500)
#define P2P_DEFAULT_SLEEP_TIME_VSDB 200 #define P2P_DEFAULT_SLEEP_TIME_VSDB 200
/* WiFi P2P Public Action Frame OUI Subtypes */ /* WiFi P2P Public Action Frame OUI Subtypes */
...@@ -102,6 +102,7 @@ ...@@ -102,6 +102,7 @@
#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ #define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */
#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ #define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
#define BRCMF_P2P_DISABLE_TIMEOUT msecs_to_jiffies(500)
/** /**
* struct brcmf_p2p_disc_st_le - set discovery state in firmware. * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
* *
...@@ -1514,7 +1515,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, ...@@ -1514,7 +1515,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
p2p->af_tx_sent_jiffies = jiffies; p2p->af_tx_sent_jiffies = jiffies;
timeout = wait_for_completion_timeout(&p2p->send_af_done, timeout = wait_for_completion_timeout(&p2p->send_af_done,
msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME)); P2P_AF_MAX_WAIT_TIME);
if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) { if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {
brcmf_dbg(TRACE, "TX action frame operation is success\n"); brcmf_dbg(TRACE, "TX action frame operation is success\n");
...@@ -1988,7 +1989,7 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, ...@@ -1988,7 +1989,7 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
return err; return err;
} }
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
msecs_to_jiffies(1500)); BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(cfg, NULL); brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) { if (!err) {
brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
...@@ -2090,7 +2091,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, ...@@ -2090,7 +2091,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
/* wait for firmware event */ /* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD, err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
msecs_to_jiffies(1500)); BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL); brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
brcmf_fweh_p2pdev_setup(pri_ifp, false); brcmf_fweh_p2pdev_setup(pri_ifp, false);
if (!err) { if (!err) {
...@@ -2180,7 +2181,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, ...@@ -2180,7 +2181,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
/* wait for firmware event */ /* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
msecs_to_jiffies(1500)); BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(cfg, NULL); brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) { if (!err) {
brcmf_err("timeout occurred\n"); brcmf_err("timeout occurred\n");
...@@ -2230,7 +2231,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2230,7 +2231,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_p2p_info *p2p = &cfg->p2p; struct brcmf_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_vif *vif;
unsigned long jiffie_timeout = msecs_to_jiffies(1500);
bool wait_for_disable = false; bool wait_for_disable = false;
int err; int err;
...@@ -2263,7 +2263,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2263,7 +2263,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
if (wait_for_disable) if (wait_for_disable)
wait_for_completion_timeout(&cfg->vif_disabled, wait_for_completion_timeout(&cfg->vif_disabled,
msecs_to_jiffies(500)); BRCMF_P2P_DISABLE_TIMEOUT);
err = 0; err = 0;
if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) { if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) {
...@@ -2273,7 +2273,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2273,7 +2273,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
if (!err) { if (!err) {
/* wait for firmware event */ /* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
jiffie_timeout); BRCMF_VIF_EVENT_TIMEOUT);
if (!err) if (!err)
err = -EIO; err = -EIO;
else else
......
...@@ -191,7 +191,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { ...@@ -191,7 +191,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_H2D_HOST_D0_INFORM_IN_USE 0x00000008 #define BRCMF_H2D_HOST_D0_INFORM_IN_USE 0x00000008
#define BRCMF_H2D_HOST_D0_INFORM 0x00000010 #define BRCMF_H2D_HOST_D0_INFORM 0x00000010
#define BRCMF_PCIE_MBDATA_TIMEOUT 2000 #define BRCMF_PCIE_MBDATA_TIMEOUT msecs_to_jiffies(2000)
#define BRCMF_PCIE_CFGREG_STATUS_CMD 0x4 #define BRCMF_PCIE_CFGREG_STATUS_CMD 0x4
#define BRCMF_PCIE_CFGREG_PM_CSR 0x4C #define BRCMF_PCIE_CFGREG_PM_CSR 0x4C
...@@ -1885,9 +1885,8 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev) ...@@ -1885,9 +1885,8 @@ static int brcmf_pcie_pm_enter_D3(struct device *dev)
devinfo->mbdata_completed = false; devinfo->mbdata_completed = false;
brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM); brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM);
wait_event_timeout(devinfo->mbdata_resp_wait, wait_event_timeout(devinfo->mbdata_resp_wait, devinfo->mbdata_completed,
devinfo->mbdata_completed, BRCMF_PCIE_MBDATA_TIMEOUT);
msecs_to_jiffies(BRCMF_PCIE_MBDATA_TIMEOUT));
if (!devinfo->mbdata_completed) { if (!devinfo->mbdata_completed) {
brcmf_err("Timeout on response for entering D3 substate\n"); brcmf_err("Timeout on response for entering D3 substate\n");
return -EIO; return -EIO;
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
#include "chip.h" #include "chip.h"
#include "firmware.h" #include "firmware.h"
#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000)
#define CTL_DONE_TIMEOUT 2000 /* In milli second */ #define CTL_DONE_TIMEOUT msecs_to_jiffies(2000)
#ifdef DEBUG #ifdef DEBUG
...@@ -503,8 +503,7 @@ struct brcmf_sdio { ...@@ -503,8 +503,7 @@ struct brcmf_sdio {
struct timer_list timer; struct timer_list timer;
struct completion watchdog_wait; struct completion watchdog_wait;
struct task_struct *watchdog_tsk; struct task_struct *watchdog_tsk;
bool wd_timer_valid; bool wd_active;
uint save_ms;
struct workqueue_struct *brcmf_wq; struct workqueue_struct *brcmf_wq;
struct work_struct datawork; struct work_struct datawork;
...@@ -961,7 +960,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) ...@@ -961,7 +960,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
brcmf_sdio_clkctl(bus, CLK_NONE, pendok); brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
} else { } else {
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); brcmf_sdio_wd_timer(bus, true);
} }
bus->sleeping = sleep; bus->sleeping = sleep;
brcmf_dbg(SDIO, "new state %s\n", brcmf_dbg(SDIO, "new state %s\n",
...@@ -1658,7 +1657,7 @@ static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, ...@@ -1658,7 +1657,7 @@ static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
bool *pending) bool *pending)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); int timeout = DCMD_RESP_TIMEOUT;
/* Wait until control frame is available */ /* Wait until control frame is available */
add_wait_queue(&bus->dcmd_resp_wait, &wait); add_wait_queue(&bus->dcmd_resp_wait, &wait);
...@@ -2843,7 +2842,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) ...@@ -2843,7 +2842,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
brcmf_sdio_trigger_dpc(bus); brcmf_sdio_trigger_dpc(bus);
wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
msecs_to_jiffies(CTL_DONE_TIMEOUT)); CTL_DONE_TIMEOUT);
ret = 0; ret = 0;
if (bus->ctrl_frame_stat) { if (bus->ctrl_frame_stat) {
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
...@@ -3553,7 +3552,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) ...@@ -3553,7 +3552,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
/* Poll for console output periodically */ /* Poll for console output periodically */
if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() && if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() &&
bus->console_interval != 0) { bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS; bus->console.count += jiffies_to_msecs(BRCMF_WD_POLL);
if (bus->console.count >= bus->console_interval) { if (bus->console.count >= bus->console_interval) {
bus->console.count -= bus->console_interval; bus->console.count -= bus->console_interval;
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
...@@ -3576,7 +3575,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) ...@@ -3576,7 +3575,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
if (bus->idlecount > bus->idletime) { if (bus->idlecount > bus->idletime) {
brcmf_dbg(SDIO, "idle\n"); brcmf_dbg(SDIO, "idle\n");
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdio_wd_timer(bus, 0); brcmf_sdio_wd_timer(bus, false);
bus->idlecount = 0; bus->idlecount = 0;
brcmf_sdio_bus_sleep(bus, true, false); brcmf_sdio_bus_sleep(bus, true, false);
sdio_release_host(bus->sdiodev->func[1]); sdio_release_host(bus->sdiodev->func[1]);
...@@ -3908,9 +3907,9 @@ brcmf_sdio_watchdog(unsigned long data) ...@@ -3908,9 +3907,9 @@ brcmf_sdio_watchdog(unsigned long data)
if (bus->watchdog_tsk) { if (bus->watchdog_tsk) {
complete(&bus->watchdog_wait); complete(&bus->watchdog_wait);
/* Reschedule the watchdog */ /* Reschedule the watchdog */
if (bus->wd_timer_valid) if (bus->wd_active)
mod_timer(&bus->timer, mod_timer(&bus->timer,
jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS)); jiffies + BRCMF_WD_POLL);
} }
} }
...@@ -3950,7 +3949,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, ...@@ -3950,7 +3949,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
/* Start the watchdog timer */ /* Start the watchdog timer */
bus->sdcnt.tickcnt = 0; bus->sdcnt.tickcnt = 0;
brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); brcmf_sdio_wd_timer(bus, true);
sdio_claim_host(sdiodev->func[1]); sdio_claim_host(sdiodev->func[1]);
...@@ -4195,7 +4194,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) ...@@ -4195,7 +4194,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
if (bus->ci) { if (bus->ci) {
if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) { if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) {
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdio_wd_timer(bus, 0); brcmf_sdio_wd_timer(bus, false);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false); brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Leave the device in state where it is /* Leave the device in state where it is
* 'passive'. This is done by resetting all * 'passive'. This is done by resetting all
...@@ -4217,13 +4216,12 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) ...@@ -4217,13 +4216,12 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Disconnected\n"); brcmf_dbg(TRACE, "Disconnected\n");
} }
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick) void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active)
{ {
/* Totally stop the timer */ /* Totally stop the timer */
if (!wdtick && bus->wd_timer_valid) { if (!active && bus->wd_active) {
del_timer_sync(&bus->timer); del_timer_sync(&bus->timer);
bus->wd_timer_valid = false; bus->wd_active = false;
bus->save_ms = wdtick;
return; return;
} }
...@@ -4231,27 +4229,18 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick) ...@@ -4231,27 +4229,18 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
if (bus->sdiodev->state != BRCMF_SDIOD_DATA) if (bus->sdiodev->state != BRCMF_SDIOD_DATA)
return; return;
if (wdtick) { if (active) {
if (bus->save_ms != BRCMF_WD_POLL_MS) { if (!bus->wd_active) {
if (bus->wd_timer_valid)
/* Stop timer and restart at new value */
del_timer_sync(&bus->timer);
/* Create timer again when watchdog period is /* Create timer again when watchdog period is
dynamically changed or in the first instance dynamically changed or in the first instance
*/ */
bus->timer.expires = bus->timer.expires = jiffies + BRCMF_WD_POLL;
jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS);
add_timer(&bus->timer); add_timer(&bus->timer);
bus->wd_active = true;
} else { } else {
/* Re arm the timer, at last watchdog period */ /* Re arm the timer, at last watchdog period */
mod_timer(&bus->timer, mod_timer(&bus->timer, jiffies + BRCMF_WD_POLL);
jiffies + msecs_to_jiffies(BRCMF_WD_POLL_MS));
} }
bus->wd_timer_valid = true;
bus->save_ms = wdtick;
} }
} }
......
...@@ -152,8 +152,8 @@ ...@@ -152,8 +152,8 @@
/* Packet alignment for most efficient SDIO (can change based on platform) */ /* Packet alignment for most efficient SDIO (can change based on platform) */
#define BRCMF_SDALIGN (1 << 6) #define BRCMF_SDALIGN (1 << 6)
/* watchdog polling interval in ms */ /* watchdog polling interval */
#define BRCMF_WD_POLL_MS 10 #define BRCMF_WD_POLL msecs_to_jiffies(10)
/** /**
* enum brcmf_sdiod_state - the state of the bus. * enum brcmf_sdiod_state - the state of the bus.
...@@ -369,7 +369,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); ...@@ -369,7 +369,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus); void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus); void brcmf_sdio_isr(struct brcmf_sdio *bus);
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick); void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
void brcmf_sdio_wowl_config(struct device *dev, bool enabled); void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep); int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus); void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "usb.h" #include "usb.h"
#define IOCTL_RESP_TIMEOUT 2000 #define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
#define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */ #define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */
#define BRCMF_USB_RESET_GETVER_LOOP_CNT 10 #define BRCMF_USB_RESET_GETVER_LOOP_CNT 10
...@@ -190,8 +190,7 @@ static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev) ...@@ -190,8 +190,7 @@ static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo) static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo)
{ {
return wait_event_timeout(devinfo->ioctl_resp_wait, return wait_event_timeout(devinfo->ioctl_resp_wait,
devinfo->ctl_completed, devinfo->ctl_completed, IOCTL_RESP_TIMEOUT);
msecs_to_jiffies(IOCTL_RESP_TIMEOUT));
} }
static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo) static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
......
...@@ -2311,8 +2311,10 @@ static int ipw2100_alloc_skb(struct ipw2100_priv *priv, ...@@ -2311,8 +2311,10 @@ static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
sizeof(struct ipw2100_rx), sizeof(struct ipw2100_rx),
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
/* NOTE: pci_map_single does not return an error code, and 0 is a valid if (pci_dma_mapping_error(priv->pci_dev, packet->dma_addr)) {
* dma_addr */ dev_kfree_skb(packet->skb);
return -ENOMEM;
}
return 0; return 0;
} }
...@@ -3183,6 +3185,11 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) ...@@ -3183,6 +3185,11 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
LIBIPW_3ADDR_LEN, LIBIPW_3ADDR_LEN,
tbd->buf_length, tbd->buf_length,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(priv->pci_dev,
tbd->host_addr)) {
IPW_DEBUG_TX("dma mapping error\n");
break;
}
IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n", IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
txq->next, tbd->host_addr, txq->next, tbd->host_addr,
......
...@@ -6416,7 +6416,7 @@ il4965_hw_detect(struct il_priv *il) ...@@ -6416,7 +6416,7 @@ il4965_hw_detect(struct il_priv *il)
D_INFO("HW Revision ID = 0x%X\n", il->rev_id); D_INFO("HW Revision ID = 0x%X\n", il->rev_id);
} }
static struct il_sensitivity_ranges il4965_sensitivity = { static const struct il_sensitivity_ranges il4965_sensitivity = {
.min_nrg_cck = 97, .min_nrg_cck = 97,
.max_nrg_cck = 0, /* not used, set to 0 */ .max_nrg_cck = 0, /* not used, set to 0 */
......
...@@ -1154,6 +1154,9 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) ...@@ -1154,6 +1154,9 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
priv->ucode_loaded = false; priv->ucode_loaded = false;
iwl_trans_stop_device(priv->trans); iwl_trans_stop_device(priv->trans);
ret = iwl_trans_start_hw(priv->trans);
if (ret)
goto out;
priv->wowlan = true; priv->wowlan = true;
......
...@@ -72,8 +72,8 @@ ...@@ -72,8 +72,8 @@
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 17 #define IWL7260_UCODE_API_MAX 17
#define IWL7265_UCODE_API_MAX 19 #define IWL7265_UCODE_API_MAX 17
#define IWL7265D_UCODE_API_MAX 19 #define IWL7265D_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13 #define IWL7260_UCODE_API_OK 13
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 19 #define IWL8000_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13 #define IWL8000_UCODE_API_OK 13
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 16 #define IWL9000_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL9000_UCODE_API_OK 13 #define IWL9000_UCODE_API_OK 13
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
* &struct iwl_fw_error_dump_rb * &struct iwl_fw_error_dump_rb
* @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were
* paged to the DRAM. * paged to the DRAM.
* @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers.
*/ */
enum iwl_fw_error_dump_type { enum iwl_fw_error_dump_type {
/* 0 is deprecated */ /* 0 is deprecated */
...@@ -103,6 +104,7 @@ enum iwl_fw_error_dump_type { ...@@ -103,6 +104,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_ERROR_INFO = 10, IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
IWL_FW_ERROR_DUMP_RB = 11, IWL_FW_ERROR_DUMP_RB = 11,
IWL_FW_ERROR_DUMP_PAGING = 12, IWL_FW_ERROR_DUMP_PAGING = 12,
IWL_FW_ERROR_DUMP_RADIO_REG = 13,
IWL_FW_ERROR_DUMP_MAX, IWL_FW_ERROR_DUMP_MAX,
}; };
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -309,6 +311,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; ...@@ -309,6 +311,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
* @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
* @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
* @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
* antenna the beacon should be transmitted
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
* *
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used * @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/ */
...@@ -336,6 +341,8 @@ enum iwl_ucode_tlv_capa { ...@@ -336,6 +341,8 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
NUM_IWL_UCODE_TLV_CAPA NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__ #ifdef __CHECKER__
...@@ -550,6 +557,8 @@ enum iwl_fw_dbg_trigger_vif_type { ...@@ -550,6 +557,8 @@ enum iwl_fw_dbg_trigger_vif_type {
* @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what
* configuration should be applied when the triggers kicks in. * configuration should be applied when the triggers kicks in.
* @occurrences: number of occurrences. 0 means the trigger will never fire. * @occurrences: number of occurrences. 0 means the trigger will never fire.
* @trig_dis_ms: the time, in milliseconds, after an occurrence of this
* trigger in which another occurrence should be ignored.
*/ */
struct iwl_fw_dbg_trigger_tlv { struct iwl_fw_dbg_trigger_tlv {
__le32 id; __le32 id;
...@@ -559,7 +568,8 @@ struct iwl_fw_dbg_trigger_tlv { ...@@ -559,7 +568,8 @@ struct iwl_fw_dbg_trigger_tlv {
u8 mode; u8 mode;
u8 start_conf_id; u8 start_conf_id;
__le16 occurrences; __le16 occurrences;
__le32 reserved[2]; __le16 trig_dis_ms;
__le16 reserved[3];
u8 data[0]; u8 data[0];
} __packed; } __packed;
......
...@@ -345,6 +345,12 @@ enum secure_load_status_reg { ...@@ -345,6 +345,12 @@ enum secure_load_status_reg {
#define TXF_READ_MODIFY_DATA (0xa00448) #define TXF_READ_MODIFY_DATA (0xa00448)
#define TXF_READ_MODIFY_ADDR (0xa0044c) #define TXF_READ_MODIFY_ADDR (0xa0044c)
/* Radio registers access */
#define RSP_RADIO_CMD (0xa02804)
#define RSP_RADIO_RDDAT (0xa02814)
#define RADIO_RSP_ADDR_POS (6)
#define RADIO_RSP_RD_CMD (3)
/* FW monitor */ /* FW monitor */
#define MON_BUFF_SAMPLE_CTL (0xa03c00) #define MON_BUFF_SAMPLE_CTL (0xa03c00)
#define MON_BUFF_BASE_ADDR (0xa03c3c) #define MON_BUFF_BASE_ADDR (0xa03c3c)
......
...@@ -663,7 +663,7 @@ struct iwl_trans_ops { ...@@ -663,7 +663,7 @@ struct iwl_trans_ops {
void (*resume)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans);
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv const struct iwl_fw_dbg_trigger_tlv
*trigger); *trigger);
}; };
...@@ -966,7 +966,7 @@ static inline void iwl_trans_resume(struct iwl_trans *trans) ...@@ -966,7 +966,7 @@ static inline void iwl_trans_resume(struct iwl_trans *trans)
static inline struct iwl_trans_dump_data * static inline struct iwl_trans_dump_data *
iwl_trans_dump_data(struct iwl_trans *trans, iwl_trans_dump_data(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
if (!trans->ops->dump_data) if (!trans->ops->dump_data)
return NULL; return NULL;
......
...@@ -137,6 +137,28 @@ static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out) ...@@ -137,6 +137,28 @@ static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)
out[i] = cpu_to_le16(p1k[i]); out[i] = cpu_to_le16(p1k[i]);
} }
static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key,
struct iwl_mvm_key_pn *ptk_pn,
struct ieee80211_key_seq *seq,
int tid, int queues)
{
const u8 *ret = seq->ccmp.pn;
int i;
/* get the PN from mac80211, used on the default queue */
ieee80211_get_key_rx_seq(key, tid, seq);
/* and use the internal data for the other queues */
for (i = 1; i < queues; i++) {
const u8 *tmp = ptk_pn->q[i].pn[tid];
if (memcmp(ret, tmp, IEEE80211_CCMP_PN_LEN) <= 0)
ret = tmp;
}
return ret;
}
struct wowlan_key_data { struct wowlan_key_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
struct iwl_wowlan_tkip_params_cmd *tkip; struct iwl_wowlan_tkip_params_cmd *tkip;
...@@ -294,18 +316,42 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ...@@ -294,18 +316,42 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
/* /*
* For non-QoS this relies on the fact that both the uCode and * For non-QoS this relies on the fact that both the uCode and
* mac80211 use TID 0 for checking the IV in the frames. * mac80211/our RX code use TID 0 for checking the PN.
*/ */
for (i = 0; i < IWL_NUM_RSC; i++) { if (sta && iwl_mvm_has_new_rx_api(mvm)) {
u8 *pn = seq.ccmp.pn; struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
const u8 *pn;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[key->keyidx],
lockdep_is_held(&mvm->mutex));
if (WARN_ON(!ptk_pn))
break;
ieee80211_get_key_rx_seq(key, i, &seq); for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
aes_sc[i].pn = cpu_to_le64((u64)pn[5] | pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i,
((u64)pn[4] << 8) | mvm->trans->num_rx_queues);
((u64)pn[3] << 16) | aes_sc[i].pn = cpu_to_le64((u64)pn[5] |
((u64)pn[2] << 24) | ((u64)pn[4] << 8) |
((u64)pn[1] << 32) | ((u64)pn[3] << 16) |
((u64)pn[0] << 40)); ((u64)pn[2] << 24) |
((u64)pn[1] << 32) |
((u64)pn[0] << 40));
}
} else {
for (i = 0; i < IWL_NUM_RSC; i++) {
u8 *pn = seq.ccmp.pn;
ieee80211_get_key_rx_seq(key, i, &seq);
aes_sc[i].pn = cpu_to_le64((u64)pn[5] |
((u64)pn[4] << 8) |
((u64)pn[3] << 16) |
((u64)pn[2] << 24) |
((u64)pn[1] << 32) |
((u64)pn[0] << 40));
}
} }
data->use_rsc_tsc = true; data->use_rsc_tsc = true;
break; break;
...@@ -1426,18 +1472,42 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc, ...@@ -1426,18 +1472,42 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
seq->tkip.iv16 = le16_to_cpu(sc->iv16); seq->tkip.iv16 = le16_to_cpu(sc->iv16);
} }
static void iwl_mvm_set_aes_rx_seq(struct aes_sc *scs, static void iwl_mvm_set_aes_rx_seq(struct iwl_mvm *mvm, struct aes_sc *scs,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
{ {
int tid; int tid;
BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS); BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
for (tid = 0; tid < IWL_NUM_RSC; tid++) { if (sta && iwl_mvm_has_new_rx_api(mvm)) {
struct ieee80211_key_seq seq = {}; struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq); mvmsta = iwl_mvm_sta_from_mac80211(sta);
ieee80211_set_key_rx_seq(key, tid, &seq);
ptk_pn = rcu_dereference_protected(mvmsta->ptk_pn[key->keyidx],
lockdep_is_held(&mvm->mutex));
if (WARN_ON(!ptk_pn))
return;
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
struct ieee80211_key_seq seq = {};
int i;
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
ieee80211_set_key_rx_seq(key, tid, &seq);
for (i = 1; i < mvm->trans->num_rx_queues; i++)
memcpy(ptk_pn->q[i].pn[tid],
seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
}
} else {
for (tid = 0; tid < IWL_NUM_RSC; tid++) {
struct ieee80211_key_seq seq = {};
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
ieee80211_set_key_rx_seq(key, tid, &seq);
}
} }
} }
...@@ -1456,14 +1526,15 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs, ...@@ -1456,14 +1526,15 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
} }
} }
static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct ieee80211_key_conf *key,
struct iwl_wowlan_status *status) struct iwl_wowlan_status *status)
{ {
union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc; union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
switch (key->cipher) { switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
iwl_mvm_set_aes_rx_seq(rsc->aes.multicast_rsc, key); iwl_mvm_set_aes_rx_seq(mvm, rsc->aes.multicast_rsc, NULL, key);
break; break;
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key); iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
...@@ -1474,6 +1545,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, ...@@ -1474,6 +1545,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
} }
struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm_d3_gtk_iter_data {
struct iwl_mvm *mvm;
struct iwl_wowlan_status *status; struct iwl_wowlan_status *status;
void *last_gtk; void *last_gtk;
u32 cipher; u32 cipher;
...@@ -1522,7 +1594,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, ...@@ -1522,7 +1594,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
switch (key->cipher) { switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
iwl_mvm_set_aes_rx_seq(sc->aes.unicast_rsc, key); iwl_mvm_set_aes_rx_seq(data->mvm, sc->aes.unicast_rsc,
sta, key);
atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn)); atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn));
break; break;
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
...@@ -1545,7 +1618,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, ...@@ -1545,7 +1618,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
if (data->status->num_of_gtk_rekeys) if (data->status->num_of_gtk_rekeys)
ieee80211_remove_key(key); ieee80211_remove_key(key);
else if (data->last_gtk == key) else if (data->last_gtk == key)
iwl_mvm_set_key_rx_seq(key, data->status); iwl_mvm_set_key_rx_seq(data->mvm, key, data->status);
} }
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
...@@ -1554,6 +1627,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ...@@ -1554,6 +1627,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_d3_gtk_iter_data gtkdata = { struct iwl_mvm_d3_gtk_iter_data gtkdata = {
.mvm = mvm,
.status = status, .status = status,
}; };
u32 disconnection_reasons = u32 disconnection_reasons =
...@@ -1615,7 +1689,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ...@@ -1615,7 +1689,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
key = ieee80211_gtk_rekey_add(vif, &conf.conf); key = ieee80211_gtk_rekey_add(vif, &conf.conf);
if (IS_ERR(key)) if (IS_ERR(key))
return false; return false;
iwl_mvm_set_key_rx_seq(key, status); iwl_mvm_set_key_rx_seq(mvm, key, status);
} }
if (status->num_of_gtk_rekeys) { if (status->num_of_gtk_rekeys) {
...@@ -1769,6 +1843,7 @@ void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, ...@@ -1769,6 +1843,7 @@ void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
struct iwl_wowlan_status *status) struct iwl_wowlan_status *status)
{ {
struct iwl_mvm_d3_gtk_iter_data gtkdata = { struct iwl_mvm_d3_gtk_iter_data gtkdata = {
.mvm = mvm,
.status = status, .status = status,
}; };
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -1451,6 +1453,22 @@ struct iwl_sf_cfg_cmd { ...@@ -1451,6 +1453,22 @@ struct iwl_sf_cfg_cmd {
* Location Aware Regulatory (LAR) API - MCC updates * Location Aware Regulatory (LAR) API - MCC updates
***********************************/ ***********************************/
/**
* struct iwl_mcc_update_cmd_v1 - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code).
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
* 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
* MCC in the cmd response will be the relevant MCC in the NVM.
* @mcc: given mobile country code
* @source_id: the source from where we got the MCC, see iwl_mcc_source
* @reserved: reserved for alignment
*/
struct iwl_mcc_update_cmd_v1 {
__le16 mcc;
u8 source_id;
u8 reserved;
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */
/** /**
* struct iwl_mcc_update_cmd - Request the device to update geographic * struct iwl_mcc_update_cmd - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code). * regulatory profile according to the given MCC (Mobile Country Code).
...@@ -1460,12 +1478,39 @@ struct iwl_sf_cfg_cmd { ...@@ -1460,12 +1478,39 @@ struct iwl_sf_cfg_cmd {
* @mcc: given mobile country code * @mcc: given mobile country code
* @source_id: the source from where we got the MCC, see iwl_mcc_source * @source_id: the source from where we got the MCC, see iwl_mcc_source
* @reserved: reserved for alignment * @reserved: reserved for alignment
* @key: integrity key for MCC API OEM testing
* @reserved2: reserved
*/ */
struct iwl_mcc_update_cmd { struct iwl_mcc_update_cmd {
__le16 mcc; __le16 mcc;
u8 source_id; u8 source_id;
u8 reserved; u8 reserved;
} __packed; /* LAR_UPDATE_MCC_CMD_API_S */ __le32 key;
__le32 reserved2[5];
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
/**
* iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD.
* Contains the new channel control profile map, if changed, and the new MCC
* (mobile country code).
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
* @status: see &enum iwl_mcc_update_status
* @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
* channels, depending on platform)
* @channels: channel control data map, DWORD for each channel. Only the first
* 16bits are used.
*/
struct iwl_mcc_update_resp_v1 {
__le32 status;
__le16 mcc;
u8 cap;
u8 source_id;
__le32 n_channels;
__le32 channels[0];
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
/** /**
* iwl_mcc_update_resp - response to MCC_UPDATE_CMD. * iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
...@@ -1476,6 +1521,8 @@ struct iwl_mcc_update_cmd { ...@@ -1476,6 +1521,8 @@ struct iwl_mcc_update_cmd {
* @mcc: the new applied MCC * @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC * @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source * @source_id: the MCC source, see iwl_mcc_source
* @time: time elapsed from the MCC test start (in 30 seconds TU)
* @reserved: reserved.
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
* channels, depending on platform) * channels, depending on platform)
* @channels: channel control data map, DWORD for each channel. Only the first * @channels: channel control data map, DWORD for each channel. Only the first
...@@ -1486,9 +1533,11 @@ struct iwl_mcc_update_resp { ...@@ -1486,9 +1533,11 @@ struct iwl_mcc_update_resp {
__le16 mcc; __le16 mcc;
u8 cap; u8 cap;
u8 source_id; u8 source_id;
__le16 time;
__le16 reserved;
__le32 n_channels; __le32 n_channels;
__le32 channels[0]; __le32 channels[0];
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */
/** /**
* struct iwl_mcc_chub_notif - chub notifies of mcc change * struct iwl_mcc_chub_notif - chub notifies of mcc change
...@@ -1518,6 +1567,9 @@ enum iwl_mcc_update_status { ...@@ -1518,6 +1567,9 @@ enum iwl_mcc_update_status {
MCC_RESP_NVM_DISABLED, MCC_RESP_NVM_DISABLED,
MCC_RESP_ILLEGAL, MCC_RESP_ILLEGAL,
MCC_RESP_LOW_PRIORITY, MCC_RESP_LOW_PRIORITY,
MCC_RESP_TEST_MODE_ACTIVE,
MCC_RESP_TEST_MODE_NOT_ACTIVE,
MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE,
}; };
enum iwl_mcc_source { enum iwl_mcc_source {
...@@ -1530,7 +1582,9 @@ enum iwl_mcc_source { ...@@ -1530,7 +1582,9 @@ enum iwl_mcc_source {
MCC_SOURCE_RESERVED = 6, MCC_SOURCE_RESERVED = 6,
MCC_SOURCE_DEFAULT = 7, MCC_SOURCE_DEFAULT = 7,
MCC_SOURCE_UNINITIALIZED = 8, MCC_SOURCE_UNINITIALIZED = 8,
MCC_SOURCE_GET_CURRENT = 0x10 MCC_SOURCE_MCC_API = 9,
MCC_SOURCE_GET_CURRENT = 0x10,
MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11,
}; };
/* DTS measurements */ /* DTS measurements */
......
...@@ -113,6 +113,35 @@ static void iwl_mvm_free_coredump(const void *data) ...@@ -113,6 +113,35 @@ static void iwl_mvm_free_coredump(const void *data)
kfree(fw_error_dump); kfree(fw_error_dump);
} }
#define RADIO_REG_MAX_READ 0x2ad
static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm,
struct iwl_fw_error_dump_data **dump_data)
{
u8 *pos = (void *)(*dump_data)->data;
unsigned long flags;
int i;
if (!iwl_trans_grab_nic_access(mvm->trans, &flags))
return;
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG);
(*dump_data)->len = cpu_to_le32(RADIO_REG_MAX_READ);
for (i = 0; i < RADIO_REG_MAX_READ; i++) {
u32 rd_cmd = RADIO_RSP_RD_CMD;
rd_cmd |= i << RADIO_RSP_ADDR_POS;
iwl_write_prph_no_grab(mvm->trans, RSP_RADIO_CMD, rd_cmd);
*pos = (u8)iwl_read_prph_no_grab(mvm->trans, RSP_RADIO_RDDAT);
pos++;
}
*dump_data = iwl_fw_error_next_data(*dump_data);
iwl_trans_release_nic_access(mvm->trans, &flags);
}
static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
struct iwl_fw_error_dump_data **dump_data) struct iwl_fw_error_dump_data **dump_data)
{ {
...@@ -241,8 +270,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, ...@@ -241,8 +270,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
{ {
if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert || if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert)
!mvm->fw_dump_desc)
return; return;
kfree(mvm->fw_dump_desc); kfree(mvm->fw_dump_desc);
...@@ -401,7 +429,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -401,7 +429,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct iwl_fw_error_dump_trigger_desc *dump_trig; struct iwl_fw_error_dump_trigger_desc *dump_trig;
struct iwl_mvm_dump_ptrs *fw_error_dump; struct iwl_mvm_dump_ptrs *fw_error_dump;
u32 sram_len, sram_ofs; u32 sram_len, sram_ofs;
u32 file_len, fifo_data_len = 0, prph_len = 0; u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
u32 smem_len = mvm->cfg->smem_len; u32 smem_len = mvm->cfg->smem_len;
u32 sram2_len = mvm->cfg->dccm2_len; u32 sram2_len = mvm->cfg->dccm2_len;
bool monitor_dump_only = false; bool monitor_dump_only = false;
...@@ -412,7 +440,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -412,7 +440,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
/* there's no point in fw dump if the bus is dead */ /* there's no point in fw dump if the bus is dead */
if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) {
IWL_ERR(mvm, "Skip fw error dump since bus is dead\n"); IWL_ERR(mvm, "Skip fw error dump since bus is dead\n");
return; goto out;
} }
if (mvm->fw_dump_trig && if (mvm->fw_dump_trig &&
...@@ -421,7 +449,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -421,7 +449,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
if (!fw_error_dump) if (!fw_error_dump)
return; goto out;
/* SRAM - include stack CCM if driver knows the values for it */ /* SRAM - include stack CCM if driver knows the values for it */
if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) {
...@@ -472,6 +500,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -472,6 +500,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof(struct iwl_fw_error_dump_prph) + sizeof(struct iwl_fw_error_dump_prph) +
num_bytes_in_chunk; num_bytes_in_chunk;
} }
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
} }
file_len = sizeof(*dump_file) + file_len = sizeof(*dump_file) +
...@@ -479,6 +510,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -479,6 +510,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sram_len + sizeof(*dump_mem) + sram_len + sizeof(*dump_mem) +
fifo_data_len + fifo_data_len +
prph_len + prph_len +
radio_len +
sizeof(*dump_info); sizeof(*dump_info);
/* Make room for the SMEM, if it exists */ /* Make room for the SMEM, if it exists */
...@@ -517,8 +549,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -517,8 +549,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_file = vzalloc(file_len); dump_file = vzalloc(file_len);
if (!dump_file) { if (!dump_file) {
kfree(fw_error_dump); kfree(fw_error_dump);
iwl_mvm_free_fw_dump_desc(mvm); goto out;
return;
} }
fw_error_dump->op_mode_ptr = dump_file; fw_error_dump->op_mode_ptr = dump_file;
...@@ -543,8 +574,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -543,8 +574,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_data = iwl_fw_error_next_data(dump_data); dump_data = iwl_fw_error_next_data(dump_data);
/* We only dump the FIFOs if the FW is in error state */ /* We only dump the FIFOs if the FW is in error state */
if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) {
iwl_mvm_dump_fifos(mvm, &dump_data); iwl_mvm_dump_fifos(mvm, &dump_data);
if (radio_len)
iwl_mvm_read_radio_reg(mvm, &dump_data);
}
if (mvm->fw_dump_desc) { if (mvm->fw_dump_desc) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
...@@ -554,8 +588,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -554,8 +588,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc, memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc,
sizeof(*dump_trig) + mvm->fw_dump_desc->len); sizeof(*dump_trig) + mvm->fw_dump_desc->len);
/* now we can free this copy */
iwl_mvm_free_fw_dump_desc(mvm);
dump_data = iwl_fw_error_next_data(dump_data); dump_data = iwl_fw_error_next_data(dump_data);
} }
...@@ -641,19 +673,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -641,19 +673,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
out:
iwl_mvm_free_fw_dump_desc(mvm);
mvm->fw_dump_trig = NULL; mvm->fw_dump_trig = NULL;
clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
} }
struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = { const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = {
.trig_desc = { .trig_desc = {
.type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT), .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
}, },
}; };
int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
struct iwl_mvm_dump_desc *desc, const struct iwl_mvm_dump_desc *desc,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
unsigned int delay = 0; unsigned int delay = 0;
...@@ -679,7 +713,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, ...@@ -679,7 +713,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
const char *str, size_t len, const char *str, size_t len,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
struct iwl_mvm_dump_desc *desc; struct iwl_mvm_dump_desc *desc;
......
...@@ -72,11 +72,11 @@ ...@@ -72,11 +72,11 @@
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
struct iwl_mvm_dump_desc *desc, const struct iwl_mvm_dump_desc *desc,
struct iwl_fw_dbg_trigger_tlv *trigger); const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
const char *str, size_t len, const char *str, size_t len,
struct iwl_fw_dbg_trigger_tlv *trigger); const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trigger, struct iwl_fw_dbg_trigger_tlv *trigger,
const char *fmt, ...) __printf(3, 4); const char *fmt, ...) __printf(3, 4);
...@@ -117,6 +117,24 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm, ...@@ -117,6 +117,24 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm,
(BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids)))); (BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids))));
} }
static inline bool
iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig)
{
unsigned long wind_jiff =
msecs_to_jiffies(le16_to_cpu(trig->trig_dis_ms));
u32 id = le32_to_cpu(trig->id);
/* If this is the first event checked, jump to update start ts */
if (mvm->fw_dbg_non_collect_ts_start[id] &&
(time_after(mvm->fw_dbg_non_collect_ts_start[id] + wind_jiff,
jiffies)))
return true;
mvm->fw_dbg_non_collect_ts_start[id] = jiffies;
return false;
}
static inline bool static inline bool
iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -125,6 +143,12 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, ...@@ -125,6 +143,12 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif)) if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif))
return false; return false;
if (iwl_fw_dbg_no_trig_window(mvm, trig)) {
IWL_WARN(mvm, "Trigger %d occurred while no-collect window.\n",
trig->id);
return false;
}
return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig); return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig);
} }
......
...@@ -943,6 +943,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -943,6 +943,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
} }
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
mvm->scan_type = IWL_SCAN_TYPE_NOT_SET;
ret = iwl_mvm_config_scan(mvm); ret = iwl_mvm_config_scan(mvm);
if (ret) if (ret)
goto error; goto error;
......
...@@ -717,6 +717,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -717,6 +717,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cpu_to_le32(vif->bss_conf.use_short_slot ? cpu_to_le32(vif->bss_conf.use_short_slot ?
MAC_FLG_SHORT_SLOT : 0); MAC_FLG_SHORT_SLOT : 0);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_ac_to_tx_fifo[i]; u8 txf = iwl_mvm_ac_to_tx_fifo[i];
...@@ -730,11 +732,26 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -730,11 +732,26 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->ac[txf].fifos_mask = BIT(txf); cmd->ac[txf].fifos_mask = BIT(txf);
} }
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */ if (vif->type == NL80211_IFTYPE_AP) {
if (vif->type == NL80211_IFTYPE_AP) /* in AP mode, the MCAST FIFO takes the EDCA params from VO */
cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |=
BIT(IWL_MVM_TX_FIFO_MCAST); BIT(IWL_MVM_TX_FIFO_MCAST);
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count) {
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
}
if (vif->bss_conf.qos) if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
...@@ -748,8 +765,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -748,8 +765,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
if (ht_enabled) if (ht_enabled)
iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd); iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
} }
static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
...@@ -1012,9 +1027,12 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, ...@@ -1012,9 +1027,12 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
TX_CMD_FLG_BT_PRIO_POS; TX_CMD_FLG_BT_PRIO_POS;
beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
mvm->mgmt_last_antenna_idx = if (!fw_has_capa(&mvm->fw->ucode_capa,
iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
mvm->mgmt_last_antenna_idx); mvm->mgmt_last_antenna_idx =
iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
mvm->mgmt_last_antenna_idx);
}
beacon_cmd.tx.rate_n_flags = beacon_cmd.tx.rate_n_flags =
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
...@@ -1153,7 +1171,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, ...@@ -1153,7 +1171,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u32 action) u32 action)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_ctx_cmd cmd = {}; struct iwl_mac_ctx_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
...@@ -1161,19 +1178,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, ...@@ -1161,19 +1178,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
* for ht protection); when there're no any associated station
* don't ask FW to pass beacons to prevent unnecessary wake-ups.
*/
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
/* Fill the data specific for ap mode */ /* Fill the data specific for ap mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
action == FW_CTXT_ACTION_ADD); action == FW_CTXT_ACTION_ADD);
...@@ -1193,13 +1197,6 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, ...@@ -1193,13 +1197,6 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
* for ht protection)
*/
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
MAC_FILTER_IN_BEACON);
/* Fill the data specific for GO mode */ /* Fill the data specific for GO mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
action == FW_CTXT_ACTION_ADD); action == FW_CTXT_ACTION_ADD);
......
...@@ -438,6 +438,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -438,6 +438,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, CHANCTX_STA_CSA); ieee80211_hw_set(hw, CHANCTX_STA_CSA);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
if (mvm->trans->max_skb_frags) if (mvm->trans->max_skb_frags)
hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
...@@ -1002,7 +1004,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ...@@ -1002,7 +1004,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->vif_count = 0; mvm->vif_count = 0;
mvm->rx_ba_sessions = 0; mvm->rx_ba_sessions = 0;
mvm->fw_dbg_conf = FW_DBG_INVALID; mvm->fw_dbg_conf = FW_DBG_INVALID;
mvm->scan_type = IWL_SCAN_TYPE_NOT_SET;
/* keep statistics ticking */ /* keep statistics ticking */
iwl_mvm_accu_radio_stats(mvm); iwl_mvm_accu_radio_stats(mvm);
...@@ -2567,6 +2568,9 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2567,6 +2568,9 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
int keyidx = key->keyidx;
int ret; int ret;
u8 key_offset; u8 key_offset;
...@@ -2634,6 +2638,36 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2634,6 +2638,36 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
} }
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
struct ieee80211_key_seq seq;
int tid, q;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));
ptk_pn = kzalloc(sizeof(*ptk_pn) +
mvm->trans->num_rx_queues *
sizeof(ptk_pn->q[0]),
GFP_KERNEL);
if (!ptk_pn) {
ret = -ENOMEM;
break;
}
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
ieee80211_get_key_rx_seq(key, tid, &seq);
for (q = 0; q < mvm->trans->num_rx_queues; q++)
memcpy(ptk_pn->q[q].pn[tid],
seq.ccmp.pn,
IEEE80211_CCMP_PN_LEN);
}
rcu_assign_pointer(mvmsta->ptk_pn[keyidx], ptk_pn);
}
/* in HW restart reuse the index, otherwise request a new one */ /* in HW restart reuse the index, otherwise request a new one */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
key_offset = key->hw_key_idx; key_offset = key->hw_key_idx;
...@@ -2659,6 +2693,19 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2659,6 +2693,19 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
} }
if (sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[keyidx],
lockdep_is_held(&mvm->mutex));
RCU_INIT_POINTER(mvmsta->ptk_pn[keyidx], NULL);
if (ptk_pn)
kfree_rcu(ptk_pn, rcu_head);
}
IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
break; break;
......
...@@ -157,7 +157,7 @@ struct iwl_mvm_dump_desc { ...@@ -157,7 +157,7 @@ struct iwl_mvm_dump_desc {
struct iwl_fw_error_dump_trigger_desc trig_desc; struct iwl_fw_error_dump_trigger_desc trig_desc;
}; };
extern struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert; extern const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert;
struct iwl_mvm_phy_ctxt { struct iwl_mvm_phy_ctxt {
u16 id; u16 id;
...@@ -658,6 +658,9 @@ struct iwl_mvm { ...@@ -658,6 +658,9 @@ struct iwl_mvm {
/* max number of simultaneous scans the FW supports */ /* max number of simultaneous scans the FW supports */
unsigned int max_scans; unsigned int max_scans;
/* ts of the beginning of a non-collect fw dbg data period */
unsigned long fw_dbg_non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
/* UMAC scan tracking */ /* UMAC scan tracking */
u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS]; u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS];
...@@ -729,8 +732,8 @@ struct iwl_mvm { ...@@ -729,8 +732,8 @@ struct iwl_mvm {
s8 restart_fw; s8 restart_fw;
u8 fw_dbg_conf; u8 fw_dbg_conf;
struct delayed_work fw_dump_wk; struct delayed_work fw_dump_wk;
struct iwl_mvm_dump_desc *fw_dump_desc; const struct iwl_mvm_dump_desc *fw_dump_desc;
struct iwl_fw_dbg_trigger_tlv *fw_dump_trig; const struct iwl_fw_dbg_trigger_tlv *fw_dump_trig;
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led; struct led_classdev led;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -640,7 +642,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) ...@@ -640,7 +642,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
else else
mvm->nvm_file_name = nvm_file_C; mvm->nvm_file_name = nvm_file_C;
if (ret == -EFAULT && mvm->nvm_file_name) { if ((ret == -EFAULT || ret == -ENOENT) &&
mvm->nvm_file_name) {
/* in case nvm file was failed try again */ /* in case nvm file was failed try again */
ret = iwl_mvm_read_external_nvm(mvm); ret = iwl_mvm_read_external_nvm(mvm);
if (ret) if (ret)
...@@ -670,6 +673,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -670,6 +673,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
.source_id = (u8)src_id, .source_id = (u8)src_id,
}; };
struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = NULL;
struct iwl_rx_packet *pkt; struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = MCC_UPDATE_CMD, .id = MCC_UPDATE_CMD,
...@@ -681,11 +685,15 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -681,11 +685,15 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
u32 status; u32 status;
int resp_len, n_channels; int resp_len, n_channels;
u16 mcc; u16 mcc;
bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
if (!resp_v2)
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1);
IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
alpha2[0], alpha2[1], src_id); alpha2[0], alpha2[1], src_id);
...@@ -697,31 +705,50 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -697,31 +705,50 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
pkt = cmd.resp_pkt; pkt = cmd.resp_pkt;
/* Extract MCC response */ /* Extract MCC response */
mcc_resp = (void *)pkt->data; if (resp_v2) {
status = le32_to_cpu(mcc_resp->status); mcc_resp = (void *)pkt->data;
n_channels = __le32_to_cpu(mcc_resp->n_channels);
} else {
mcc_resp_v1 = (void *)pkt->data;
n_channels = __le32_to_cpu(mcc_resp_v1->n_channels);
}
mcc = le16_to_cpu(mcc_resp->mcc); resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels *
sizeof(__le32);
resp_cp = kzalloc(resp_len, GFP_KERNEL);
if (!resp_cp) {
ret = -ENOMEM;
goto exit;
}
if (resp_v2) {
memcpy(resp_cp, mcc_resp, resp_len);
} else {
resp_cp->status = mcc_resp_v1->status;
resp_cp->mcc = mcc_resp_v1->mcc;
resp_cp->cap = mcc_resp_v1->cap;
resp_cp->source_id = mcc_resp_v1->source_id;
resp_cp->n_channels = mcc_resp_v1->n_channels;
memcpy(resp_cp->channels, mcc_resp_v1->channels,
n_channels * sizeof(__le32));
}
status = le32_to_cpu(resp_cp->status);
mcc = le16_to_cpu(resp_cp->mcc);
/* W/A for a FW/NVM issue - returns 0x00 for the world domain */ /* W/A for a FW/NVM issue - returns 0x00 for the world domain */
if (mcc == 0) { if (mcc == 0) {
mcc = 0x3030; /* "00" - world */ mcc = 0x3030; /* "00" - world */
mcc_resp->mcc = cpu_to_le16(mcc); resp_cp->mcc = cpu_to_le16(mcc);
} }
n_channels = __le32_to_cpu(mcc_resp->n_channels);
IWL_DEBUG_LAR(mvm, IWL_DEBUG_LAR(mvm,
"MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
status, mcc, mcc >> 8, mcc & 0xff, status, mcc, mcc >> 8, mcc & 0xff,
!!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels); !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
if (!resp_cp) {
ret = -ENOMEM;
goto exit;
}
ret = 0;
exit: exit:
iwl_free_resp(&cmd); iwl_free_resp(&cmd);
if (ret) if (ret)
......
...@@ -613,8 +613,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, ...@@ -613,8 +613,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
break; break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
/* only a single MAC of the same type */
WARN_ON(power_iterator->bss_vif);
power_iterator->bss_vif = vif; power_iterator->bss_vif = vif;
if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS) if (mvmvif->phy_ctxt->id < MAX_PHYS)
......
...@@ -78,12 +78,83 @@ void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ...@@ -78,12 +78,83 @@ void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
#endif #endif
} }
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
struct napi_struct *napi, int queue, struct ieee80211_sta *sta)
struct sk_buff *skb, {
struct ieee80211_hdr *hdr, u16 len, struct iwl_mvm_sta *mvmsta;
u32 ampdu_status, u8 crypt_len, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_rx_cmd_buffer *rxb) struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
struct iwl_mvm_key_pn *ptk_pn;
u8 tid, keyidx;
u8 pn[IEEE80211_CCMP_PN_LEN];
u8 *extiv;
/* do PN checking */
/* multicast and non-data only arrives on default queue */
if (!ieee80211_is_data(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
return 0;
/* do not check PN for open AP */
if (!(stats->flag & RX_FLAG_DECRYPTED))
return 0;
/*
* avoid checking for default queue - we don't want to replicate
* all the logic that's necessary for checking the PN on fragmented
* frames, leave that to mac80211
*/
if (queue == 0)
return 0;
/* if we are here - this for sure is either CCMP or GCMP */
if (IS_ERR_OR_NULL(sta)) {
IWL_ERR(mvm,
"expected hw-decrypted unicast frame for station\n");
return -1;
}
mvmsta = iwl_mvm_sta_from_mac80211(sta);
extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
keyidx = extiv[3] >> 6;
ptk_pn = rcu_dereference(mvmsta->ptk_pn[keyidx]);
if (!ptk_pn)
return -1;
if (ieee80211_is_data_qos(hdr->frame_control))
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
else
tid = 0;
/* we don't use HCCA/802.11 QoS TSPECs, so drop such frames */
if (tid >= IWL_MAX_TID_COUNT)
return -1;
/* load pn */
pn[0] = extiv[7];
pn[1] = extiv[6];
pn[2] = extiv[5];
pn[3] = extiv[4];
pn[4] = extiv[1];
pn[5] = extiv[0];
if (memcmp(pn, ptk_pn->q[queue].pn[tid],
IEEE80211_CCMP_PN_LEN) <= 0)
return -1;
memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
stats->flag |= RX_FLAG_PN_VALIDATED;
return 0;
}
/* iwl_mvm_create_skb Adds the rxb to a new skb */
static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr,
u16 len, u8 crypt_len,
struct iwl_rx_cmd_buffer *rxb)
{ {
unsigned int hdrlen, fraglen; unsigned int hdrlen, fraglen;
...@@ -112,8 +183,18 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, ...@@ -112,8 +183,18 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
fraglen, rxb->truesize); fraglen, rxb->truesize);
} }
}
ieee80211_rx_napi(mvm->hw, skb, napi); /* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct napi_struct *napi,
struct sk_buff *skb, int queue,
struct ieee80211_sta *sta)
{
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
kfree_skb(skb);
else
ieee80211_rx_napi(mvm->hw, skb, napi);
} }
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
...@@ -141,7 +222,7 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, ...@@ -141,7 +222,7 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
rx_status->chain_signal[2] = energy_c; rx_status->chain_signal[2] = energy_c;
} }
static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_rx_status *stats, struct ieee80211_rx_status *stats,
struct iwl_rx_mpdu_desc *desc, int queue, struct iwl_rx_mpdu_desc *desc, int queue,
u8 *crypt_len) u8 *crypt_len)
...@@ -158,6 +239,7 @@ static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, ...@@ -158,6 +239,7 @@ static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) {
case IWL_RX_MPDU_STATUS_SEC_CCM: case IWL_RX_MPDU_STATUS_SEC_CCM:
case IWL_RX_MPDU_STATUS_SEC_GCM: case IWL_RX_MPDU_STATUS_SEC_GCM:
BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN);
/* alg is CCM: check MIC only */ /* alg is CCM: check MIC only */
if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
return -1; return -1;
...@@ -217,7 +299,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -217,7 +299,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
struct ieee80211_sta *sta = NULL; struct ieee80211_sta *sta = NULL;
struct sk_buff *skb; struct sk_buff *skb;
u32 ampdu_status;
u8 crypt_len = 0; u8 crypt_len = 0;
/* Dont use dev_alloc_skb(), we'll have enough headroom once /* Dont use dev_alloc_skb(), we'll have enough headroom once
...@@ -311,8 +392,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -311,8 +392,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
iwl_mvm_rx_csum(sta, skb, desc); iwl_mvm_rx_csum(sta, skb, desc);
} }
rcu_read_unlock();
/* /*
* TODO: PHY info. * TODO: PHY info.
* Verify we don't have the information in the MPDU descriptor and * Verify we don't have the information in the MPDU descriptor and
...@@ -367,8 +446,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -367,8 +446,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
/* TODO: PHY info - update ampdu queue statistics (for debugfs) */ /* TODO: PHY info - update ampdu queue statistics (for debugfs) */
/* TODO: PHY info - gscan */ /* TODO: PHY info - gscan */
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status, iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
crypt_len, rxb); iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
rcu_read_unlock();
} }
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
......
...@@ -92,7 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -92,7 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 0, .suspend_time = 0,
.max_out_time = 0, .max_out_time = 0,
}, },
...@@ -100,7 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -100,7 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 30, .suspend_time = 30,
.max_out_time = 120, .max_out_time = 120,
}, },
...@@ -108,7 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -108,7 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 120, .suspend_time = 120,
.max_out_time = 120, .max_out_time = 120,
}, },
...@@ -116,7 +116,6 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -116,7 +116,6 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 44,
.suspend_time = 95, .suspend_time = 95,
.max_out_time = 44, .max_out_time = 44,
}, },
...@@ -790,7 +789,8 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, ...@@ -790,7 +789,8 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
#endif #endif
if (iwl_mvm_is_regular_scan(params) && if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE) vif->type != NL80211_IFTYPE_P2P_DEVICE &&
params->type != IWL_SCAN_TYPE_FRAGMENTED)
flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL; flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL;
return flags; return flags;
...@@ -1072,7 +1072,8 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, ...@@ -1072,7 +1072,8 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
#endif #endif
if (iwl_mvm_is_regular_scan(params) && if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE) vif->type != NL80211_IFTYPE_P2P_DEVICE &&
params->type != IWL_SCAN_TYPE_FRAGMENTED)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
return flags; return flags;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -284,6 +286,13 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -284,6 +286,13 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
tid_data->next_reclaimed); tid_data->next_reclaimed);
} }
struct iwl_mvm_key_pn {
struct rcu_head rcu_head;
struct {
u8 pn[IWL_MAX_TID_COUNT][IEEE80211_CCMP_PN_LEN];
} ____cacheline_aligned_in_smp q[];
};
/** /**
* struct iwl_mvm_sta - representation of a station in the driver * struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color) * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
...@@ -308,6 +317,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -308,6 +317,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
* gets empty before all the frames were sent, which can happen when * gets empty before all the frames were sent, which can happen when
* we are sending frames from an AMPDU queue and there was a hole in * we are sending frames from an AMPDU queue and there was a hole in
* the BA window. To be used for UAPSD only. * the BA window. To be used for UAPSD only.
* @ptk_pn: per-queue PTK PN data structures
* *
* When mac80211 creates a station it reserves some space (hw->sta_data_size) * 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 * in the structure for use by driver. This structure is placed in that
...@@ -328,6 +338,8 @@ struct iwl_mvm_sta { ...@@ -328,6 +338,8 @@ struct iwl_mvm_sta {
struct iwl_lq_sta lq_sta; struct iwl_lq_sta lq_sta;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
/* Temporary, until the new TLC will control the Tx protection */ /* Temporary, until the new TLC will control the Tx protection */
s8 tx_protection; s8 tx_protection;
bool tt_tx_protection; bool tt_tx_protection;
......
...@@ -120,7 +120,7 @@ static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, ...@@ -120,7 +120,7 @@ static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
int len = iwl_rx_packet_payload_len(pkt); int len = iwl_rx_packet_payload_len(pkt);
int temp; int temp;
if (WARN_ON_ONCE(len != sizeof(*notif))) { if (WARN_ON_ONCE(len < sizeof(*notif))) {
IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -388,6 +388,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -388,6 +388,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5C10, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
...@@ -405,10 +406,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -405,10 +406,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9310, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)},
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -924,9 +926,16 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) ...@@ -924,9 +926,16 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)
if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
iwl_write_prph(trans, le32_to_cpu(dest->base_reg), iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
trans_pcie->fw_mon_phys >> dest->base_shift); trans_pcie->fw_mon_phys >> dest->base_shift);
iwl_write_prph(trans, le32_to_cpu(dest->end_reg), if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
(trans_pcie->fw_mon_phys + iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
trans_pcie->fw_mon_size) >> dest->end_shift); (trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size - 256) >>
dest->end_shift);
else
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
(trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size) >>
dest->end_shift);
} }
} }
...@@ -2364,7 +2373,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, ...@@ -2364,7 +2373,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
static struct iwl_trans_dump_data static struct iwl_trans_dump_data
*iwl_trans_pcie_dump_data(struct iwl_trans *trans, *iwl_trans_pcie_dump_data(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_fw_error_dump_data *data; struct iwl_fw_error_dump_data *data;
......
...@@ -763,7 +763,7 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, ...@@ -763,7 +763,7 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
spin_lock_irqsave(&priv->ack_status_lock, flags); spin_lock_irqsave(&priv->ack_status_lock, flags);
id = idr_alloc(&priv->ack_status_frames, orig_skb, id = idr_alloc(&priv->ack_status_frames, orig_skb,
1, 0xff, GFP_ATOMIC); 1, 0x10, GFP_ATOMIC);
spin_unlock_irqrestore(&priv->ack_status_lock, flags); spin_unlock_irqrestore(&priv->ack_status_lock, flags);
if (id >= 0) { if (id >= 0) {
......
...@@ -2129,14 +2129,14 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) ...@@ -2129,14 +2129,14 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
struct mwifiex_adapter *adapter; struct mwifiex_adapter *adapter;
if (!pdev) { if (!pdev) {
pr_debug("info: %s: pdev is NULL\n", (u8 *)pdev); pr_err("info: %s: pdev is NULL\n", __func__);
goto exit; goto exit;
} }
card = pci_get_drvdata(pdev); card = pci_get_drvdata(pdev);
if (!card || !card->adapter) { if (!card || !card->adapter) {
pr_debug("info: %s: card=%p adapter=%p\n", __func__, card, pr_err("info: %s: card=%p adapter=%p\n", __func__, card,
card ? card->adapter : NULL); card ? card->adapter : NULL);
goto exit; goto exit;
} }
adapter = card->adapter; adapter = card->adapter;
...@@ -2473,50 +2473,44 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) ...@@ -2473,50 +2473,44 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
pci_set_master(pdev); pci_set_master(pdev);
mwifiex_dbg(adapter, INFO, pr_notice("try set_consistent_dma_mask(32)\n");
"try set_consistent_dma_mask(32)\n");
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, pr_err("set_dma_mask(32) failed\n");
"set_dma_mask(32) failed\n");
goto err_set_dma_mask; goto err_set_dma_mask;
} }
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, pr_err("set_consistent_dma_mask(64) failed\n");
"set_consistent_dma_mask(64) failed\n");
goto err_set_dma_mask; goto err_set_dma_mask;
} }
ret = pci_request_region(pdev, 0, DRV_NAME); ret = pci_request_region(pdev, 0, DRV_NAME);
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, pr_err("req_reg(0) error\n");
"req_reg(0) error\n");
goto err_req_region0; goto err_req_region0;
} }
card->pci_mmap = pci_iomap(pdev, 0, 0); card->pci_mmap = pci_iomap(pdev, 0, 0);
if (!card->pci_mmap) { if (!card->pci_mmap) {
mwifiex_dbg(adapter, ERROR, "iomap(0) error\n"); pr_err("iomap(0) error\n");
ret = -EIO; ret = -EIO;
goto err_iomap0; goto err_iomap0;
} }
ret = pci_request_region(pdev, 2, DRV_NAME); ret = pci_request_region(pdev, 2, DRV_NAME);
if (ret) { if (ret) {
mwifiex_dbg(adapter, ERROR, "req_reg(2) error\n"); pr_err("req_reg(2) error\n");
goto err_req_region2; goto err_req_region2;
} }
card->pci_mmap1 = pci_iomap(pdev, 2, 0); card->pci_mmap1 = pci_iomap(pdev, 2, 0);
if (!card->pci_mmap1) { if (!card->pci_mmap1) {
mwifiex_dbg(adapter, ERROR, pr_err("iomap(2) error\n");
"iomap(2) error\n");
ret = -EIO; ret = -EIO;
goto err_iomap2; goto err_iomap2;
} }
mwifiex_dbg(adapter, INFO, pr_notice("PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
"PCI memory map Virt0: %p PCI memory map Virt2: %p\n", card->pci_mmap, card->pci_mmap1);
card->pci_mmap, card->pci_mmap1);
card->cmdrsp_buf = NULL; card->cmdrsp_buf = NULL;
ret = mwifiex_pcie_create_txbd_ring(adapter); ret = mwifiex_pcie_create_txbd_ring(adapter);
...@@ -2635,11 +2629,11 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) ...@@ -2635,11 +2629,11 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
/* save adapter pointer in card */ /* save adapter pointer in card */
card->adapter = adapter; card->adapter = adapter;
adapter->dev = &pdev->dev;
if (mwifiex_pcie_request_irq(adapter)) if (mwifiex_pcie_request_irq(adapter))
return -1; return -1;
adapter->dev = &pdev->dev;
adapter->tx_buf_size = card->pcie.tx_buf_size; adapter->tx_buf_size = card->pcie.tx_buf_size;
adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
......
...@@ -796,8 +796,8 @@ mwifiex_sdio_interrupt(struct sdio_func *func) ...@@ -796,8 +796,8 @@ mwifiex_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func); card = sdio_get_drvdata(func);
if (!card || !card->adapter) { if (!card || !card->adapter) {
pr_debug("int: func=%p card=%p adapter=%p\n", pr_err("int: func=%p card=%p adapter=%p\n",
func, card, card ? card->adapter : NULL); func, card, card ? card->adapter : NULL);
return; return;
} }
adapter = card->adapter; adapter = card->adapter;
...@@ -2053,8 +2053,19 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) ...@@ -2053,8 +2053,19 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
/* Allocate skb pointer buffers */ /* Allocate skb pointer buffers */
card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) * card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) *
card->mp_agg_pkt_limit, GFP_KERNEL); card->mp_agg_pkt_limit, GFP_KERNEL);
if (!card->mpa_rx.skb_arr) {
kfree(card->mp_regs);
return -ENOMEM;
}
card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) * card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) *
card->mp_agg_pkt_limit, GFP_KERNEL); card->mp_agg_pkt_limit, GFP_KERNEL);
if (!card->mpa_rx.len_arr) {
kfree(card->mp_regs);
kfree(card->mpa_rx.skb_arr);
return -ENOMEM;
}
ret = mwifiex_alloc_sdio_mpa_buffers(adapter, ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
card->mp_tx_agg_buf_size, card->mp_tx_agg_buf_size,
card->mp_rx_agg_buf_size); card->mp_rx_agg_buf_size);
......
...@@ -149,6 +149,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) ...@@ -149,6 +149,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
ieee80211_free_hw(hw); ieee80211_free_hw(hw);
exit_release_regions: exit_release_regions:
pci_clear_mwi(pci_dev);
pci_release_regions(pci_dev); pci_release_regions(pci_dev);
exit_disable_device: exit_disable_device:
...@@ -173,6 +174,7 @@ void rt2x00pci_remove(struct pci_dev *pci_dev) ...@@ -173,6 +174,7 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
/* /*
* Free the PCI device data. * Free the PCI device data.
*/ */
pci_clear_mwi(pci_dev);
pci_disable_device(pci_dev); pci_disable_device(pci_dev);
pci_release_regions(pci_dev); pci_release_regions(pci_dev);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册