mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 05:11:48 +00:00
Merge ath-next from ath.git
Major changes: ath10k: * qca6174 power consumption improvements, enable ASPM etc (Michal) wil6210: * support Wi-Fi Simple Configuration in STA mode
This commit is contained in:
commit
1d36f46b4e
@ -387,7 +387,9 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
|
||||
|
||||
if (!skip_otp && result != 0) {
|
||||
if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
|
||||
ar->fw_features))
|
||||
&& result != 0) {
|
||||
ath10k_err(ar, "otp calibration failed: %d", result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -460,6 +460,14 @@ enum ath10k_fw_features {
|
||||
*/
|
||||
ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6,
|
||||
|
||||
/* Don't trust error code from otp.bin */
|
||||
ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
|
||||
|
||||
/* Some firmware revisions pad 4th hw address to 4 byte boundary making
|
||||
* it 8 bytes long in Native Wifi Rx decap.
|
||||
*/
|
||||
ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
|
@ -36,6 +36,7 @@ enum ath10k_debug_mask {
|
||||
ATH10K_DBG_REGULATORY = 0x00000800,
|
||||
ATH10K_DBG_TESTMODE = 0x00001000,
|
||||
ATH10K_DBG_WMI_PRINT = 0x00002000,
|
||||
ATH10K_DBG_PCI_PS = 0x00004000,
|
||||
ATH10K_DBG_ANY = 0xffffffff,
|
||||
};
|
||||
|
||||
|
@ -965,10 +965,16 @@ static void ath10k_process_rx(struct ath10k *ar,
|
||||
ieee80211_rx(ar->hw, skb);
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
|
||||
static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
/* nwifi header is padded to 4 bytes. this fixes 4addr rx */
|
||||
return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
|
||||
int len = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
|
||||
ar->fw_features))
|
||||
len = round_up(len, 4);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
|
||||
@ -1067,7 +1073,7 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
|
||||
|
||||
/* pull decapped header and copy SA & DA */
|
||||
hdr = (struct ieee80211_hdr *)msdu->data;
|
||||
hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
|
||||
hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
|
||||
ether_addr_copy(da, ieee80211_get_DA(hdr));
|
||||
ether_addr_copy(sa, ieee80211_get_SA(hdr));
|
||||
skb_pull(msdu, hdr_len);
|
||||
|
@ -1708,7 +1708,14 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
|
||||
enable_ps = false;
|
||||
}
|
||||
|
||||
if (enable_ps) {
|
||||
if (!arvif->is_started) {
|
||||
/* mac80211 can update vif powersave state while disconnected.
|
||||
* Firmware doesn't behave nicely and consumes more power than
|
||||
* necessary if PS is disabled on a non-started vdev. Hence
|
||||
* force-enable PS for non-running vdevs.
|
||||
*/
|
||||
psmode = WMI_STA_PS_MODE_ENABLED;
|
||||
} else if (enable_ps) {
|
||||
psmode = WMI_STA_PS_MODE_ENABLED;
|
||||
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
|
||||
|
||||
|
@ -330,6 +330,205 @@ static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static bool ath10k_pci_is_awake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
u32 val = ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
|
||||
RTC_STATE_ADDRESS);
|
||||
|
||||
return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
|
||||
}
|
||||
|
||||
static void __ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
lockdep_assert_held(&ar_pci->ps_lock);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake reg refcount %lu awake %d\n",
|
||||
ar_pci->ps_wake_refcount, ar_pci->ps_awake);
|
||||
|
||||
iowrite32(PCIE_SOC_WAKE_V_MASK,
|
||||
ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
|
||||
PCIE_SOC_WAKE_ADDRESS);
|
||||
}
|
||||
|
||||
static void __ath10k_pci_sleep(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
lockdep_assert_held(&ar_pci->ps_lock);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep reg refcount %lu awake %d\n",
|
||||
ar_pci->ps_wake_refcount, ar_pci->ps_awake);
|
||||
|
||||
iowrite32(PCIE_SOC_WAKE_RESET,
|
||||
ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
|
||||
PCIE_SOC_WAKE_ADDRESS);
|
||||
ar_pci->ps_awake = false;
|
||||
}
|
||||
|
||||
static int ath10k_pci_wake_wait(struct ath10k *ar)
|
||||
{
|
||||
int tot_delay = 0;
|
||||
int curr_delay = 5;
|
||||
|
||||
while (tot_delay < PCIE_WAKE_TIMEOUT) {
|
||||
if (ath10k_pci_is_awake(ar))
|
||||
return 0;
|
||||
|
||||
udelay(curr_delay);
|
||||
tot_delay += curr_delay;
|
||||
|
||||
if (curr_delay < 50)
|
||||
curr_delay += 5;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n",
|
||||
ar_pci->ps_wake_refcount, ar_pci->ps_awake);
|
||||
|
||||
/* This function can be called very frequently. To avoid excessive
|
||||
* CPU stalls for MMIO reads use a cache var to hold the device state.
|
||||
*/
|
||||
if (!ar_pci->ps_awake) {
|
||||
__ath10k_pci_wake(ar);
|
||||
|
||||
ret = ath10k_pci_wake_wait(ar);
|
||||
if (ret == 0)
|
||||
ar_pci->ps_awake = true;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ar_pci->ps_wake_refcount++;
|
||||
WARN_ON(ar_pci->ps_wake_refcount == 0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_pci_sleep(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n",
|
||||
ar_pci->ps_wake_refcount, ar_pci->ps_awake);
|
||||
|
||||
if (WARN_ON(ar_pci->ps_wake_refcount == 0))
|
||||
goto skip;
|
||||
|
||||
ar_pci->ps_wake_refcount--;
|
||||
|
||||
mod_timer(&ar_pci->ps_timer, jiffies +
|
||||
msecs_to_jiffies(ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC));
|
||||
|
||||
skip:
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
}
|
||||
|
||||
static void ath10k_pci_ps_timer(unsigned long ptr)
|
||||
{
|
||||
struct ath10k *ar = (void *)ptr;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps timer refcount %lu awake %d\n",
|
||||
ar_pci->ps_wake_refcount, ar_pci->ps_awake);
|
||||
|
||||
if (ar_pci->ps_wake_refcount > 0)
|
||||
goto skip;
|
||||
|
||||
__ath10k_pci_sleep(ar);
|
||||
|
||||
skip:
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
}
|
||||
|
||||
static void ath10k_pci_sleep_sync(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
del_timer_sync(&ar_pci->ps_timer);
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
WARN_ON(ar_pci->ps_wake_refcount > 0);
|
||||
__ath10k_pci_sleep(ar);
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
}
|
||||
|
||||
void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n",
|
||||
value, offset, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
iowrite32(value, ar_pci->mem + offset);
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n",
|
||||
offset, ret);
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
val = ioread32(ar_pci->mem + offset);
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||
{
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
|
||||
}
|
||||
|
||||
u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
return ath10k_pci_read32(ar, PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||
{
|
||||
ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
|
||||
}
|
||||
|
||||
static bool ath10k_pci_irq_pending(struct ath10k *ar)
|
||||
{
|
||||
u32 cause;
|
||||
@ -793,60 +992,6 @@ static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
|
||||
return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static bool ath10k_pci_is_awake(struct ath10k *ar)
|
||||
{
|
||||
u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
|
||||
|
||||
return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
|
||||
}
|
||||
|
||||
static int ath10k_pci_wake_wait(struct ath10k *ar)
|
||||
{
|
||||
int tot_delay = 0;
|
||||
int curr_delay = 5;
|
||||
|
||||
while (tot_delay < PCIE_WAKE_TIMEOUT) {
|
||||
if (ath10k_pci_is_awake(ar))
|
||||
return 0;
|
||||
|
||||
udelay(curr_delay);
|
||||
tot_delay += curr_delay;
|
||||
|
||||
if (curr_delay < 50)
|
||||
curr_delay += 5;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* The rule is host is forbidden from accessing device registers while it's
|
||||
* asleep. Currently ath10k_pci_wake() and ath10k_pci_sleep() calls aren't
|
||||
* balanced and the device is kept awake all the time. This is intended for a
|
||||
* simpler solution for the following problems:
|
||||
*
|
||||
* * device can enter sleep during s2ram without the host knowing,
|
||||
*
|
||||
* * irq handlers access registers which is a problem if other device asserts
|
||||
* a shared irq line when ath10k is between hif_power_down() and
|
||||
* hif_power_up().
|
||||
*
|
||||
* FIXME: If power consumption is a concern (and there are *real* gains) then a
|
||||
* refcounted wake/sleep needs to be implemented.
|
||||
*/
|
||||
|
||||
static int ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
|
||||
PCIE_SOC_WAKE_V_MASK);
|
||||
return ath10k_pci_wake_wait(ar);
|
||||
}
|
||||
|
||||
static void ath10k_pci_sleep(struct ath10k *ar)
|
||||
{
|
||||
ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
|
||||
PCIE_SOC_WAKE_RESET);
|
||||
}
|
||||
|
||||
/* Called by lower (CE) layer when a send to Target completes. */
|
||||
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
@ -1227,11 +1372,15 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
|
||||
|
||||
static int ath10k_pci_hif_start(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
|
||||
|
||||
ath10k_pci_irq_enable(ar);
|
||||
ath10k_pci_rx_post(ar);
|
||||
|
||||
pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ar_pci->link_ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1344,6 +1493,9 @@ static void ath10k_pci_flush(struct ath10k *ar)
|
||||
|
||||
static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned long flags;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
|
||||
|
||||
/* Most likely the device has HTT Rx ring configured. The only way to
|
||||
@ -1362,6 +1514,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
ath10k_pci_irq_disable(ar);
|
||||
ath10k_pci_irq_sync(ar);
|
||||
ath10k_pci_flush(ar);
|
||||
|
||||
spin_lock_irqsave(&ar_pci->ps_lock, flags);
|
||||
WARN_ON(ar_pci->ps_wake_refcount > 0);
|
||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
||||
@ -1981,15 +2137,15 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
|
||||
|
||||
static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to wake up target: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
&ar_pci->link_ctl);
|
||||
pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
|
||||
ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
|
||||
|
||||
/*
|
||||
* Bring the target up cleanly.
|
||||
@ -2037,7 +2193,6 @@ err_ce:
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
|
||||
err_sleep:
|
||||
ath10k_pci_sleep(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2054,7 +2209,12 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
||||
|
||||
static int ath10k_pci_hif_suspend(struct ath10k *ar)
|
||||
{
|
||||
ath10k_pci_sleep(ar);
|
||||
/* The grace timer can still be counting down and ar->ps_awake be true.
|
||||
* It is known that the device may be asleep after resuming regardless
|
||||
* of the SoC powersave state before suspending. Hence make sure the
|
||||
* device is asleep before proceeding.
|
||||
*/
|
||||
ath10k_pci_sleep_sync(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2064,13 +2224,6 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct pci_dev *pdev = ar_pci->pdev;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to wake device up on resume: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Suspend/Resume resets the PCI configuration space, so we have to
|
||||
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
|
||||
@ -2081,7 +2234,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2175,13 +2328,6 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
||||
{
|
||||
struct ath10k *ar = arg;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (ar_pci->num_msi_intrs == 0) {
|
||||
if (!ath10k_pci_irq_pending(ar))
|
||||
@ -2502,7 +2648,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct pci_dev *pdev = ar_pci->pdev;
|
||||
u32 lcr_val;
|
||||
int ret;
|
||||
|
||||
pci_set_drvdata(pdev, ar);
|
||||
@ -2536,10 +2681,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* Workaround: Disable ASPM */
|
||||
pci_read_config_dword(pdev, 0x80, &lcr_val);
|
||||
pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
|
||||
|
||||
/* Arrange for access to Target SoC registers. */
|
||||
ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
|
||||
if (!ar_pci->mem) {
|
||||
@ -2633,8 +2774,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
pdev->subsystem_vendor, pdev->subsystem_device);
|
||||
|
||||
spin_lock_init(&ar_pci->ce_lock);
|
||||
spin_lock_init(&ar_pci->ps_lock);
|
||||
|
||||
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
|
||||
(unsigned long)ar);
|
||||
setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
|
||||
(unsigned long)ar);
|
||||
|
||||
ret = ath10k_pci_claim(ar);
|
||||
if (ret) {
|
||||
@ -2642,12 +2787,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
goto err_core_destroy;
|
||||
}
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to wake up: %d\n", ret);
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
ret = ath10k_pci_alloc_pipes(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
|
||||
@ -2711,9 +2850,6 @@ err_free_pipes:
|
||||
ath10k_pci_free_pipes(ar);
|
||||
|
||||
err_sleep:
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
err_release:
|
||||
ath10k_pci_release(ar);
|
||||
|
||||
err_core_destroy:
|
||||
@ -2743,6 +2879,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||
ath10k_pci_deinit_irq(ar);
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
ath10k_pci_free_pipes(ar);
|
||||
ath10k_pci_sleep_sync(ar);
|
||||
ath10k_pci_release(ar);
|
||||
ath10k_core_destroy(ar);
|
||||
}
|
||||
|
@ -185,6 +185,41 @@ struct ath10k_pci {
|
||||
/* Map CE id to ce_state */
|
||||
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
|
||||
struct timer_list rx_post_retry;
|
||||
|
||||
/* Due to HW quirks it is recommended to disable ASPM during device
|
||||
* bootup. To do that the original PCI-E Link Control is stored before
|
||||
* device bootup is executed and re-programmed later.
|
||||
*/
|
||||
u16 link_ctl;
|
||||
|
||||
/* Protects ps_awake and ps_wake_refcount */
|
||||
spinlock_t ps_lock;
|
||||
|
||||
/* The device has a special powersave-oriented register. When device is
|
||||
* considered asleep it drains less power and driver is forbidden from
|
||||
* accessing most MMIO registers. If host were to access them without
|
||||
* waking up the device might scribble over host memory or return
|
||||
* 0xdeadbeef readouts.
|
||||
*/
|
||||
unsigned long ps_wake_refcount;
|
||||
|
||||
/* Waking up takes some time (up to 2ms in some cases) so it can be bad
|
||||
* for latency. To mitigate this the device isn't immediately allowed
|
||||
* to sleep after all references are undone - instead there's a grace
|
||||
* period after which the powersave register is updated unless some
|
||||
* activity to/from device happened in the meantime.
|
||||
*
|
||||
* Also see comments on ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC.
|
||||
*/
|
||||
struct timer_list ps_timer;
|
||||
|
||||
/* MMIO registers are used to communicate with the device. With
|
||||
* intensive traffic accessing powersave register would be a bit
|
||||
* wasteful overhead and would needlessly stall CPU. It is far more
|
||||
* efficient to rely on a variable in RAM and update it only upon
|
||||
* powersave register state changes.
|
||||
*/
|
||||
bool ps_awake;
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
@ -209,61 +244,25 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
* for this device; but that's not guaranteed.
|
||||
*/
|
||||
#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \
|
||||
(((ioread32((pci_addr)+(SOC_CORE_BASE_ADDRESS| \
|
||||
(((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \
|
||||
CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \
|
||||
0x100000 | ((addr) & 0xfffff))
|
||||
|
||||
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
|
||||
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
|
||||
|
||||
/* Target exposes its registers for direct access. However before host can
|
||||
* access them it needs to make sure the target is awake (ath10k_pci_wake,
|
||||
* ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
|
||||
* to sleep unless host tells it to (ath10k_pci_sleep).
|
||||
*
|
||||
* If host tries to access target registers without waking it up it can
|
||||
* scribble over host memory.
|
||||
*
|
||||
* If target is asleep waking it up may take up to even 2ms.
|
||||
void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value);
|
||||
void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val);
|
||||
void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val);
|
||||
|
||||
u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
|
||||
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
|
||||
u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr);
|
||||
|
||||
/* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too
|
||||
* frequently. To avoid this put SoC to sleep after a very conservative grace
|
||||
* period. Adjust with great care.
|
||||
*/
|
||||
|
||||
static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
|
||||
u32 value)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
iowrite32(value, ar_pci->mem + offset);
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
return ioread32(ar_pci->mem + offset);
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||
{
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
#define ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC 60
|
||||
|
||||
#endif /* _PCI_H_ */
|
||||
|
@ -519,9 +519,12 @@ int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
|
||||
|
||||
int ath10k_spectral_create(struct ath10k *ar)
|
||||
{
|
||||
/* The buffer size covers whole channels in dual bands up to 128 bins.
|
||||
* Scan with bigger than 128 bins needs to be run on single band each.
|
||||
*/
|
||||
ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
|
||||
ar->debug.debugfs_phy,
|
||||
1024, 256,
|
||||
1140, 2500,
|
||||
&rfs_spec_scan_cb, NULL);
|
||||
debugfs_create_file("spectral_scan_ctl",
|
||||
S_IRUSR | S_IWUSR,
|
||||
|
@ -1645,10 +1645,10 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
||||
survey = &ar->survey[idx];
|
||||
survey->time = WMI_CHAN_INFO_MSEC(cycle_count);
|
||||
survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
|
||||
survey->time_busy = WMI_CHAN_INFO_MSEC(rx_clear_count);
|
||||
survey->noise = noise_floor;
|
||||
survey->filled = SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_BUSY |
|
||||
SURVEY_INFO_NOISE_DBM;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ wil6210-y += debug.o
|
||||
wil6210-y += rx_reorder.o
|
||||
wil6210-y += ioctl.o
|
||||
wil6210-y += fw.o
|
||||
wil6210-y += pmc.o
|
||||
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
|
||||
wil6210-y += wil_platform.o
|
||||
wil6210-y += ethtool.o
|
||||
|
@ -402,11 +402,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
rsn_eid = sme->ie ?
|
||||
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
|
||||
NULL;
|
||||
|
||||
if (sme->privacy && !rsn_eid) {
|
||||
wil_err(wil, "Missing RSN IE for secure connection\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (sme->privacy && !rsn_eid)
|
||||
wil_info(wil, "WSC connection\n");
|
||||
|
||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||
sme->ssid, sme->ssid_len,
|
||||
@ -425,10 +422,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
wil->privacy = sme->privacy;
|
||||
|
||||
if (wil->privacy) {
|
||||
/* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
|
||||
rc = wmi_del_cipher_key(wil, 0, bss->bssid);
|
||||
/* For secure assoc, remove old keys */
|
||||
rc = wmi_del_cipher_key(wil, 0, bss->bssid,
|
||||
WMI_KEY_USE_PAIRWISE);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
|
||||
goto out;
|
||||
}
|
||||
rc = wmi_del_cipher_key(wil, 0, bss->bssid,
|
||||
WMI_KEY_USE_RX_GROUP);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -458,11 +462,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
goto out;
|
||||
}
|
||||
if (wil->privacy) {
|
||||
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
|
||||
conn.auth_mode = WMI_AUTH_WPA2_PSK;
|
||||
conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
|
||||
conn.pairwise_crypto_len = 16;
|
||||
} else {
|
||||
if (rsn_eid) { /* regular secure connection */
|
||||
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
|
||||
conn.auth_mode = WMI_AUTH_WPA2_PSK;
|
||||
conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
|
||||
conn.pairwise_crypto_len = 16;
|
||||
conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
|
||||
conn.group_crypto_len = 16;
|
||||
} else { /* WSC */
|
||||
conn.dot11_auth_mode = WMI_AUTH11_WSC;
|
||||
conn.auth_mode = WMI_AUTH_NONE;
|
||||
}
|
||||
} else { /* insecure connection */
|
||||
conn.dot11_auth_mode = WMI_AUTH11_OPEN;
|
||||
conn.auth_mode = WMI_AUTH_NONE;
|
||||
}
|
||||
@ -507,6 +518,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
|
||||
int rc;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
|
||||
|
||||
rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
|
||||
|
||||
return rc;
|
||||
@ -561,6 +574,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
|
||||
bool pairwise)
|
||||
{
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
enum wmi_key_usage rc;
|
||||
static const char * const key_usage_str[] = {
|
||||
[WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE",
|
||||
[WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP",
|
||||
[WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP",
|
||||
};
|
||||
|
||||
if (pairwise) {
|
||||
rc = WMI_KEY_USE_PAIRWISE;
|
||||
} else {
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
rc = WMI_KEY_USE_RX_GROUP;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
rc = WMI_KEY_USE_TX_GROUP;
|
||||
break;
|
||||
default:
|
||||
/* TODO: Rx GTK or Tx GTK? */
|
||||
wil_err(wil, "Can't determine GTK type\n");
|
||||
rc = WMI_KEY_USE_RX_GROUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 key_index, bool pairwise,
|
||||
@ -568,13 +614,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
|
||||
|
||||
/* group key is not used */
|
||||
if (!pairwise)
|
||||
return 0;
|
||||
wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
|
||||
pairwise ? "PTK" : "GTK");
|
||||
|
||||
return wmi_add_cipher_key(wil, key_index, mac_addr,
|
||||
params->key_len, params->key);
|
||||
return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
|
||||
params->key, key_usage);
|
||||
}
|
||||
|
||||
static int wil_cfg80211_del_key(struct wiphy *wiphy,
|
||||
@ -583,12 +629,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
|
||||
|
||||
/* group key is not used */
|
||||
if (!pairwise)
|
||||
return 0;
|
||||
wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
|
||||
pairwise ? "PTK" : "GTK");
|
||||
|
||||
return wmi_del_cipher_key(wil, key_index, mac_addr);
|
||||
return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
|
||||
}
|
||||
|
||||
/* Need to be present or wiphy_new() will WARN */
|
||||
@ -661,11 +707,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
|
||||
if (bcon->probe_resp_len <= hlen)
|
||||
return 0;
|
||||
|
||||
if (!bcon->proberesp_ies) {
|
||||
bcon->proberesp_ies = f->u.probe_resp.variable;
|
||||
bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
|
||||
rc = 1;
|
||||
}
|
||||
if (!bcon->assocresp_ies) {
|
||||
bcon->assocresp_ies = f->u.probe_resp.variable;
|
||||
bcon->assocresp_ies_len = bcon->probe_resp_len - hlen;
|
||||
@ -680,9 +721,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
struct cfg80211_beacon_data *bcon)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
|
||||
size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
const u8 *pr_ies = NULL;
|
||||
size_t pr_ies_len = 0;
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
wil_print_bcon_data(bcon);
|
||||
|
||||
if (bcon->probe_resp_len > hlen) {
|
||||
pr_ies = f->u.probe_resp.variable;
|
||||
pr_ies_len = bcon->probe_resp_len - hlen;
|
||||
}
|
||||
|
||||
if (wil_fix_bcon(wil, bcon)) {
|
||||
wil_dbg_misc(wil, "Fixed bcon\n");
|
||||
@ -695,9 +746,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
|
||||
* bcon->beacon_ies);
|
||||
*/
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
|
||||
bcon->proberesp_ies_len,
|
||||
bcon->proberesp_ies);
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
|
||||
if (rc) {
|
||||
wil_err(wil, "set_ie(PROBE_RESP) failed\n");
|
||||
return rc;
|
||||
@ -725,6 +774,10 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
struct cfg80211_beacon_data *bcon = &info->beacon;
|
||||
struct cfg80211_crypto_settings *crypto = &info->crypto;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
|
||||
size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
const u8 *pr_ies = NULL;
|
||||
size_t pr_ies_len = 0;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
@ -744,6 +797,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
wil_print_bcon_data(bcon);
|
||||
wil_print_crypto(wil, crypto);
|
||||
|
||||
if (bcon->probe_resp_len > hlen) {
|
||||
pr_ies = f->u.probe_resp.variable;
|
||||
pr_ies_len = bcon->probe_resp_len - hlen;
|
||||
}
|
||||
|
||||
if (wil_fix_bcon(wil, bcon)) {
|
||||
wil_dbg_misc(wil, "Fixed bcon\n");
|
||||
wil_print_bcon_data(bcon);
|
||||
@ -771,8 +829,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
|
||||
* bcon->beacon_ies);
|
||||
*/
|
||||
wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
|
||||
bcon->proberesp_ies);
|
||||
wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
|
||||
wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
|
||||
bcon->assocresp_ies);
|
||||
|
||||
@ -814,13 +871,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
||||
wmi_pcp_stop(wil);
|
||||
|
||||
__wil_down(wil);
|
||||
__wil_up(wil);
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
/* some functions above might fail (e.g. __wil_up). Nevertheless, we
|
||||
* return success because AP has stopped
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -830,6 +883,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, params->mac,
|
||||
params->reason_code);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(wil, params->mac, params->reason_code, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -24,6 +24,7 @@
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
#include "txrx.h"
|
||||
#include "pmc.h"
|
||||
|
||||
/* Nasty hack. Better have per device instances */
|
||||
static u32 mem_addr;
|
||||
@ -123,15 +124,17 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
||||
|
||||
if (cid < WIL6210_MAX_CID)
|
||||
seq_printf(s,
|
||||
"\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
|
||||
"\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
|
||||
wil->sta[cid].addr, cid, tid,
|
||||
txdata->dot1x_open ? "+" : "-",
|
||||
txdata->agg_wsize,
|
||||
txdata->agg_timeout,
|
||||
txdata->agg_amsdu ? "+" : "-",
|
||||
used, avail, sidle);
|
||||
else
|
||||
seq_printf(s,
|
||||
"\nBroadcast [%3d|%3d] idle %s\n",
|
||||
"\nBroadcast 1x%s [%3d|%3d] idle %s\n",
|
||||
txdata->dot1x_open ? "+" : "-",
|
||||
used, avail, sidle);
|
||||
|
||||
wil_print_vring(s, wil, name, vring, '_', 'H');
|
||||
@ -702,6 +705,89 @@ static const struct file_operations fops_back = {
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
/* pmc control, write:
|
||||
* - "alloc <num descriptors> <descriptor_size>" to allocate PMC
|
||||
* - "free" to release memory allocated for PMC
|
||||
*/
|
||||
static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
int rc;
|
||||
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
|
||||
char cmd[9];
|
||||
int num_descs, desc_size;
|
||||
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
|
||||
if (rc != len) {
|
||||
kfree(kbuf);
|
||||
return rc >= 0 ? -EIO : rc;
|
||||
}
|
||||
|
||||
kbuf[len] = '\0';
|
||||
rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
|
||||
kfree(kbuf);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc < 1) {
|
||||
wil_err(wil, "pmccfg: no params given\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (0 == strcmp(cmd, "alloc")) {
|
||||
if (rc != 3) {
|
||||
wil_err(wil, "pmccfg: alloc requires 2 params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
wil_pmc_alloc(wil, num_descs, desc_size);
|
||||
} else if (0 == strcmp(cmd, "free")) {
|
||||
if (rc != 1) {
|
||||
wil_err(wil, "pmccfg: free does not have any params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
wil_pmc_free(wil, true);
|
||||
} else {
|
||||
wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
char text[256];
|
||||
char help[] = "pmc control, write:\n"
|
||||
" - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
|
||||
" - \"free\" to free memory allocated for pmc\n";
|
||||
|
||||
sprintf(text, "Last command status: %d\n\n%s",
|
||||
wil_pmc_last_cmd_status(wil),
|
||||
help);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, text,
|
||||
strlen(text) + 1);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_pmccfg = {
|
||||
.read = wil_read_pmccfg,
|
||||
.write = wil_write_pmccfg,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
static const struct file_operations fops_pmcdata = {
|
||||
.open = simple_open,
|
||||
.read = wil_pmc_read,
|
||||
.llseek = wil_pmc_llseek,
|
||||
};
|
||||
|
||||
/*---tx_mgmt---*/
|
||||
/* Write mgmt frame to this file to send it */
|
||||
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
||||
@ -1111,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
|
||||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
|
||||
(p->data_port_open ? " data_port_open" : ""));
|
||||
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
rc = wil_cid_fill_sinfo(wil, i, &sinfo);
|
||||
@ -1292,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
||||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
|
||||
(p->data_port_open ? " data_port_open" : ""));
|
||||
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
spin_lock_bh(&p->tid_rx_lock);
|
||||
@ -1363,6 +1447,8 @@ static const struct {
|
||||
{"tx_mgmt", S_IWUSR, &fops_txmgmt},
|
||||
{"wmi_send", S_IWUSR, &fops_wmi},
|
||||
{"back", S_IRUGO | S_IWUSR, &fops_back},
|
||||
{"pmccfg", S_IRUGO | S_IWUSR, &fops_pmccfg},
|
||||
{"pmcdata", S_IRUGO, &fops_pmcdata},
|
||||
{"temp", S_IRUGO, &fops_temp},
|
||||
{"freq", S_IRUGO, &fops_freq},
|
||||
{"link", S_IRUGO, &fops_link},
|
||||
@ -1440,6 +1526,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
||||
if (IS_ERR_OR_NULL(dbg))
|
||||
return -ENODEV;
|
||||
|
||||
wil_pmc_init(wil);
|
||||
|
||||
wil6210_debugfs_init_files(wil, dbg);
|
||||
wil6210_debugfs_init_isr(wil, dbg);
|
||||
wil6210_debugfs_init_blobs(wil, dbg);
|
||||
@ -1459,4 +1547,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
|
||||
{
|
||||
debugfs_remove_recursive(wil->debug);
|
||||
wil->debug = NULL;
|
||||
|
||||
/* free pmc memory without sending command to fw, as it will
|
||||
* be reset on the way down anyway
|
||||
*/
|
||||
wil_pmc_free(wil, false);
|
||||
}
|
||||
|
@ -25,6 +25,10 @@
|
||||
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
|
||||
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
|
||||
|
||||
bool debug_fw; /* = false; */
|
||||
module_param(debug_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
|
||||
|
||||
bool no_fw_recovery;
|
||||
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
|
||||
@ -146,7 +150,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
|
||||
sta->status);
|
||||
|
||||
sta->data_port_open = false;
|
||||
if (sta->status != wil_sta_unused) {
|
||||
if (!from_event)
|
||||
wmi_disconnect_sta(wil, sta->addr, reason_code);
|
||||
@ -373,9 +376,10 @@ int wil_bcast_init(struct wil6210_priv *wil)
|
||||
if (ri < 0)
|
||||
return ri;
|
||||
|
||||
wil->bcast_vring = ri;
|
||||
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
|
||||
if (rc == 0)
|
||||
wil->bcast_vring = ri;
|
||||
if (rc)
|
||||
wil->bcast_vring = -1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -547,7 +551,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
|
||||
static int wil_target_reset(struct wil6210_priv *wil)
|
||||
{
|
||||
int delay = 0;
|
||||
u32 x;
|
||||
u32 x, x1 = 0;
|
||||
|
||||
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
|
||||
|
||||
@ -602,12 +606,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
|
||||
do {
|
||||
msleep(RST_DELAY);
|
||||
x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
|
||||
if (x1 != x) {
|
||||
wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
|
||||
x1 = x;
|
||||
}
|
||||
if (delay++ > RST_COUNT) {
|
||||
wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
|
||||
x);
|
||||
return -ETIME;
|
||||
}
|
||||
} while (!(x & BIT_BL_READY));
|
||||
} while (x != BIT_BL_READY);
|
||||
|
||||
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
|
||||
|
||||
@ -686,6 +694,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
WARN_ON(!mutex_is_locked(&wil->mutex));
|
||||
WARN_ON(test_bit(wil_status_napi_en, wil->status));
|
||||
|
||||
if (debug_fw) {
|
||||
static const u8 mac[ETH_ALEN] = {
|
||||
0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
|
||||
};
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
ether_addr_copy(ndev->perm_addr, mac);
|
||||
ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
|
@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev)
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
if (debug_fw) {
|
||||
wil_err(wil, "%s() while in debug_fw mode\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return wil_up(wil);
|
||||
}
|
||||
|
||||
|
@ -27,10 +27,6 @@ MODULE_PARM_DESC(use_msi,
|
||||
" Use MSI interrupt: "
|
||||
"0 - don't, 1 - (default) - single, or 3");
|
||||
|
||||
static bool debug_fw; /* = false; */
|
||||
module_param(debug_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
|
||||
|
||||
static
|
||||
void wil_set_capabilities(struct wil6210_priv *wil)
|
||||
{
|
||||
@ -133,8 +129,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
||||
mutex_lock(&wil->mutex);
|
||||
rc = wil_reset(wil, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
if (debug_fw)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
goto release_irq;
|
||||
|
||||
|
375
drivers/net/wireless/ath/wil6210/pmc.c
Normal file
375
drivers/net/wireless/ath/wil6210/pmc.c
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include "wmi.h"
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
#include "pmc.h"
|
||||
|
||||
struct desc_alloc_info {
|
||||
dma_addr_t pa;
|
||||
void *va;
|
||||
};
|
||||
|
||||
static int wil_is_pmc_allocated(struct pmc_ctx *pmc)
|
||||
{
|
||||
return !!pmc->pring_va;
|
||||
}
|
||||
|
||||
void wil_pmc_init(struct wil6210_priv *wil)
|
||||
{
|
||||
memset(&wil->pmc, 0, sizeof(struct pmc_ctx));
|
||||
mutex_init(&wil->pmc.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the physical ring (p-ring) and the required
|
||||
* number of descriptors of required size.
|
||||
* Initialize the descriptors as required by pmc dma.
|
||||
* The descriptors' buffers dwords are initialized to hold
|
||||
* dword's serial number in the lsw and reserved value
|
||||
* PCM_DATA_INVALID_DW_VAL in the msw.
|
||||
*/
|
||||
void wil_pmc_alloc(struct wil6210_priv *wil,
|
||||
int num_descriptors,
|
||||
int descriptor_size)
|
||||
{
|
||||
u32 i;
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wmi_pmc_cmd pmc_cmd = {0};
|
||||
|
||||
mutex_lock(&pmc->lock);
|
||||
|
||||
if (wil_is_pmc_allocated(pmc)) {
|
||||
/* sanity check */
|
||||
wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__);
|
||||
goto no_release_err;
|
||||
}
|
||||
|
||||
pmc->num_descriptors = num_descriptors;
|
||||
pmc->descriptor_size = descriptor_size;
|
||||
|
||||
wil_dbg_misc(wil, "%s: %d descriptors x %d bytes each\n",
|
||||
__func__, num_descriptors, descriptor_size);
|
||||
|
||||
/* allocate descriptors info list in pmc context*/
|
||||
pmc->descriptors = kcalloc(num_descriptors,
|
||||
sizeof(struct desc_alloc_info),
|
||||
GFP_KERNEL);
|
||||
if (!pmc->descriptors) {
|
||||
wil_err(wil, "%s: ERROR allocating pmc skb list\n", __func__);
|
||||
goto no_release_err;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"%s: allocated descriptors info list %p\n",
|
||||
__func__, pmc->descriptors);
|
||||
|
||||
/* Allocate pring buffer and descriptors.
|
||||
* vring->va should be aligned on its size rounded up to power of 2
|
||||
* This is granted by the dma_alloc_coherent
|
||||
*/
|
||||
pmc->pring_va = dma_alloc_coherent(dev,
|
||||
sizeof(struct vring_tx_desc) * num_descriptors,
|
||||
&pmc->pring_pa,
|
||||
GFP_KERNEL);
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"%s: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
|
||||
__func__,
|
||||
pmc->pring_va, &pmc->pring_pa,
|
||||
sizeof(struct vring_tx_desc),
|
||||
num_descriptors,
|
||||
sizeof(struct vring_tx_desc) * num_descriptors);
|
||||
|
||||
if (!pmc->pring_va) {
|
||||
wil_err(wil, "%s: ERROR allocating pmc pring\n", __func__);
|
||||
goto release_pmc_skb_list;
|
||||
}
|
||||
|
||||
/* initially, all descriptors are SW owned
|
||||
* For Tx, Rx, and PMC, ownership bit is at the same location, thus
|
||||
* we can use any
|
||||
*/
|
||||
for (i = 0; i < num_descriptors; i++) {
|
||||
struct vring_tx_desc *_d = &pmc->pring_va[i];
|
||||
struct vring_tx_desc dd, *d = ⅆ
|
||||
int j = 0;
|
||||
|
||||
pmc->descriptors[i].va = dma_alloc_coherent(dev,
|
||||
descriptor_size,
|
||||
&pmc->descriptors[i].pa,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (unlikely(!pmc->descriptors[i].va)) {
|
||||
wil_err(wil,
|
||||
"%s: ERROR allocating pmc descriptor %d",
|
||||
__func__, i);
|
||||
goto release_pmc_skbs;
|
||||
}
|
||||
|
||||
for (j = 0; j < descriptor_size / sizeof(u32); j++) {
|
||||
u32 *p = (u32 *)pmc->descriptors[i].va + j;
|
||||
*p = PCM_DATA_INVALID_DW_VAL | j;
|
||||
}
|
||||
|
||||
/* configure dma descriptor */
|
||||
d->dma.addr.addr_low =
|
||||
cpu_to_le32(lower_32_bits(pmc->descriptors[i].pa));
|
||||
d->dma.addr.addr_high =
|
||||
cpu_to_le16((u16)upper_32_bits(pmc->descriptors[i].pa));
|
||||
d->dma.status = 0; /* 0 = HW_OWNED */
|
||||
d->dma.length = cpu_to_le16(descriptor_size);
|
||||
d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
|
||||
*_d = *d;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "%s: allocated successfully\n", __func__);
|
||||
|
||||
pmc_cmd.op = WMI_PMC_ALLOCATE;
|
||||
pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors);
|
||||
pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa);
|
||||
|
||||
wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with ALLOCATE op\n", __func__);
|
||||
pmc->last_cmd_status = wmi_send(wil,
|
||||
WMI_PMC_CMDID,
|
||||
&pmc_cmd,
|
||||
sizeof(pmc_cmd));
|
||||
if (pmc->last_cmd_status) {
|
||||
wil_err(wil,
|
||||
"%s: WMI_PMC_CMD with ALLOCATE op failed with status %d",
|
||||
__func__, pmc->last_cmd_status);
|
||||
goto release_pmc_skbs;
|
||||
}
|
||||
|
||||
mutex_unlock(&pmc->lock);
|
||||
|
||||
return;
|
||||
|
||||
release_pmc_skbs:
|
||||
wil_err(wil, "%s: exit on error: Releasing skbs...\n", __func__);
|
||||
for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
|
||||
dma_free_coherent(dev,
|
||||
descriptor_size,
|
||||
pmc->descriptors[i].va,
|
||||
pmc->descriptors[i].pa);
|
||||
|
||||
pmc->descriptors[i].va = NULL;
|
||||
}
|
||||
wil_err(wil, "%s: exit on error: Releasing pring...\n", __func__);
|
||||
|
||||
dma_free_coherent(dev,
|
||||
sizeof(struct vring_tx_desc) * num_descriptors,
|
||||
pmc->pring_va,
|
||||
pmc->pring_pa);
|
||||
|
||||
pmc->pring_va = NULL;
|
||||
|
||||
release_pmc_skb_list:
|
||||
wil_err(wil, "%s: exit on error: Releasing descriptors info list...\n",
|
||||
__func__);
|
||||
kfree(pmc->descriptors);
|
||||
pmc->descriptors = NULL;
|
||||
|
||||
no_release_err:
|
||||
pmc->last_cmd_status = -ENOMEM;
|
||||
mutex_unlock(&pmc->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse the p-ring and release all buffers.
|
||||
* At the end release the p-ring memory
|
||||
*/
|
||||
void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
|
||||
{
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wmi_pmc_cmd pmc_cmd = {0};
|
||||
|
||||
mutex_lock(&pmc->lock);
|
||||
|
||||
pmc->last_cmd_status = 0;
|
||||
|
||||
if (!wil_is_pmc_allocated(pmc)) {
|
||||
wil_dbg_misc(wil, "%s: Error, can't free - not allocated\n",
|
||||
__func__);
|
||||
pmc->last_cmd_status = -EPERM;
|
||||
mutex_unlock(&pmc->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (send_pmc_cmd) {
|
||||
wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with RELEASE op\n",
|
||||
__func__);
|
||||
pmc_cmd.op = WMI_PMC_RELEASE;
|
||||
pmc->last_cmd_status =
|
||||
wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
|
||||
sizeof(pmc_cmd));
|
||||
if (pmc->last_cmd_status) {
|
||||
wil_err(wil,
|
||||
"%s WMI_PMC_CMD with RELEASE op failed, status %d",
|
||||
__func__, pmc->last_cmd_status);
|
||||
/* There's nothing we can do with this error.
|
||||
* Normally, it should never occur.
|
||||
* Continue to freeing all memory allocated for pmc.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (pmc->pring_va) {
|
||||
size_t buf_size = sizeof(struct vring_tx_desc) *
|
||||
pmc->num_descriptors;
|
||||
|
||||
wil_dbg_misc(wil, "%s: free pring va %p\n",
|
||||
__func__, pmc->pring_va);
|
||||
dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa);
|
||||
|
||||
pmc->pring_va = NULL;
|
||||
} else {
|
||||
pmc->last_cmd_status = -ENOENT;
|
||||
}
|
||||
|
||||
if (pmc->descriptors) {
|
||||
int i;
|
||||
|
||||
for (i = 0;
|
||||
pmc->descriptors[i].va && i < pmc->num_descriptors; i++) {
|
||||
dma_free_coherent(dev,
|
||||
pmc->descriptor_size,
|
||||
pmc->descriptors[i].va,
|
||||
pmc->descriptors[i].pa);
|
||||
pmc->descriptors[i].va = NULL;
|
||||
}
|
||||
wil_dbg_misc(wil, "%s: free descriptor info %d/%d\n",
|
||||
__func__, i, pmc->num_descriptors);
|
||||
wil_dbg_misc(wil,
|
||||
"%s: free pmc descriptors info list %p\n",
|
||||
__func__, pmc->descriptors);
|
||||
kfree(pmc->descriptors);
|
||||
pmc->descriptors = NULL;
|
||||
} else {
|
||||
pmc->last_cmd_status = -ENOENT;
|
||||
}
|
||||
|
||||
mutex_unlock(&pmc->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of the last operation requested via debugfs: alloc/free/read.
|
||||
* 0 - success or negative errno
|
||||
*/
|
||||
int wil_pmc_last_cmd_status(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "%s: status %d\n", __func__,
|
||||
wil->pmc.last_cmd_status);
|
||||
|
||||
return wil->pmc.last_cmd_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from required position up to the end of current descriptor,
|
||||
* depends on descriptor size configured during alloc request.
|
||||
*/
|
||||
ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count,
|
||||
loff_t *f_pos)
|
||||
{
|
||||
struct wil6210_priv *wil = filp->private_data;
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
size_t retval = 0;
|
||||
unsigned long long idx;
|
||||
loff_t offset;
|
||||
size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
|
||||
|
||||
mutex_lock(&pmc->lock);
|
||||
|
||||
if (!wil_is_pmc_allocated(pmc)) {
|
||||
wil_err(wil, "%s: error, pmc is not allocated!\n", __func__);
|
||||
pmc->last_cmd_status = -EPERM;
|
||||
mutex_unlock(&pmc->lock);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"%s: size %u, pos %lld\n",
|
||||
__func__, (unsigned)count, *f_pos);
|
||||
|
||||
pmc->last_cmd_status = 0;
|
||||
|
||||
idx = *f_pos;
|
||||
do_div(idx, pmc->descriptor_size);
|
||||
offset = *f_pos - (idx * pmc->descriptor_size);
|
||||
|
||||
if (*f_pos >= pmc_size) {
|
||||
wil_dbg_misc(wil, "%s: reached end of pmc buf: %lld >= %u\n",
|
||||
__func__, *f_pos, (unsigned)pmc_size);
|
||||
pmc->last_cmd_status = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"%s: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n",
|
||||
__func__, *f_pos, idx, offset, count);
|
||||
|
||||
/* if no errors, return the copied byte count */
|
||||
retval = simple_read_from_buffer(buf,
|
||||
count,
|
||||
&offset,
|
||||
pmc->descriptors[idx].va,
|
||||
pmc->descriptor_size);
|
||||
*f_pos += retval;
|
||||
out:
|
||||
mutex_unlock(&pmc->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence)
|
||||
{
|
||||
loff_t newpos;
|
||||
struct wil6210_priv *wil = filp->private_data;
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
|
||||
|
||||
switch (whence) {
|
||||
case 0: /* SEEK_SET */
|
||||
newpos = off;
|
||||
break;
|
||||
|
||||
case 1: /* SEEK_CUR */
|
||||
newpos = filp->f_pos + off;
|
||||
break;
|
||||
|
||||
case 2: /* SEEK_END */
|
||||
newpos = pmc_size;
|
||||
break;
|
||||
|
||||
default: /* can't happen */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (newpos < 0)
|
||||
return -EINVAL;
|
||||
if (newpos > pmc_size)
|
||||
newpos = pmc_size;
|
||||
|
||||
filp->f_pos = newpos;
|
||||
|
||||
return newpos;
|
||||
}
|
27
drivers/net/wireless/ath/wil6210/pmc.h
Normal file
27
drivers/net/wireless/ath/wil6210/pmc.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define PCM_DATA_INVALID_DW_VAL (0xB0BA0000)
|
||||
|
||||
void wil_pmc_init(struct wil6210_priv *wil);
|
||||
void wil_pmc_alloc(struct wil6210_priv *wil,
|
||||
int num_descriptors, int descriptor_size);
|
||||
void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd);
|
||||
int wil_pmc_last_cmd_status(struct wil6210_priv *wil);
|
||||
ssize_t wil_pmc_read(struct file *, char __user *, size_t, loff_t *);
|
||||
loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -236,7 +236,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
|
||||
d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT;
|
||||
wil_desc_addr_set(&d->dma.addr, pa);
|
||||
/* ip_length don't care */
|
||||
/* b11 don't care */
|
||||
@ -724,6 +724,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
if (!wil->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
@ -738,11 +740,13 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
|
||||
txdata->enabled = 1;
|
||||
if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
|
||||
if (txdata->dot1x_open && (agg_wsize >= 0))
|
||||
wil_addba_tx_request(wil, id, agg_wsize);
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
txdata->dot1x_open = false;
|
||||
txdata->enabled = 0;
|
||||
wil_vring_free(wil, vring, 1);
|
||||
out:
|
||||
|
||||
@ -792,6 +796,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
if (!wil->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
@ -809,6 +815,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
txdata->enabled = 0;
|
||||
txdata->dot1x_open = false;
|
||||
wil_vring_free(wil, vring, 1);
|
||||
out:
|
||||
|
||||
@ -828,6 +836,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
||||
wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
|
||||
|
||||
spin_lock_bh(&txdata->lock);
|
||||
txdata->dot1x_open = false;
|
||||
txdata->enabled = 0; /* no Tx can be in progress or start anew */
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
/* make sure NAPI won't touch this vring */
|
||||
@ -848,12 +857,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
||||
if (cid < 0)
|
||||
return NULL;
|
||||
|
||||
if (!wil->sta[cid].data_port_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
return NULL;
|
||||
|
||||
/* TODO: fix for multiple TID */
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
|
||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
continue;
|
||||
if (wil->vring2cid_tid[i][0] == cid) {
|
||||
struct vring *v = &wil->vring_tx[i];
|
||||
|
||||
@ -883,7 +891,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||
|
||||
/* In the STA mode, it is expected to have only 1 VRING
|
||||
* for the AP we connected to.
|
||||
* find 1-st vring and see whether it is eligible for data
|
||||
* find 1-st vring eligible for this skb and use it.
|
||||
*/
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v = &wil->vring_tx[i];
|
||||
@ -894,9 +902,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
continue;
|
||||
|
||||
if (!wil->sta[cid].data_port_open &&
|
||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
break;
|
||||
continue;
|
||||
|
||||
wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
|
||||
|
||||
@ -918,7 +926,6 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||
* in all cases override dest address to unicast peer's address
|
||||
* Use old strategy when new is not supported yet:
|
||||
* - for PBSS
|
||||
* - for secure link
|
||||
*/
|
||||
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
@ -931,6 +938,9 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
|
||||
v = &wil->vring_tx[i];
|
||||
if (!v->va)
|
||||
return NULL;
|
||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
return NULL;
|
||||
|
||||
return v;
|
||||
}
|
||||
@ -963,7 +973,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
continue;
|
||||
if (!wil->sta[cid].data_port_open)
|
||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
continue;
|
||||
|
||||
/* don't Tx back to source when re-routing Rx->Tx at the AP */
|
||||
@ -989,7 +1000,8 @@ found:
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
continue;
|
||||
if (!wil->sta[cid].data_port_open)
|
||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
continue;
|
||||
|
||||
if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
|
||||
@ -1016,9 +1028,6 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP)
|
||||
return wil_find_tx_bcast_2(wil, skb);
|
||||
|
||||
if (wil->privacy)
|
||||
return wil_find_tx_bcast_2(wil, skb);
|
||||
|
||||
return wil_find_tx_bcast_1(wil, skb);
|
||||
}
|
||||
|
||||
@ -1144,13 +1153,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
wil_tx_desc_map(d, pa, len, vring_index);
|
||||
if (unlikely(mcast)) {
|
||||
d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */
|
||||
if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) {
|
||||
/* set MCS 1 */
|
||||
if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) /* set MCS 1 */
|
||||
d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);
|
||||
/* packet mode 2 */
|
||||
d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) |
|
||||
(2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS);
|
||||
}
|
||||
}
|
||||
/* Process TCP/UDP checksum offloading */
|
||||
if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) {
|
||||
|
@ -384,19 +384,27 @@ struct vring_rx_mac {
|
||||
* [word 7] length
|
||||
*/
|
||||
|
||||
#define RX_DMA_D0_CMD_DMA_IT BIT(10)
|
||||
#define RX_DMA_D0_CMD_DMA_EOP BIT(8)
|
||||
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
|
||||
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
|
||||
|
||||
/* Error field, offload bits */
|
||||
#define RX_DMA_ERROR_L3_ERR BIT(4)
|
||||
#define RX_DMA_ERROR_L4_ERR BIT(5)
|
||||
/* Error field */
|
||||
#define RX_DMA_ERROR_FCS BIT(0)
|
||||
#define RX_DMA_ERROR_MIC BIT(1)
|
||||
#define RX_DMA_ERROR_KEY BIT(2) /* Key missing */
|
||||
#define RX_DMA_ERROR_REPLAY BIT(3)
|
||||
#define RX_DMA_ERROR_L3_ERR BIT(4)
|
||||
#define RX_DMA_ERROR_L4_ERR BIT(5)
|
||||
|
||||
/* Status field */
|
||||
#define RX_DMA_STATUS_DU BIT(0)
|
||||
#define RX_DMA_STATUS_ERROR BIT(2)
|
||||
|
||||
#define RX_DMA_STATUS_DU BIT(0)
|
||||
#define RX_DMA_STATUS_EOP BIT(1)
|
||||
#define RX_DMA_STATUS_ERROR BIT(2)
|
||||
#define RX_DMA_STATUS_MI BIT(3) /* MAC Interrupt is asserted */
|
||||
#define RX_DMA_STATUS_L3I BIT(4)
|
||||
#define RX_DMA_STATUS_L4I BIT(5)
|
||||
#define RX_DMA_STATUS_PHY_INFO BIT(6)
|
||||
#define RX_DMA_STATUS_FFM BIT(7) /* EtherType Flex Filter Match */
|
||||
|
||||
struct vring_rx_dma {
|
||||
u32 d0;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/types.h>
|
||||
#include "wil_platform.h"
|
||||
|
||||
extern bool no_fw_recovery;
|
||||
@ -29,10 +30,11 @@ extern unsigned short rx_ring_overflow_thrsh;
|
||||
extern int agg_wsize;
|
||||
extern u32 vring_idle_trsh;
|
||||
extern bool rx_align_2;
|
||||
extern bool debug_fw;
|
||||
|
||||
#define WIL_NAME "wil6210"
|
||||
#define WIL_FW_NAME "wil6210.fw" /* code */
|
||||
#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */
|
||||
#define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */
|
||||
|
||||
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
|
||||
|
||||
@ -396,6 +398,7 @@ struct vring {
|
||||
* Additional data for Tx Vring
|
||||
*/
|
||||
struct vring_tx_data {
|
||||
bool dot1x_open;
|
||||
int enabled;
|
||||
cycles_t idle, last_idle, begin;
|
||||
u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
|
||||
@ -484,7 +487,6 @@ struct wil_sta_info {
|
||||
u8 addr[ETH_ALEN];
|
||||
enum wil_sta_status status;
|
||||
struct wil_net_stats stats;
|
||||
bool data_port_open; /* can send any data, not only EAPOL */
|
||||
/* Rx BACK */
|
||||
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
|
||||
spinlock_t tid_rx_lock; /* guarding tid_rx array */
|
||||
@ -526,6 +528,17 @@ struct wil_probe_client_req {
|
||||
u8 cid;
|
||||
};
|
||||
|
||||
struct pmc_ctx {
|
||||
/* alloc, free, and read operations must own the lock */
|
||||
struct mutex lock;
|
||||
struct vring_tx_desc *pring_va;
|
||||
dma_addr_t pring_pa;
|
||||
struct desc_alloc_info *descriptors;
|
||||
int last_cmd_status;
|
||||
int num_descriptors;
|
||||
int descriptor_size;
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
int n_msi;
|
||||
@ -610,6 +623,8 @@ struct wil6210_priv {
|
||||
|
||||
void *platform_handle;
|
||||
struct wil_platform_ops platform_ops;
|
||||
|
||||
struct pmc_ctx pmc;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
@ -701,9 +716,10 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
|
||||
int wmi_set_channel(struct wil6210_priv *wil, int channel);
|
||||
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr);
|
||||
const void *mac_addr, int key_usage);
|
||||
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr, int key_len, const void *key);
|
||||
const void *mac_addr, int key_len, const void *key,
|
||||
int key_usage);
|
||||
int wmi_echo(struct wil6210_priv *wil);
|
||||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -543,55 +543,22 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
||||
}
|
||||
}
|
||||
|
||||
static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
|
||||
static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct vring_tx_data *t;
|
||||
int i;
|
||||
struct wmi_vring_en_event *evt = d;
|
||||
u8 vri = evt->vring_index;
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
if (cid != wil->vring2cid_tid[i][0])
|
||||
continue;
|
||||
t = &wil->vring_tx_data[i];
|
||||
if (!t->enabled)
|
||||
continue;
|
||||
wil_dbg_wmi(wil, "Enable vring %d\n", vri);
|
||||
|
||||
wil_addba_tx_request(wil, i, wsize);
|
||||
}
|
||||
}
|
||||
|
||||
static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct wmi_data_port_open_event *evt = d;
|
||||
u8 cid = evt->cid;
|
||||
|
||||
wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
|
||||
|
||||
if (cid >= ARRAY_SIZE(wil->sta)) {
|
||||
wil_err(wil, "Link UP for invalid CID %d\n", cid);
|
||||
if (vri >= ARRAY_SIZE(wil->vring_tx)) {
|
||||
wil_err(wil, "Enable for invalid vring %d\n", vri);
|
||||
return;
|
||||
}
|
||||
|
||||
wil->sta[cid].data_port_open = true;
|
||||
wil->vring_tx_data[vri].dot1x_open = true;
|
||||
if (vri == wil->bcast_vring) /* no BA for bcast */
|
||||
return;
|
||||
if (agg_wsize >= 0)
|
||||
wil_addba_tx_cid(wil, cid, agg_wsize);
|
||||
}
|
||||
|
||||
static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wmi_wbe_link_down_event *evt = d;
|
||||
u8 cid = evt->cid;
|
||||
|
||||
wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
|
||||
cid, le32_to_cpu(evt->reason));
|
||||
|
||||
if (cid >= ARRAY_SIZE(wil->sta)) {
|
||||
wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
|
||||
return;
|
||||
}
|
||||
|
||||
wil->sta[cid].data_port_open = false;
|
||||
netif_carrier_off(ndev);
|
||||
wil_addba_tx_request(wil, vri, agg_wsize);
|
||||
}
|
||||
|
||||
static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
|
||||
@ -695,11 +662,10 @@ static const struct {
|
||||
{WMI_CONNECT_EVENTID, wmi_evt_connect},
|
||||
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
|
||||
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
|
||||
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
|
||||
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
|
||||
{WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
|
||||
{WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
|
||||
{WMI_DELBA_EVENTID, wmi_evt_delba},
|
||||
{WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -844,7 +810,7 @@ int wmi_echo(struct wil6210_priv *wil)
|
||||
};
|
||||
|
||||
return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
|
||||
WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
|
||||
}
|
||||
|
||||
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
|
||||
@ -985,7 +951,7 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
|
||||
}
|
||||
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr)
|
||||
const void *mac_addr, int key_usage)
|
||||
{
|
||||
struct wmi_delete_cipher_key_cmd cmd = {
|
||||
.key_index = key_index,
|
||||
@ -998,11 +964,12 @@ int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
}
|
||||
|
||||
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr, int key_len, const void *key)
|
||||
const void *mac_addr, int key_len, const void *key,
|
||||
int key_usage)
|
||||
{
|
||||
struct wmi_add_cipher_key_cmd cmd = {
|
||||
.key_index = key_index,
|
||||
.key_usage = WMI_KEY_USE_PAIRWISE,
|
||||
.key_usage = key_usage,
|
||||
.key_len = key_len,
|
||||
};
|
||||
|
||||
@ -1238,7 +1205,8 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
|
||||
cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
|
||||
|
||||
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
|
||||
WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
|
||||
100);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2006-2012 Wilocity .
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
@ -253,8 +253,8 @@ struct wmi_set_passphrase_cmd {
|
||||
*/
|
||||
enum wmi_key_usage {
|
||||
WMI_KEY_USE_PAIRWISE = 0,
|
||||
WMI_KEY_USE_GROUP = 1,
|
||||
WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */
|
||||
WMI_KEY_USE_RX_GROUP = 1,
|
||||
WMI_KEY_USE_TX_GROUP = 2,
|
||||
};
|
||||
|
||||
struct wmi_add_cipher_key_cmd {
|
||||
@ -835,6 +835,21 @@ struct wmi_temp_sense_cmd {
|
||||
__le32 measure_mode;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI_PMC_CMDID
|
||||
*/
|
||||
enum wmi_pmc_op_e {
|
||||
WMI_PMC_ALLOCATE = 0,
|
||||
WMI_PMC_RELEASE = 1,
|
||||
};
|
||||
|
||||
struct wmi_pmc_cmd {
|
||||
u8 op; /* enum wmi_pmc_cmd_op_type */
|
||||
u8 reserved;
|
||||
__le16 ring_size;
|
||||
__le64 mem_base;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI Events
|
||||
*/
|
||||
@ -870,7 +885,7 @@ enum wmi_event_id {
|
||||
WMI_VRING_CFG_DONE_EVENTID = 0x1821,
|
||||
WMI_BA_STATUS_EVENTID = 0x1823,
|
||||
WMI_RCP_ADDBA_REQ_EVENTID = 0x1824,
|
||||
WMI_ADDBA_RESP_SENT_EVENTID = 0x1825,
|
||||
WMI_RCP_ADDBA_RESP_SENT_EVENTID = 0x1825,
|
||||
WMI_DELBA_EVENTID = 0x1826,
|
||||
WMI_GET_SSID_EVENTID = 0x1828,
|
||||
WMI_GET_PCP_CHANNEL_EVENTID = 0x182a,
|
||||
@ -882,7 +897,7 @@ enum wmi_event_id {
|
||||
WMI_WRITE_MAC_TXQ_EVENTID = 0x1833,
|
||||
WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834,
|
||||
|
||||
WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836,
|
||||
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
|
||||
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
|
||||
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
|
||||
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
|
||||
@ -894,11 +909,12 @@ enum wmi_event_id {
|
||||
|
||||
/* Performance monitoring events */
|
||||
WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
|
||||
WMI_WBE_LINKDOWN_EVENTID = 0x1861,
|
||||
WMI_WBE_LINK_DOWN_EVENTID = 0x1861,
|
||||
|
||||
WMI_BF_CTRL_DONE_EVENTID = 0x1862,
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863,
|
||||
WMI_GET_STATUS_DONE_EVENTID = 0x1864,
|
||||
WMI_VRING_EN_EVENTID = 0x1865,
|
||||
|
||||
WMI_UNIT_TEST_EVENTID = 0x1900,
|
||||
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
|
||||
@ -1147,7 +1163,7 @@ struct wmi_vring_cfg_done_event {
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI_ADDBA_RESP_SENT_EVENTID
|
||||
* WMI_RCP_ADDBA_RESP_SENT_EVENTID
|
||||
*/
|
||||
struct wmi_rcp_addba_resp_sent_event {
|
||||
u8 cidxtid;
|
||||
@ -1179,7 +1195,7 @@ struct wmi_cfg_rx_chain_done_event {
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI_WBE_LINKDOWN_EVENTID
|
||||
* WMI_WBE_LINK_DOWN_EVENTID
|
||||
*/
|
||||
enum wmi_wbe_link_down_event_reason {
|
||||
WMI_WBE_REASON_USER_REQUEST = 0,
|
||||
@ -1201,6 +1217,14 @@ struct wmi_data_port_open_event {
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI_VRING_EN_EVENTID
|
||||
*/
|
||||
struct wmi_vring_en_event {
|
||||
u8 vring_index;
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* WMI_GET_PCP_CHANNEL_EVENTID
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user