mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 07:37:31 -04:00
Merge "wil6210: support IPA offload"
This commit is contained in:
commit
77a29a8c4d
17 changed files with 1549 additions and 159 deletions
|
|
@ -53,3 +53,12 @@ config WIL6210_DEBUGFS
|
|||
option if you are interested in debugging the driver.
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config WIL6210_IPA
|
||||
bool "wil6210 IPA offload support"
|
||||
depends on WIL6210
|
||||
depends on ARCH_QCOM
|
||||
default y
|
||||
help
|
||||
Say Y here to enable wil6210 driver support for data path
|
||||
IPA offload
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ wil6210-y += ethtool.o
|
|||
wil6210-y += wil_crash_dump.o
|
||||
wil6210-y += p2p.o
|
||||
wil6210-y += ftm.o
|
||||
wil6210-$(CONFIG_WIL6210_IPA) += ipa.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "wmi.h"
|
||||
#include "ftm.h"
|
||||
#include "fw.h"
|
||||
#include "ipa.h"
|
||||
|
||||
#define WIL_MAX_ROC_DURATION_MS 5000
|
||||
#define WIL_BRD_SUFFIX_CN "CN"
|
||||
|
|
@ -139,6 +140,8 @@ enum wil_nl_60g_evt_type {
|
|||
|
||||
enum wil_nl_60g_debug_cmd {
|
||||
NL_60G_DBG_FORCE_WMI_SEND,
|
||||
NL_60G_GEN_RADAR_ALLOC_BUFFER,
|
||||
NL_60G_GEN_FW_RESET,
|
||||
};
|
||||
|
||||
struct wil_nl_60g_send_receive_wmi {
|
||||
|
|
@ -2159,7 +2162,22 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
|
||||
if (wil->ipa_handle) {
|
||||
wil_ipa_uninit(wil->ipa_handle);
|
||||
wil->ipa_handle = NULL;
|
||||
}
|
||||
|
||||
__wil_down(wil);
|
||||
|
||||
if (wil_ipa_offload()) {
|
||||
wil->ipa_handle = wil_ipa_init(wil);
|
||||
if (!wil->ipa_handle) {
|
||||
wil_err(wil, "wil_ipa_init failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = __wil_up(wil);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
|
@ -2182,6 +2200,12 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
memcpy(vif->ssid, ssid, ssid_len);
|
||||
vif->ssid_len = ssid_len;
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
rc = wil_ipa_start_ap(wil->ipa_handle);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
|
||||
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
|
||||
|
|
@ -2204,6 +2228,11 @@ err_pcp_start:
|
|||
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
|
||||
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
|
||||
out:
|
||||
if (rc && wil->ipa_handle) {
|
||||
wil_ipa_uninit(wil->ipa_handle);
|
||||
wil->ipa_handle = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -2394,6 +2423,10 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
|||
memset(vif->gtk, 0, WMI_MAX_KEY_LEN);
|
||||
vif->gtk_len = 0;
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
wil_ipa_uninit(wil->ipa_handle);
|
||||
wil->ipa_handle = NULL;
|
||||
}
|
||||
if (last)
|
||||
__wil_down(wil);
|
||||
else
|
||||
|
|
@ -3707,6 +3740,23 @@ static int wil_nl_60g_handle_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
wil_dbg_wmi(wil, "force sending wmi commands %d\n",
|
||||
wil->force_wmi_send);
|
||||
break;
|
||||
case NL_60G_GEN_FW_RESET:
|
||||
if (!test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
|
||||
wil->fw_capabilities)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"NL_60G_GEN_FW_RESET, resetting...\n");
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
down_write(&wil->mem_lock);
|
||||
rc = wil_reset(wil, true);
|
||||
up_write(&wil->mem_lock);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
wil_err(wil, "invalid debug_cmd id %d",
|
||||
|
|
|
|||
|
|
@ -1,18 +1,7 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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/interrupt.h>
|
||||
|
|
@ -44,7 +33,7 @@
|
|||
(~(BIT_DMA_EP_RX_ICR_RX_HTRSH)))
|
||||
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
|
||||
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
|
||||
#define WIL6210_IMC_TX_EDMA BIT_TX_STATUS_IRQ
|
||||
#define WIL6210_IMC_TX_EDMA (0xFFFFFFFFUL)
|
||||
#define WIL6210_IMC_RX_EDMA BIT_RX_STATUS_IRQ
|
||||
#define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \
|
||||
ISR_MISC_MBOX_EVT | \
|
||||
|
|
@ -226,6 +215,7 @@ void wil_unmask_irq(struct wil6210_priv *wil)
|
|||
void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
|
||||
{
|
||||
u32 moderation;
|
||||
int i, num_int_lines = 2 /* Rx + Tx status */;
|
||||
|
||||
wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC);
|
||||
|
||||
|
|
@ -234,8 +224,11 @@ void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
|
|||
/* Update RX and TX moderation */
|
||||
moderation = wil->rx_max_burst_duration |
|
||||
(WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS);
|
||||
wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation);
|
||||
wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation);
|
||||
if (wil->ipa_handle)
|
||||
/* additional int per client, for Tx desc ring */
|
||||
num_int_lines += max_assoc_sta;
|
||||
for (i = 0; i < num_int_lines; i++)
|
||||
wil_w(wil, i * 4 + RGF_INT_CTRL_INT_GEN_CFG, moderation);
|
||||
|
||||
/* Treat special events as regular
|
||||
* (set bit 0 to 0x1 and clear bits 1-8)
|
||||
|
|
@ -541,7 +534,7 @@ static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
|
|||
return true;
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr;
|
||||
|
|
@ -610,7 +603,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
|||
}
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
||||
irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr = wil->isr_misc;
|
||||
|
|
|
|||
982
drivers/net/wireless/ath/wil6210/ipa.c
Normal file
982
drivers/net/wireless/ath/wil6210/ipa.c
Normal file
|
|
@ -0,0 +1,982 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/ipa_wigig.h>
|
||||
#include <linux/iommu.h>
|
||||
#include "wil6210.h"
|
||||
#include "txrx_edma.h"
|
||||
#include "txrx.h"
|
||||
#include "ipa.h"
|
||||
|
||||
#define WIL_IPA_MSI_CAP (0x50)
|
||||
#define WIL_IPA_MSI_MSG_DATA 0xCAFE
|
||||
|
||||
#define WIL_IPA_BCAST_POLL_MS 20
|
||||
#define WIL_IPA_READY_TO_MS 2000
|
||||
|
||||
/* IPA requires power of 2 buffer size */
|
||||
#define WIL_IPA_RX_BUFF_SIZE (8 * 1024)
|
||||
#define WIL_IPA_TX_BUFF_SIZE (2 * 1024)
|
||||
|
||||
u8 ipa_offload;
|
||||
module_param(ipa_offload, byte, 0444);
|
||||
MODULE_PARM_DESC(ipa_offload, " Enable IPA offload, default - disabled");
|
||||
|
||||
/* template IP headers */
|
||||
static struct ethhdr wil_ipa_v4_hdr = {
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05, 0x07},
|
||||
0x0008
|
||||
};
|
||||
|
||||
static struct ethhdr wil_ipa_v6_hdr = {
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05, 0x08},
|
||||
{0x01, 0x02, 0x03, 0x04, 0x05, 0x09},
|
||||
0xDD86
|
||||
};
|
||||
|
||||
int wil_ipa_get_bcast_sring_id(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)wil->ipa_handle;
|
||||
|
||||
return ipa->bcast_sring_id;
|
||||
}
|
||||
|
||||
void wil_ipa_set_bcast_sring_id(struct wil6210_priv *wil, int bcast_sring_id)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)wil->ipa_handle;
|
||||
|
||||
ipa->bcast_sring_id = bcast_sring_id;
|
||||
}
|
||||
|
||||
static phys_addr_t wil_ipa_get_bar_base_pa(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
struct resource *res = &pdev->resource[0];
|
||||
|
||||
return res->start;
|
||||
}
|
||||
|
||||
static void
|
||||
wil_ipa_calc_head_tail(struct wil6210_priv *wil, int ring_id, int sring_id,
|
||||
phys_addr_t *desc_hwhead, phys_addr_t *desc_hwtail,
|
||||
phys_addr_t *status_hwhead, phys_addr_t *status_hwtail)
|
||||
{
|
||||
phys_addr_t bar_base_pa = wil_ipa_get_bar_base_pa(wil);
|
||||
|
||||
/* HWTAIL / HWHEAD calculation:
|
||||
* for descriptor rings:
|
||||
* 1. SW should update the SUBQ producer pointer by writing to
|
||||
* SUBQ_RD_PTR (table of 64 entries, one for each Q), to update the
|
||||
* HW that there are descriptors waiting
|
||||
* 2. SW should read the SUBQ_CONS information, in order to track the
|
||||
* used registers. SUBQ_CONS is a table of 32 entries, one for
|
||||
* each Q pair. lower 16bits are for even ring_id and upper 16bits
|
||||
* are for odd ring_id
|
||||
* for status rings:
|
||||
* 1. SW should read the COMPQ_PROD information
|
||||
* 2. SW should write the COMPQ_RD_PTR which is actually the completion
|
||||
* queue consumer pointer
|
||||
*/
|
||||
|
||||
*desc_hwhead = bar_base_pa +
|
||||
HOSTADDR(RGF_DMA_SCM_SUBQ_CONS + 4 * (ring_id / 2));
|
||||
*status_hwhead = bar_base_pa +
|
||||
HOSTADDR(RGF_DMA_SCM_COMPQ_PROD + 4 * (sring_id / 2));
|
||||
|
||||
*desc_hwtail = bar_base_pa +
|
||||
HOSTADDR(RGF_SCM_PTRS_SUBQ_RD_PTR + 4 * ring_id);
|
||||
*status_hwtail = bar_base_pa +
|
||||
HOSTADDR(RGF_SCM_PTRS_COMPQ_RD_PTR + 4 * sring_id);
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"desc_hwhead %pad desc_hwtail %pad status_hwhead %pad status_hwtail %pad\n",
|
||||
desc_hwhead, desc_hwtail, status_hwhead, status_hwtail);
|
||||
}
|
||||
|
||||
static void wil_ipa_rx(struct wil_ipa *ipa, struct sk_buff *skb)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
int cid, len = skb->len;
|
||||
u8 *sa = wil_skb_get_sa(skb);
|
||||
struct wil_net_stats *stats;
|
||||
|
||||
wil_dbg_txrx(wil, "ipa_rx %d bytes\n", len);
|
||||
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
if (unlikely(len < ETH_HLEN)) {
|
||||
wil_err(wil, "ipa rx packet too short %d\n", len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
cid = wil_find_cid(wil, vif->mid, sa);
|
||||
if (unlikely(cid < 0)) {
|
||||
wil_err_ratelimited(wil, "cid not found for sa %pM\n", sa);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
wil_netif_rx(skb, ndev, cid, stats, false);
|
||||
|
||||
return;
|
||||
|
||||
drop:
|
||||
dev_kfree_skb(skb);
|
||||
ndev->stats.rx_dropped++;
|
||||
}
|
||||
|
||||
static void wil_ipa_notify_cb(void *priv, enum ipa_dp_evt_type evt,
|
||||
unsigned long data)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)priv;
|
||||
struct sk_buff *skb;
|
||||
|
||||
switch (evt) {
|
||||
case IPA_RECEIVE:
|
||||
skb = (struct sk_buff *)data;
|
||||
wil_ipa_rx(ipa, skb);
|
||||
break;
|
||||
default:
|
||||
wil_dbg_misc(ipa->wil, "unhandled ipa evt %d\n", evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_conn_rx_pipe_smmu(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct ipa_wigig_conn_rx_in_params_smmu in = {
|
||||
.notify = wil_ipa_notify_cb,
|
||||
.priv = ipa,
|
||||
};
|
||||
struct ipa_wigig_conn_out_params out = {0};
|
||||
int rc;
|
||||
struct wil_ring *rx_ring = &wil->ring_rx;
|
||||
struct wil_status_ring *rx_sring = &wil->srings[wil->rx_sring_idx];
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.pipe_smmu.desc_ring_base,
|
||||
(void *)rx_ring->va, rx_ring->pa,
|
||||
rx_ring->size * sizeof(rx_ring->va[0]));
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "dma_get_sgtable for desc ring failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
in.pipe_smmu.desc_ring_base_iova = rx_ring->pa;
|
||||
in.pipe_smmu.desc_ring_size = rx_ring->size * sizeof(rx_ring->va[0]);
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.pipe_smmu.status_ring_base,
|
||||
rx_sring->va, rx_sring->pa,
|
||||
rx_sring->size * rx_sring->elem_size);
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "dma_get_sgtable for status ring failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
in.pipe_smmu.status_ring_base_iova = rx_sring->pa;
|
||||
in.pipe_smmu.status_ring_size = rx_sring->size * rx_sring->elem_size;
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.dbuff_smmu.data_buffer_base,
|
||||
ipa->rx_buf.va, ipa->rx_buf.pa, ipa->rx_buf.sz);
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "dma_get_sgtable for data buffer failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_ipa_calc_head_tail(wil, WIL_RX_DESC_RING_ID, wil->rx_sring_idx,
|
||||
&in.pipe_smmu.desc_ring_HWHEAD_pa,
|
||||
&in.pipe_smmu.desc_ring_HWTAIL_pa,
|
||||
&in.pipe_smmu.status_ring_HWHEAD_pa,
|
||||
&in.pipe_smmu.status_ring_HWTAIL_pa);
|
||||
|
||||
in.dbuff_smmu.data_buffer_base_iova = ipa->rx_buf.pa;
|
||||
in.dbuff_smmu.data_buffer_size = wil->rx_buf_len;
|
||||
|
||||
rc = ipa_wigig_conn_rx_pipe_smmu(&in, &out);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_conn_rx_pipe_smmu failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ipa->rx_client_type = out.client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_conn_rx_pipe(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct ipa_wigig_conn_rx_in_params in = {
|
||||
.notify = wil_ipa_notify_cb,
|
||||
.priv = ipa,
|
||||
};
|
||||
struct ipa_wigig_conn_out_params out = {0};
|
||||
int rc;
|
||||
struct wil_ring *rx_ring = &wil->ring_rx;
|
||||
struct wil_status_ring *rx_sring = &wil->srings[wil->rx_sring_idx];
|
||||
|
||||
in.pipe.desc_ring_base_pa = rx_ring->pa;
|
||||
in.pipe.desc_ring_size = rx_ring->size * sizeof(rx_ring->va[0]);
|
||||
in.pipe.status_ring_base_pa = rx_sring->pa;
|
||||
in.pipe.status_ring_size = rx_sring->size * rx_sring->elem_size;
|
||||
|
||||
wil_ipa_calc_head_tail(wil, WIL_RX_DESC_RING_ID, wil->rx_sring_idx,
|
||||
&in.pipe.desc_ring_HWHEAD_pa,
|
||||
&in.pipe.desc_ring_HWTAIL_pa,
|
||||
&in.pipe.status_ring_HWHEAD_pa,
|
||||
&in.pipe.status_ring_HWTAIL_pa);
|
||||
|
||||
in.dbuff.data_buffer_base_pa = ipa->rx_buf.pa;
|
||||
in.dbuff.data_buffer_size = wil->rx_buf_len;
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"calling ipa_wigig_conn_rx_pipe, desc_ring_base_pa %pad status_ring_base_pa %pad data_buffer_base_pa %pad\n",
|
||||
&in.pipe.desc_ring_base_pa, &in.pipe.status_ring_base_pa,
|
||||
&in.dbuff.data_buffer_base_pa);
|
||||
|
||||
rc = ipa_wigig_conn_rx_pipe(&in, &out);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_conn_rx_pipe failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ipa->rx_client_type = out.client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_reg_intf(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct ipa_wigig_reg_intf_in_params in = {
|
||||
.netdev_name = ndev->name,
|
||||
};
|
||||
int rc;
|
||||
|
||||
ether_addr_copy(in.netdev_mac, ndev->dev_addr);
|
||||
ether_addr_copy(wil_ipa_v4_hdr.h_source, ndev->dev_addr);
|
||||
ether_addr_copy(wil_ipa_v6_hdr.h_source, ndev->dev_addr);
|
||||
|
||||
in.hdr_info[IPA_IP_v4].hdr = (u8 *)&wil_ipa_v4_hdr;
|
||||
in.hdr_info[IPA_IP_v4].hdr_len = sizeof(wil_ipa_v4_hdr);
|
||||
in.hdr_info[IPA_IP_v4].dst_mac_addr_offset =
|
||||
offsetof(struct ethhdr, h_dest);
|
||||
in.hdr_info[IPA_IP_v4].hdr_type = IPA_HDR_L2_ETHERNET_II;
|
||||
in.hdr_info[IPA_IP_v6].hdr = (u8 *)&wil_ipa_v6_hdr;
|
||||
in.hdr_info[IPA_IP_v6].hdr_len = sizeof(wil_ipa_v6_hdr);
|
||||
in.hdr_info[IPA_IP_v6].dst_mac_addr_offset =
|
||||
offsetof(struct ethhdr, h_dest);
|
||||
in.hdr_info[IPA_IP_v6].hdr_type = IPA_HDR_L2_ETHERNET_II;
|
||||
|
||||
rc = ipa_wigig_reg_intf(&in);
|
||||
if (rc)
|
||||
wil_err(wil, "ipa_wigig_reg_intf failed %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_ipa_set_ring_buf(struct wil6210_priv *wil,
|
||||
struct wil_ring *ring, u32 i)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)wil->ipa_handle;
|
||||
size_t sz = wil->rx_buf_len;
|
||||
dma_addr_t pa;
|
||||
struct wil_rx_enhanced_desc dd, *d = ⅆ
|
||||
struct wil_rx_enhanced_desc *_d = (struct wil_rx_enhanced_desc *)
|
||||
&ring->va[i].rx.enhanced;
|
||||
|
||||
memset(&dd, 0, sizeof(dd));
|
||||
|
||||
pa = ipa->rx_buf.pa + i * sz;
|
||||
|
||||
wil_desc_set_addr_edma(&d->dma.addr, &d->dma.addr_high_high, pa);
|
||||
d->dma.length = cpu_to_le16(sz);
|
||||
d->mac.buff_id = cpu_to_le16(i);
|
||||
*_d = *d;
|
||||
}
|
||||
|
||||
static void wil_ipa_rx_refill(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ring->size; i++)
|
||||
wil_ipa_set_ring_buf(wil, ring, i);
|
||||
ring->swhead = ring->size - 1;
|
||||
|
||||
/* commit to HW */
|
||||
wil_w(wil, ring->hwtail, ring->swhead);
|
||||
}
|
||||
|
||||
static int wil_ipa_rx_alloc(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
u16 status_ring_size, desc_ring_size;
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
int rc, sring_id;
|
||||
size_t elem_size = sizeof(struct wil_rx_status_compressed);
|
||||
|
||||
/* in IPA offload must use compressed_rx_status and hw_reordering */
|
||||
if (!wil->use_compressed_rx_status || !wil->use_rx_hw_reordering) {
|
||||
wil_err(wil, "invalid config for IPA offload (compressed %d, hw_reorder %d)\n",
|
||||
wil->use_compressed_rx_status,
|
||||
wil->use_rx_hw_reordering);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wil->num_rx_status_rings != 1) {
|
||||
wil_err(wil, "invalid config for IPA offload (num_rx_status_rings %d)\n",
|
||||
wil->num_rx_status_rings);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* hard coded sizes for IPA offload */
|
||||
desc_ring_size = WIL_IPA_DESC_RING_SIZE;
|
||||
status_ring_size = WIL_IPA_STATUS_RING_SIZE;
|
||||
wil->rx_buf_len = WIL_IPA_RX_BUFF_SIZE;
|
||||
|
||||
wil_dbg_misc(wil,
|
||||
"rx_alloc, desc_ring_size=%u, status_ring_size=%u, elem_size=%zu\n",
|
||||
desc_ring_size, status_ring_size, elem_size);
|
||||
|
||||
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len, false);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Allocate status ring */
|
||||
sring_id = wil_find_free_sring(wil);
|
||||
if (sring_id < 0)
|
||||
return -EFAULT;
|
||||
wil->rx_sring_idx = sring_id;
|
||||
rc = wil_init_rx_sring(wil, status_ring_size, elem_size, sring_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Allocate descriptor ring */
|
||||
rc = wil_init_rx_desc_ring(wil, desc_ring_size, wil->rx_sring_idx);
|
||||
if (rc)
|
||||
goto err_free_status;
|
||||
|
||||
/* Allocate contiguous memory for Rx buffers, zero initialized */
|
||||
ipa->rx_buf.sz = desc_ring_size * wil->rx_buf_len;
|
||||
ipa->rx_buf.va =
|
||||
dma_alloc_attrs(dev, ipa->rx_buf.sz, &ipa->rx_buf.pa,
|
||||
GFP_KERNEL | __GFP_ZERO,
|
||||
DMA_ATTR_FORCE_CONTIGUOUS);
|
||||
if (!ipa->rx_buf.va) {
|
||||
rc = -ENOMEM;
|
||||
goto err_free_desc;
|
||||
}
|
||||
|
||||
/* Fill descriptor ring with credits */
|
||||
wil_ipa_rx_refill(wil);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_desc:
|
||||
wil_ring_free_edma(wil, ring);
|
||||
err_free_status:
|
||||
wil_sring_free(wil, &wil->srings[sring_id]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_ipa_rx_free(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = (struct wil6210_priv *)ipa->wil;
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
|
||||
wil_dbg_misc(wil, "ipa_rx_free\n");
|
||||
|
||||
wil_ring_free_edma(wil, ring);
|
||||
wil_sring_free(wil, &wil->srings[wil->rx_sring_idx]);
|
||||
|
||||
if (ipa->rx_buf.va) {
|
||||
dma_free_attrs(wil_to_dev(wil), ipa->rx_buf.sz,
|
||||
ipa->rx_buf.va, ipa->rx_buf.pa,
|
||||
DMA_ATTR_FORCE_CONTIGUOUS);
|
||||
ipa->rx_buf.va = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int wil_ipa_start_ap(void *ipa_handle)
|
||||
{
|
||||
struct wil_ipa *ipa = ipa_handle;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
struct msi_msg msi_msg = {0};
|
||||
int rc;
|
||||
u16 msi_data;
|
||||
|
||||
/* store original MSI info to be restored upon uninit */
|
||||
if (pci_read_config_dword(pdev, WIL_IPA_MSI_CAP + PCI_MSI_ADDRESS_LO,
|
||||
&ipa->orig_msi_msg.address_lo) ||
|
||||
pci_read_config_dword(pdev, WIL_IPA_MSI_CAP + PCI_MSI_ADDRESS_HI,
|
||||
&ipa->orig_msi_msg.address_hi) ||
|
||||
pci_read_config_word(pdev, WIL_IPA_MSI_CAP + PCI_MSI_DATA_64,
|
||||
&msi_data)) {
|
||||
wil_err(wil, "fail to read MSI address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ipa->orig_msi_msg.data = msi_data;
|
||||
|
||||
rc = wil_ipa_rx_alloc(ipa);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (ipa->smmu_enabled)
|
||||
rc = wil_ipa_wigig_conn_rx_pipe_smmu(ipa);
|
||||
else
|
||||
rc = wil_ipa_wigig_conn_rx_pipe(ipa);
|
||||
if (rc)
|
||||
goto rx_free;
|
||||
|
||||
rc = ipa_wigig_set_perf_profile(WIL_MAX_BUS_REQUEST_KBPS * 8 / 1024);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_set_perf_profile failed %d\n", rc);
|
||||
goto err_disconn;
|
||||
}
|
||||
|
||||
rc = ipa_wigig_enable_pipe(ipa->rx_client_type);
|
||||
if (rc)
|
||||
goto err_disconn;
|
||||
|
||||
rc = wil_ipa_wigig_reg_intf(ipa);
|
||||
if (rc)
|
||||
goto err_disable;
|
||||
|
||||
wil_info(wil, "ipa intf registered. client %d\n", ipa->rx_client_type);
|
||||
|
||||
/* route MSI to IPA uC */
|
||||
msi_msg.address_lo = lower_32_bits(ipa->uc_db_pa);
|
||||
msi_msg.address_hi = upper_32_bits(ipa->uc_db_pa);
|
||||
msi_msg.data = WIL_IPA_MSI_MSG_DATA;
|
||||
pci_write_msi_msg(pdev->irq, &msi_msg);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable:
|
||||
ipa_wigig_disable_pipe(ipa->rx_client_type);
|
||||
err_disconn:
|
||||
ipa_wigig_disconn_pipe(ipa->rx_client_type);
|
||||
ipa->rx_client_type = IPA_CLIENT_MAX;
|
||||
rx_free:
|
||||
wil_ipa_rx_free(ipa);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_conn_client_smmu(struct wil_ipa *ipa, int cid,
|
||||
int ring_id, int sring_id)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct ipa_wigig_conn_tx_in_params_smmu in = { { {0} } };
|
||||
struct ipa_wigig_conn_out_params out = {0};
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
struct wil_status_ring *sring = &wil->srings[sring_id];
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
struct wil_ipa_conn *ipa_conn = &ipa->conn[cid];
|
||||
int rc, i;
|
||||
size_t sz;
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.pipe_smmu.desc_ring_base,
|
||||
(void *)ring->va, ring->pa,
|
||||
ring->size * sizeof(ring->va[0]));
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "dma_get_sgtable for desc ring failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
in.pipe_smmu.desc_ring_base_iova = ring->pa;
|
||||
in.pipe_smmu.desc_ring_size = ring->size * sizeof(ring->va[0]);
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.pipe_smmu.status_ring_base,
|
||||
sring->va, sring->pa,
|
||||
sring->size * sring->elem_size);
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "dma_get_sgtable for status ring failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
in.pipe_smmu.status_ring_base_iova = sring->pa;
|
||||
in.pipe_smmu.status_ring_size = sring->size * sring->elem_size;
|
||||
|
||||
wil_ipa_calc_head_tail(wil, ring_id, sring_id,
|
||||
&in.pipe_smmu.desc_ring_HWHEAD_pa,
|
||||
&in.pipe_smmu.desc_ring_HWTAIL_pa,
|
||||
&in.pipe_smmu.status_ring_HWHEAD_pa,
|
||||
&in.pipe_smmu.status_ring_HWTAIL_pa);
|
||||
|
||||
sz = ring->size * sizeof(in.dbuff_smmu.data_buffer_base[0]);
|
||||
in.dbuff_smmu.data_buffer_base = kzalloc(sz, GFP_KERNEL);
|
||||
if (!in.dbuff_smmu.data_buffer_base)
|
||||
return -ENOMEM;
|
||||
sz = ring->size * sizeof(in.dbuff_smmu.data_buffer_base_iova[0]);
|
||||
in.dbuff_smmu.data_buffer_base_iova = kzalloc(sz, GFP_KERNEL);
|
||||
if (!in.dbuff_smmu.data_buffer_base_iova) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
in.dbuff_smmu.num_buffers = ring->size;
|
||||
for (i = 0; i < in.dbuff_smmu.num_buffers; i++) {
|
||||
struct wil_dma_map_info *tx_buf = &ipa_conn->tx_bufs_addr[i];
|
||||
|
||||
rc = dma_get_sgtable(dev, &in.dbuff_smmu.data_buffer_base[i],
|
||||
tx_buf->va, tx_buf->pa,
|
||||
WIL_IPA_TX_BUFF_SIZE);
|
||||
if (rc < 0) {
|
||||
wil_err(wil, "sgtable tx buf %d failed %d\n", i, rc);
|
||||
goto out;
|
||||
}
|
||||
in.dbuff_smmu.data_buffer_base_iova[i] = tx_buf->pa;
|
||||
}
|
||||
in.dbuff_smmu.data_buffer_size = WIL_IPA_TX_BUFF_SIZE;
|
||||
|
||||
in.int_gen_tx_bit_num = ring_id;
|
||||
ether_addr_copy(in.client_mac, sta->addr);
|
||||
|
||||
rc = ipa_wigig_conn_client_smmu(&in, &out);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_conn_client failed %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ipa->conn[cid].ipa_client = out.client;
|
||||
|
||||
out:
|
||||
kfree(in.dbuff_smmu.data_buffer_base);
|
||||
kfree(in.dbuff_smmu.data_buffer_base_iova);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_conn_client(struct wil_ipa *ipa, int cid, int ring_id,
|
||||
int sring_id)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct ipa_wigig_conn_tx_in_params in = { {0} };
|
||||
struct ipa_wigig_conn_out_params out = {0};
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
struct wil_status_ring *sring = &wil->srings[sring_id];
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
int rc;
|
||||
|
||||
in.pipe.desc_ring_base_pa = ring->pa;
|
||||
in.pipe.desc_ring_size = ring->size * sizeof(ring->va[0]);
|
||||
in.pipe.status_ring_base_pa = sring->pa;
|
||||
in.pipe.status_ring_size = sring->size * sring->elem_size;
|
||||
|
||||
wil_ipa_calc_head_tail(wil, ring_id, sring_id,
|
||||
&in.pipe.desc_ring_HWHEAD_pa,
|
||||
&in.pipe.desc_ring_HWTAIL_pa,
|
||||
&in.pipe.status_ring_HWHEAD_pa,
|
||||
&in.pipe.status_ring_HWTAIL_pa);
|
||||
|
||||
in.dbuff.data_buffer_size = WIL_IPA_TX_BUFF_SIZE;
|
||||
|
||||
in.int_gen_tx_bit_num = ring_id;
|
||||
ether_addr_copy(in.client_mac, sta->addr);
|
||||
|
||||
rc = ipa_wigig_conn_client(&in, &out);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_conn_client failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ipa->conn[cid].ipa_client = out.client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wil_ipa_free_tx_bufs(struct wil_ipa *ipa, int cid)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wil_ipa_conn *conn = &ipa->conn[cid];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < conn->tx_bufs_count; i++) {
|
||||
struct wil_dma_map_info *tx_buf_addr = &conn->tx_bufs_addr[i];
|
||||
|
||||
if (tx_buf_addr->va)
|
||||
dma_free_coherent(dev, WIL_IPA_TX_BUFF_SIZE,
|
||||
tx_buf_addr->va, tx_buf_addr->pa);
|
||||
}
|
||||
|
||||
kfree(conn->tx_bufs_addr);
|
||||
conn->tx_bufs_addr = NULL;
|
||||
}
|
||||
|
||||
static int wil_ipa_alloc_tx_bufs(struct wil_ipa *ipa, int cid, int ring_id)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
struct wil_ipa_conn *conn = &ipa->conn[cid];
|
||||
size_t sz;
|
||||
int rc, i;
|
||||
|
||||
sz = ring->size * sizeof(conn->tx_bufs_addr[0]);
|
||||
conn->tx_bufs_addr = kzalloc(sz, GFP_KERNEL);
|
||||
if (!conn->tx_bufs_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
conn->tx_bufs_count = ring->size;
|
||||
for (i = 0; i < ring->size; i++) {
|
||||
struct wil_tx_enhanced_desc *d;
|
||||
|
||||
/* note: IPA requires Tx buffers to be 256B aligned */
|
||||
conn->tx_bufs_addr[i].va =
|
||||
dma_alloc_coherent(dev, WIL_IPA_TX_BUFF_SIZE,
|
||||
&conn->tx_bufs_addr[i].pa,
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!conn->tx_bufs_addr[i].va) {
|
||||
wil_err(wil, "tx buf DMA alloc error (i %d)\n", i);
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
d = (struct wil_tx_enhanced_desc *)&ring->va[i].tx.enhanced;
|
||||
wil_tx_desc_map_edma((union wil_tx_desc *)d,
|
||||
conn->tx_bufs_addr[i].pa,
|
||||
WIL_IPA_TX_BUFF_SIZE, ring_id);
|
||||
wil_tx_desc_set_nr_frags(&((union wil_tx_desc *)d)->legacy, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
wil_ipa_free_tx_bufs(ipa, cid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_ipa_conn_client(void *ipa_handle, int cid, int ring_id, int sring_id)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)ipa_handle;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct wil_ipa_conn *ipa_conn;
|
||||
int rc;
|
||||
|
||||
wil_info(wil, "ipa connect cid %d ring_id %d sring_id %d\n",
|
||||
cid, ring_id, sring_id);
|
||||
|
||||
rc = wil_ipa_alloc_tx_bufs(ipa, cid, ring_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (ipa->smmu_enabled)
|
||||
rc = wil_ipa_wigig_conn_client_smmu(ipa, cid, ring_id,
|
||||
sring_id);
|
||||
else
|
||||
rc = wil_ipa_wigig_conn_client(ipa, cid, ring_id, sring_id);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
|
||||
ipa_conn = &ipa->conn[cid];
|
||||
rc = ipa_wigig_enable_pipe(ipa_conn->ipa_client);
|
||||
if (rc)
|
||||
goto err_disconn;
|
||||
|
||||
wil_dbg_misc(wil, "ipa pipe enabled (client %d)\n",
|
||||
ipa_conn->ipa_client);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disconn:
|
||||
ipa_wigig_disconn_pipe(ipa_conn->ipa_client);
|
||||
ipa_conn->ipa_client = IPA_CLIENT_MAX;
|
||||
|
||||
err_free:
|
||||
wil_ipa_free_tx_bufs(ipa, cid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_ipa_start_bcast_timer(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
|
||||
if (timer_pending(&ipa->bcast_timer))
|
||||
return;
|
||||
|
||||
wil_dbg_txrx(wil, "ipa start bcast timer\n");
|
||||
|
||||
mod_timer(&ipa->bcast_timer,
|
||||
jiffies + msecs_to_jiffies(WIL_IPA_BCAST_POLL_MS));
|
||||
}
|
||||
|
||||
int wil_ipa_tx(void *ipa_handle, struct wil_ring *ring, struct sk_buff *skb)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)ipa_handle;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wil_ipa_conn *ipa_conn;
|
||||
struct wil_net_stats *stats;
|
||||
int cid, rc;
|
||||
const u8 *da;
|
||||
unsigned int len = skb->len;
|
||||
|
||||
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
da = wil_skb_get_da(skb);
|
||||
if (is_multicast_ether_addr(da)) {
|
||||
wil_ipa_start_bcast_timer(ipa);
|
||||
/* let wil_start_xmit() continue handling this (mcast) packet */
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
cid = wil_get_cid_by_ring(wil, ring);
|
||||
if (cid >= max_assoc_sta) {
|
||||
wil_dbg_txrx(wil, "ipa_tx invalid cid %d\n", cid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ipa_conn = &ipa->conn[cid];
|
||||
|
||||
rc = ipa_wigig_tx_dp(ipa_conn->ipa_client, skb);
|
||||
if (rc)
|
||||
return rc;
|
||||
/* skb could be freed after this point */
|
||||
|
||||
stats = &wil->sta[cid].stats;
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += len;
|
||||
ndev->stats.tx_packets++;
|
||||
ndev->stats.tx_bytes += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_ipa_disconn_client(void *ipa_handle, int cid)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)ipa_handle;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct wil_ipa_conn *ipa_conn = &ipa->conn[cid];
|
||||
|
||||
if (ipa_conn->ipa_client >= IPA_CLIENT_MAX)
|
||||
return;
|
||||
|
||||
wil_info(wil, "ipa disconnect cid %d (client %d)\n",
|
||||
cid, ipa_conn->ipa_client);
|
||||
|
||||
ipa_wigig_disable_pipe(ipa_conn->ipa_client);
|
||||
ipa_wigig_disconn_pipe(ipa_conn->ipa_client);
|
||||
wil_ipa_free_tx_bufs(ipa, cid);
|
||||
|
||||
ipa_conn->ipa_client = IPA_CLIENT_MAX;
|
||||
}
|
||||
|
||||
static void wil_ipa_uc_ready_cb(void *priv)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)priv;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
|
||||
wil_dbg_misc(wil, "got ipa uC ready cb\n");
|
||||
|
||||
complete(&ipa->ipa_uc_ready_comp);
|
||||
}
|
||||
|
||||
static void wil_ipa_wigig_misc_cb(void *priv)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)priv;
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
|
||||
wil_dbg_irq(wil, "got MISC callback from IPA\n");
|
||||
if (wil6210_irq_misc(0, wil) == IRQ_WAKE_THREAD)
|
||||
wil6210_irq_misc_thread(0, wil);
|
||||
}
|
||||
|
||||
static int wil_ipa_wigig_init(struct wil_ipa *ipa)
|
||||
{
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct ipa_wigig_init_in_params in = {0};
|
||||
struct ipa_wigig_init_out_params out = {0};
|
||||
phys_addr_t bar_base_pa = wil_ipa_get_bar_base_pa(wil);
|
||||
int rc;
|
||||
u8 wil_smmu_en;
|
||||
|
||||
ipa->domain = iommu_get_domain_for_dev(dev);
|
||||
if (!ipa->domain) {
|
||||
wil_err(wil, "iommu_get_domain failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
init_completion(&ipa->ipa_uc_ready_comp);
|
||||
in.periph_baddr_pa = bar_base_pa;
|
||||
in.pseudo_cause_pa = bar_base_pa + HOSTADDR(RGF_DMA_PSEUDO_CAUSE);
|
||||
in.int_gen_tx_pa = bar_base_pa + HOSTADDR(RGF_INT_GEN_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR);
|
||||
in.int_gen_rx_pa = bar_base_pa + HOSTADDR(RGF_INT_GEN_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR);
|
||||
in.dma_ep_misc_pa = bar_base_pa + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR);
|
||||
in.notify = wil_ipa_uc_ready_cb;
|
||||
in.int_notify = wil_ipa_wigig_misc_cb;
|
||||
in.priv = ipa;
|
||||
|
||||
rc = ipa_wigig_init(&in, &out);
|
||||
if (rc) {
|
||||
wil_err(wil, "ipa_wigig_init failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!out.is_uc_ready) {
|
||||
ulong to, left;
|
||||
|
||||
to = msecs_to_jiffies(WIL_IPA_READY_TO_MS);
|
||||
left = wait_for_completion_timeout(&ipa->ipa_uc_ready_comp, to);
|
||||
if (left == 0) {
|
||||
wil_err(wil, "IPA uC ready timeout\n");
|
||||
rc = -ETIME;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ipa->smmu_enabled = ipa_wigig_is_smmu_enabled();
|
||||
wil_smmu_en = test_bit(WIL_PLATFORM_CAPA_SMMU, wil->platform_capa);
|
||||
if (ipa->smmu_enabled != wil_smmu_en) {
|
||||
wil_err(wil, "smmu disagreement (ipa %d wil %d)\n",
|
||||
ipa->smmu_enabled, wil_smmu_en);
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
wil_info(wil, "IPA uC ready (early %d, uc_db_pa %pad, smmu %d)\n",
|
||||
out.is_uc_ready, &out.uc_db_pa, ipa->smmu_enabled);
|
||||
|
||||
if (ipa->smmu_enabled) {
|
||||
phys_addr_t pa;
|
||||
|
||||
pa = rounddown(out.uc_db_pa, PAGE_SIZE);
|
||||
rc = iommu_map(ipa->domain, pa, pa, PAGE_SIZE,
|
||||
IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO);
|
||||
if (rc) {
|
||||
wil_err(wil, "iommu_map failed %d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ipa->uc_db_pa = out.uc_db_pa;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (ipa->smmu_enabled && ipa->uc_db_pa) {
|
||||
iommu_unmap(ipa->domain, ipa->uc_db_pa, PAGE_SIZE);
|
||||
ipa->uc_db_pa = 0;
|
||||
}
|
||||
ipa_wigig_cleanup();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_ipa_bcast_fn(struct timer_list *t)
|
||||
{
|
||||
struct wil_ipa *ipa = from_timer(ipa, t, bcast_timer);
|
||||
struct wil6210_priv *wil = ipa->wil;
|
||||
|
||||
wil_dbg_txrx(wil, "NAPI(Tx bcast) schedule\n");
|
||||
napi_schedule(&wil->napi_tx);
|
||||
}
|
||||
|
||||
void *wil_ipa_init(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_ipa *ipa;
|
||||
int rc, i;
|
||||
|
||||
wil_dbg_misc(wil, "wil_ipa init\n");
|
||||
|
||||
if (wil->max_vifs > 1) {
|
||||
wil_err(wil, "IPA offload not supported with multi-VIF\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_IPA, wil->fw_capabilities)) {
|
||||
wil_err(wil, "IPA offload not supported by FW\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ipa = kzalloc(sizeof(*ipa), GFP_KERNEL);
|
||||
if (!ipa)
|
||||
return NULL;
|
||||
|
||||
ipa->wil = wil;
|
||||
ipa->bcast_sring_id = WIL6210_MAX_STATUS_RINGS;
|
||||
ipa->rx_client_type = IPA_CLIENT_MAX;
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++)
|
||||
ipa->conn[i].ipa_client = IPA_CLIENT_MAX;
|
||||
|
||||
timer_setup(&ipa->bcast_timer, wil_ipa_bcast_fn, 0);
|
||||
|
||||
rc = wil_ipa_wigig_init(ipa);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
return ipa;
|
||||
|
||||
err:
|
||||
kfree(ipa);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wil_ipa_uninit(void *ipa_handle)
|
||||
{
|
||||
struct wil_ipa *ipa = (struct wil_ipa *)ipa_handle;
|
||||
struct wil6210_priv *wil;
|
||||
struct device *dev;
|
||||
int i;
|
||||
|
||||
if (!ipa_handle)
|
||||
return;
|
||||
|
||||
wil = ipa->wil;
|
||||
dev = wil_to_dev(wil);
|
||||
wil_info(ipa->wil, "wil_ipa uninit\n");
|
||||
|
||||
del_timer_sync(&ipa->bcast_timer);
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++) {
|
||||
struct wil_ipa_conn *conn = &ipa->conn[i];
|
||||
|
||||
if (conn->ipa_client < IPA_CLIENT_MAX) {
|
||||
ipa_wigig_disable_pipe(conn->ipa_client);
|
||||
ipa_wigig_disconn_pipe(conn->ipa_client);
|
||||
|
||||
wil_ipa_free_tx_bufs(ipa, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (ipa->rx_client_type < IPA_CLIENT_MAX) {
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
|
||||
ipa_wigig_dereg_intf(ndev->name);
|
||||
ipa_wigig_disable_pipe(ipa->rx_client_type);
|
||||
ipa_wigig_disconn_pipe(ipa->rx_client_type);
|
||||
pci_write_msi_msg(pdev->irq, &ipa->orig_msi_msg);
|
||||
|
||||
wil_ipa_rx_free(ipa);
|
||||
}
|
||||
|
||||
if (ipa->smmu_enabled && ipa->uc_db_pa)
|
||||
iommu_unmap(ipa->domain, ipa->uc_db_pa, PAGE_SIZE);
|
||||
|
||||
ipa_wigig_cleanup();
|
||||
kfree(ipa_handle);
|
||||
}
|
||||
90
drivers/net/wireless/ath/wil6210/ipa.h
Normal file
90
drivers/net/wireless/ath/wil6210/ipa.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (c) 2019, The Linux Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef WIL6210_IPA_H
|
||||
#define WIL6210_IPA_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#ifdef CONFIG_WIL6210_IPA
|
||||
#include <linux/msi.h>
|
||||
#include <linux/msm_ipa.h>
|
||||
extern u8 ipa_offload;
|
||||
#endif
|
||||
|
||||
#define WIL_IPA_BCAST_DESC_RING_SIZE 512
|
||||
#define WIL_IPA_BCAST_SRING_SIZE (2 * WIL_IPA_BCAST_DESC_RING_SIZE)
|
||||
|
||||
#define WIL_IPA_DESC_RING_SIZE 2000
|
||||
#define WIL_IPA_STATUS_RING_SIZE 2048
|
||||
|
||||
#define WIL_IPA_MAX_ASSOC_STA 4
|
||||
|
||||
#ifdef CONFIG_WIL6210_IPA
|
||||
|
||||
struct wil_dma_map_info {
|
||||
void *va;
|
||||
phys_addr_t pa;
|
||||
};
|
||||
|
||||
struct wil_ipa_conn {
|
||||
enum ipa_client_type ipa_client;
|
||||
struct wil_dma_map_info *tx_bufs_addr;
|
||||
int tx_bufs_count;
|
||||
};
|
||||
|
||||
struct wil_ipa_rx_buf {
|
||||
dma_addr_t pa;
|
||||
void *va;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
struct wil_ipa {
|
||||
struct wil6210_priv *wil;
|
||||
struct iommu_domain *domain;
|
||||
struct timer_list bcast_timer;
|
||||
int bcast_sring_id;
|
||||
struct completion ipa_uc_ready_comp;
|
||||
u8 smmu_enabled;
|
||||
enum ipa_client_type rx_client_type;
|
||||
phys_addr_t uc_db_pa;
|
||||
struct wil_ipa_conn conn[WIL6210_MAX_CID];
|
||||
struct wil_ipa_rx_buf rx_buf; /* contiguous memory split into rx bufs */
|
||||
struct msi_msg orig_msi_msg;
|
||||
};
|
||||
|
||||
static inline bool wil_ipa_offload(void) {return ipa_offload; }
|
||||
void *wil_ipa_init(struct wil6210_priv *wil);
|
||||
void wil_ipa_uninit(void *ipa_handle);
|
||||
int wil_ipa_start_ap(void *ipa_handle);
|
||||
int wil_ipa_conn_client(void *ipa_handle, int cid, int ring_id, int sring_id);
|
||||
void wil_ipa_disconn_client(void *ipa_handle, int cid);
|
||||
int wil_ipa_get_bcast_sring_id(struct wil6210_priv *wil);
|
||||
void wil_ipa_set_bcast_sring_id(struct wil6210_priv *wil, int bcast_sring_id);
|
||||
int wil_ipa_tx(void *ipa_handle, struct wil_ring *ring, struct sk_buff *skb);
|
||||
|
||||
#else /* CONFIG_WIL6210_IPA */
|
||||
|
||||
static inline bool wil_ipa_offload(void) {return false; }
|
||||
static inline void *wil_ipa_init(struct wil6210_priv *wil) {return NULL; }
|
||||
static inline void wil_ipa_uninit(void *ipa_handle) {}
|
||||
static inline int wil_ipa_start_ap(void *ipa_handle) {return -EOPNOTSUPP; }
|
||||
static inline int wil_ipa_conn_client(void *ipa_handle,
|
||||
int cid, int ring_id,
|
||||
int sring_id) {return -EOPNOTSUPP; }
|
||||
static inline void wil_ipa_disconn_client(void *ipa_handle, int cid) {}
|
||||
static inline int wil_ipa_get_bcast_sring_id(struct wil6210_priv *wil)
|
||||
{
|
||||
return WIL6210_MAX_STATUS_RINGS;
|
||||
}
|
||||
|
||||
static inline void wil_ipa_set_bcast_sring_id(struct wil6210_priv *wil,
|
||||
int bcast_sring_id) {}
|
||||
static inline int wil_ipa_tx(void *ipa_handle,
|
||||
struct wil_ring *ring,
|
||||
struct sk_buff *skb) {return -EOPNOTSUPP; }
|
||||
|
||||
#endif /* CONFIG_WIL6210_IPA */
|
||||
|
||||
#endif /* WIL6210_IPA_H */
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include "txrx_edma.h"
|
||||
#include "wmi.h"
|
||||
#include "boot_loader.h"
|
||||
#include "ipa.h"
|
||||
|
||||
#define WAIT_FOR_HALP_VOTE_MS 100
|
||||
#define WAIT_FOR_SCAN_ABORT_MS 1000
|
||||
|
|
@ -294,6 +295,10 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
if (wil->ring2cid_tid[i][0] == cid)
|
||||
wil_ring_fini_tx(wil, i);
|
||||
}
|
||||
|
||||
if (wil->ipa_handle)
|
||||
wil_ipa_disconn_client(wil->ipa_handle, cid);
|
||||
|
||||
/* statistics */
|
||||
memset(&sta->stats, 0, sizeof(sta->stats));
|
||||
sta->stats.tx_latency_min_us = U32_MAX;
|
||||
|
|
@ -524,22 +529,16 @@ bool wil_is_recovery_blocked(struct wil6210_priv *wil)
|
|||
return no_fw_recovery && (wil->recovery_state == fw_recovery_pending);
|
||||
}
|
||||
|
||||
static void wil_fw_error_worker(struct work_struct *work)
|
||||
void wil_fw_recovery(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
fw_error_worker);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
wil_dbg_misc(wil, "fw error worker\n");
|
||||
wil_dbg_misc(wil, "fw recovery\n");
|
||||
|
||||
if (!ndev || !(ndev->flags & IFF_UP)) {
|
||||
wil_info(wil, "No recovery - interface is down\n");
|
||||
return;
|
||||
}
|
||||
wdev = ndev->ieee80211_ptr;
|
||||
|
||||
/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
|
||||
/* increment @recovery_count if less than WIL6210_FW_RECOVERY_TO
|
||||
* passed since last recovery attempt
|
||||
*/
|
||||
if (time_is_after_jiffies(wil->last_fw_recovery +
|
||||
|
|
@ -582,6 +581,10 @@ static void wil_fw_error_worker(struct work_struct *work)
|
|||
if (no_fw_recovery) /* upper layers do recovery */
|
||||
break;
|
||||
/* silent recovery, upper layers will see disconnect */
|
||||
if (wil->ipa_handle) {
|
||||
wil_ipa_uninit(wil->ipa_handle);
|
||||
wil->ipa_handle = NULL;
|
||||
}
|
||||
__wil_down(wil);
|
||||
__wil_up(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
|
@ -599,6 +602,22 @@ static void wil_fw_error_worker(struct work_struct *work)
|
|||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void wil_fw_error_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
fw_error_worker);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
wil_dbg_misc(wil, "fw error worker\n");
|
||||
|
||||
if (!ndev || !(ndev->flags & IFF_UP)) {
|
||||
wil_info(wil, "No recovery - interface is down\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wil_fw_recovery(wil);
|
||||
}
|
||||
|
||||
static int wil_find_free_ring(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -614,7 +633,7 @@ static int wil_find_free_ring(struct wil6210_priv *wil)
|
|||
int wil_ring_init_tx(struct wil6210_vif *vif, int cid)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc = -EINVAL, ringid;
|
||||
int rc = -EINVAL, ringid, ring_size;
|
||||
|
||||
if (cid < 0) {
|
||||
wil_err(wil, "No connection pending\n");
|
||||
|
|
@ -629,7 +648,9 @@ int wil_ring_init_tx(struct wil6210_vif *vif, int cid)
|
|||
wil_dbg_wmi(wil, "Configure for connection CID %d MID %d ring %d\n",
|
||||
cid, vif->mid, ringid);
|
||||
|
||||
rc = wil->txrx_ops.ring_init_tx(vif, ringid, 1 << tx_ring_order,
|
||||
ring_size = wil->ipa_handle ?
|
||||
WIL_IPA_DESC_RING_SIZE : 1 << tx_ring_order;
|
||||
rc = wil->txrx_ops.ring_init_tx(vif, ringid, ring_size,
|
||||
cid, 0);
|
||||
if (rc)
|
||||
wil_err(wil, "init TX for CID %d MID %d vring %d failed\n",
|
||||
|
|
@ -711,6 +732,8 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
|
||||
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
||||
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
|
||||
INIT_WORK(&wil->pci_linkdown_recovery_worker,
|
||||
wil_pci_linkdown_recovery_worker);
|
||||
|
||||
INIT_LIST_HEAD(&wil->pending_wmi_ev);
|
||||
spin_lock_init(&wil->wmi_ev_lock);
|
||||
|
|
@ -829,6 +852,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
|
|||
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
cancel_work_sync(&wil->fw_error_worker);
|
||||
cancel_work_sync(&wil->pci_linkdown_recovery_worker);
|
||||
wmi_event_flush(wil);
|
||||
destroy_workqueue(wil->wq_service);
|
||||
destroy_workqueue(wil->wmi_wq);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
#include "ipa.h"
|
||||
|
||||
static bool alt_ifname; /* = false; */
|
||||
module_param(alt_ifname, bool, 0444);
|
||||
|
|
@ -178,16 +179,27 @@ static int wil6210_netdev_poll_tx_edma(struct napi_struct *napi, int budget)
|
|||
napi_tx);
|
||||
int tx_done;
|
||||
/* There is only one status TX ring */
|
||||
struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx];
|
||||
struct wil_status_ring *sring;
|
||||
int sring_idx = wil->ipa_handle ?
|
||||
wil_ipa_get_bcast_sring_id(wil) : wil->tx_sring_idx;
|
||||
|
||||
if (!sring->va)
|
||||
if (sring_idx >= WIL6210_MAX_STATUS_RINGS) {
|
||||
napi_complete(napi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sring = &wil->srings[sring_idx];
|
||||
if (!sring->va) {
|
||||
napi_complete(napi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx_done = wil_tx_sring_handler(wil, sring);
|
||||
|
||||
if (tx_done < budget) {
|
||||
napi_complete(napi);
|
||||
wil6210_unmask_irq_tx_edma(wil);
|
||||
if (!wil->ipa_handle)
|
||||
wil6210_unmask_irq_tx_edma(wil);
|
||||
wil_dbg_txrx(wil, "NAPI TX complete\n");
|
||||
}
|
||||
|
||||
|
|
@ -346,6 +358,9 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name,
|
|||
ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
|
||||
NETIF_F_SG | NETIF_F_GRO |
|
||||
NETIF_F_TSO | NETIF_F_TSO6;
|
||||
if (wil_ipa_offload())
|
||||
ndev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_TSO |
|
||||
NETIF_F_TSO6);
|
||||
|
||||
ndev->features |= ndev->hw_features;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||
|
|
@ -559,6 +574,8 @@ void wil_if_remove(struct wil6210_priv *wil)
|
|||
wil_vif_remove(wil, 0);
|
||||
rtnl_unlock();
|
||||
|
||||
wil_ipa_uninit(wil->ipa_handle);
|
||||
wil->ipa_handle = NULL;
|
||||
netif_napi_del(&wil->napi_tx);
|
||||
netif_napi_del(&wil->napi_rx);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "wil6210.h"
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "ipa.h"
|
||||
|
||||
static int n_msi = 3;
|
||||
module_param(n_msi, int, 0444);
|
||||
|
|
@ -98,6 +99,9 @@ int wil_set_capabilities(struct wil6210_priv *wil)
|
|||
wil->use_enhanced_dma_hw = true;
|
||||
wil->use_rx_hw_reordering = true;
|
||||
wil->use_compressed_rx_status = true;
|
||||
if (wil_ipa_offload())
|
||||
/* IPA offload must use single MSI */
|
||||
n_msi = 1;
|
||||
wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
|
||||
WIL_FW_NAME_TALYN;
|
||||
if (wil_fw_verify_file_exists(wil, wil_fw_name))
|
||||
|
|
@ -218,6 +222,11 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|||
|
||||
wil->n_msi = n_msi;
|
||||
|
||||
if (wil->n_msi == 0 && wil_ipa_offload()) {
|
||||
wil_err(wil, "IPA offload cannot use INTx\n");
|
||||
rc = -ENODEV;
|
||||
goto stop_master;
|
||||
}
|
||||
if (wil->n_msi == 0 && msi_only) {
|
||||
wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
|
||||
rc = -ENODEV;
|
||||
|
|
@ -285,6 +294,108 @@ static int wil_platform_rop_fw_recovery(void *wil_handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void wil_pci_linkdown_recovery_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
pci_linkdown_recovery_worker);
|
||||
int rc, i;
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
wil_dbg_misc(wil, "starting pci_linkdown recovery\n");
|
||||
|
||||
rtnl_lock();
|
||||
mutex_lock(&wil->mutex);
|
||||
down_write(&wil->mem_lock);
|
||||
clear_bit(wil_status_fwready, wil->status);
|
||||
set_bit(wil_status_pci_linkdown, wil->status);
|
||||
set_bit(wil_status_resetting, wil->status);
|
||||
up_write(&wil->mem_lock);
|
||||
|
||||
if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
|
||||
napi_disable(&wil->napi_rx);
|
||||
napi_disable(&wil->napi_tx);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
rtnl_unlock();
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
wil_ftm_stop_operations(wil);
|
||||
wil_p2p_stop_radio_operations(wil);
|
||||
wil_abort_scan_all_vifs(wil, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (vif) {
|
||||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil6210_disconnect(vif, NULL,
|
||||
WLAN_REASON_DEAUTH_LEAVING);
|
||||
}
|
||||
}
|
||||
|
||||
wmi_event_flush(wil);
|
||||
flush_workqueue(wil->wq_service);
|
||||
flush_workqueue(wil->wmi_wq);
|
||||
|
||||
/* Recover PCIe */
|
||||
if (wil->platform_ops.pci_linkdown_recovery) {
|
||||
rc =
|
||||
wil->platform_ops.pci_linkdown_recovery(wil->platform_handle);
|
||||
if (rc) {
|
||||
wil_err(wil,
|
||||
"platform device failed to recover from pci linkdown (%d)\n",
|
||||
rc);
|
||||
mutex_unlock(&wil->mutex);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
wil_err(wil,
|
||||
"platform device doesn't support pci_linkdown recovery\n");
|
||||
mutex_unlock(&wil->mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ndev || !(ndev->flags & IFF_UP)) {
|
||||
wil_reset(wil, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
} else {
|
||||
mutex_unlock(&wil->mutex);
|
||||
wil->recovery_state = fw_recovery_pending;
|
||||
wil_fw_recovery(wil);
|
||||
}
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static int wil_platform_rop_notify(void *wil_handle,
|
||||
enum wil_platform_notif notif)
|
||||
{
|
||||
struct wil6210_priv *wil = wil_handle;
|
||||
|
||||
if (!wil)
|
||||
return -EINVAL;
|
||||
|
||||
switch (notif) {
|
||||
case WIL_PLATFORM_NOTIF_PCI_LINKDOWN:
|
||||
wil_info(wil, "received WIL_PLATFORM_NOTIF_PCI_LINKDOWN\n");
|
||||
clear_bit(wil_status_fwready, wil->status);
|
||||
set_bit(wil_status_resetting, wil->status);
|
||||
set_bit(wil_status_pci_linkdown, wil->status);
|
||||
|
||||
schedule_work(&wil->pci_linkdown_recovery_worker);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wil_platform_ops_uninit(struct wil6210_priv *wil)
|
||||
{
|
||||
if (wil->platform_ops.uninit)
|
||||
|
|
@ -300,6 +411,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
const struct wil_platform_rops rops = {
|
||||
.ramdump = wil_platform_rop_ramdump,
|
||||
.fw_recovery = wil_platform_rop_fw_recovery,
|
||||
.notify = wil_platform_rop_notify,
|
||||
};
|
||||
u32 bar_size = pci_resource_len(pdev, 0);
|
||||
int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */
|
||||
|
|
@ -537,6 +649,11 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
|
|||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
bool keep_radio_on, active_ifaces;
|
||||
|
||||
if (test_bit(wil_status_pci_linkdown, wil->status)) {
|
||||
wil_dbg_pm(wil, "ignore resume during pci linkdown\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,7 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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 "wil6210.h"
|
||||
|
|
@ -101,6 +90,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(wil_status_pci_linkdown, wil->status)) {
|
||||
wil_dbg_pm(wil, "Delay suspend during pci linkdown\n");
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "txrx.h"
|
||||
#include "trace.h"
|
||||
#include "txrx_edma.h"
|
||||
#include "ipa.h"
|
||||
|
||||
bool rx_align_2;
|
||||
module_param(rx_align_2, bool, 0444);
|
||||
|
|
@ -1636,12 +1637,6 @@ found:
|
|||
return v;
|
||||
}
|
||||
|
||||
static inline
|
||||
void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
|
||||
{
|
||||
d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the descriptor @d up for csum and/or TSO offloading. The corresponding
|
||||
* @skb is used to obtain the protocol and headers length.
|
||||
|
|
@ -2229,6 +2224,19 @@ static int wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_get_cid_by_ring(struct wil6210_priv *wil, struct wil_ring *ring)
|
||||
{
|
||||
int ring_index = ring - wil->ring_tx;
|
||||
|
||||
if (unlikely(ring_index < 0 || ring_index >= WIL6210_MAX_TX_RINGS)) {
|
||||
wil_err(wil, "cid by ring 0x%pK: invalid ring index %d\n",
|
||||
ring, ring_index);
|
||||
return max_assoc_sta;
|
||||
}
|
||||
|
||||
return wil->ring2cid_tid[ring_index][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check status of tx vrings and stop/wake net queues if needed
|
||||
* It will start/stop net queues of a specific VIF net_device.
|
||||
|
|
@ -2383,6 +2391,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
wil_dbg_txrx(wil, "No Tx RING found for %pM\n", da);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
rc = wil_ipa_tx(wil->ipa_handle, ring, skb);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
return NETDEV_TX_OK;
|
||||
case -EPROTONOSUPPORT:
|
||||
break;
|
||||
default:
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* set up vring entry */
|
||||
rc = wil_tx_ring(wil, vif, ring, skb);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,7 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WIL6210_TXRX_H
|
||||
|
|
@ -685,6 +674,12 @@ static inline void wil_skb_set_cid(struct sk_buff *skb, u8 cid)
|
|||
skb_rx_info->rx_info.cid = cid;
|
||||
}
|
||||
|
||||
static inline
|
||||
void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
|
||||
{
|
||||
d->mac.d[2] |= (nr_frags << MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
|
||||
}
|
||||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid,
|
||||
struct wil_net_stats *stats, bool gro);
|
||||
|
|
@ -699,5 +694,6 @@ void wil_tx_data_init(struct wil_ring_tx_data *txdata);
|
|||
void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil);
|
||||
void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
|
||||
struct wil_sta_info *sta);
|
||||
int wil_get_cid_by_ring(struct wil6210_priv *wil, struct wil_ring *ring);
|
||||
|
||||
#endif /* WIL6210_TXRX_H */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "txrx_edma.h"
|
||||
#include "txrx.h"
|
||||
#include "trace.h"
|
||||
#include "ipa.h"
|
||||
|
||||
/* Max number of entries (packets to complete) to update the hwtail of tx
|
||||
* status ring. Should be power of 2
|
||||
|
|
@ -44,7 +45,7 @@ static void wil_tx_desc_unmap_edma(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int wil_find_free_sring(struct wil6210_priv *wil)
|
||||
int wil_find_free_sring(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -56,8 +57,7 @@ static int wil_find_free_sring(struct wil6210_priv *wil)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void wil_sring_free(struct wil6210_priv *wil,
|
||||
struct wil_status_ring *sring)
|
||||
void wil_sring_free(struct wil6210_priv *wil, struct wil_status_ring *sring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
size_t sz;
|
||||
|
|
@ -103,47 +103,63 @@ static int wil_sring_alloc(struct wil6210_priv *wil,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wil_init_tx_sring(struct wil6210_priv *wil, u16 status_ring_size,
|
||||
size_t elem_size, u16 sring_id)
|
||||
{
|
||||
struct wil_status_ring *sring = &wil->srings[sring_id];
|
||||
int rc;
|
||||
u8 irq_mode = WMI_RING_ADD_IRQ_MODE_ENABLE;
|
||||
|
||||
wil_dbg_misc(wil, "init TX sring: size=%u, sring_id=%u\n",
|
||||
status_ring_size, sring_id);
|
||||
|
||||
sring->is_rx = false;
|
||||
sring->size = status_ring_size;
|
||||
sring->elem_size = elem_size;
|
||||
rc = wil_sring_alloc(wil, sring);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* in IPA mode, use interrupts from desc ring instead of sring */
|
||||
if (wil->ipa_handle)
|
||||
irq_mode = WMI_RING_ADD_IRQ_MODE_DISABLE;
|
||||
|
||||
rc = wil_wmi_tx_sring_cfg(wil, sring_id, irq_mode);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
sring->desc_rdy_pol = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
wil_sring_free(wil, sring);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_tx_init_edma(struct wil6210_priv *wil)
|
||||
{
|
||||
int ring_id = wil_find_free_sring(wil);
|
||||
struct wil_status_ring *sring;
|
||||
int rc;
|
||||
u16 status_ring_size;
|
||||
int sring_id = wil_find_free_sring(wil), rc;
|
||||
u16 sring_size;
|
||||
|
||||
if (sring_id < 0)
|
||||
return sring_id;
|
||||
|
||||
if (wil->tx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN ||
|
||||
wil->tx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX)
|
||||
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
|
||||
|
||||
status_ring_size = 1 << wil->tx_status_ring_order;
|
||||
|
||||
wil_dbg_misc(wil, "init TX sring: size=%u, ring_id=%u\n",
|
||||
status_ring_size, ring_id);
|
||||
|
||||
if (ring_id < 0)
|
||||
return ring_id;
|
||||
sring_size = wil_ipa_offload() ?
|
||||
WIL_IPA_STATUS_RING_SIZE : 1 << wil->tx_status_ring_order;
|
||||
|
||||
/* Allocate Tx status ring. Tx descriptor rings will be
|
||||
* allocated on WMI connect event
|
||||
*/
|
||||
sring = &wil->srings[ring_id];
|
||||
rc = wil_init_tx_sring(wil, sring_size,
|
||||
sizeof(struct wil_ring_tx_status), sring_id);
|
||||
if (!rc)
|
||||
wil->tx_sring_idx = sring_id;
|
||||
|
||||
sring->is_rx = false;
|
||||
sring->size = status_ring_size;
|
||||
sring->elem_size = sizeof(struct wil_ring_tx_status);
|
||||
rc = wil_sring_alloc(wil, sring);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = wil_wmi_tx_sring_cfg(wil, ring_id);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
sring->desc_rdy_pol = 1;
|
||||
wil->tx_sring_idx = ring_id;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
wil_sring_free(wil, sring);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -341,10 +357,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wil_init_rx_sring(struct wil6210_priv *wil,
|
||||
u16 status_ring_size,
|
||||
size_t elem_size,
|
||||
u16 ring_id)
|
||||
int wil_init_rx_sring(struct wil6210_priv *wil, u16 status_ring_size,
|
||||
size_t elem_size, u16 ring_id)
|
||||
{
|
||||
struct wil_status_ring *sring = &wil->srings[ring_id];
|
||||
int rc;
|
||||
|
|
@ -374,7 +388,8 @@ out_free:
|
|||
}
|
||||
|
||||
static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil,
|
||||
struct wil_ring *ring)
|
||||
struct wil_ring *ring,
|
||||
bool alloc_ctx)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
size_t sz = ring->size * sizeof(ring->va[0]);
|
||||
|
|
@ -385,9 +400,15 @@ static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil,
|
|||
|
||||
ring->swhead = 0;
|
||||
ring->swtail = 0;
|
||||
ring->ctx = kcalloc(ring->size, sizeof(ring->ctx[0]), GFP_KERNEL);
|
||||
if (!ring->ctx)
|
||||
goto err;
|
||||
|
||||
if (alloc_ctx) {
|
||||
ring->ctx = kcalloc(ring->size, sizeof(ring->ctx[0]),
|
||||
GFP_KERNEL);
|
||||
if (!ring->ctx)
|
||||
goto err;
|
||||
} else {
|
||||
ring->ctx = NULL;
|
||||
}
|
||||
|
||||
ring->va = dma_alloc_coherent(dev, sz, &ring->pa, GFP_KERNEL);
|
||||
if (!ring->va)
|
||||
|
|
@ -418,7 +439,7 @@ err:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring)
|
||||
void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
size_t sz;
|
||||
|
|
@ -472,6 +493,18 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring)
|
|||
ring->swtail = wil_ring_next_tail(ring);
|
||||
}
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
int bcast_sring_id = wil_ipa_get_bcast_sring_id(wil);
|
||||
|
||||
/* when freeing bcast desc ring, free the bcast status ring */
|
||||
if (wil->ring2cid_tid[ring_index][0] == WIL6210_MAX_CID &&
|
||||
bcast_sring_id < WIL6210_MAX_STATUS_RINGS) {
|
||||
wil_sring_free(wil, &wil->srings[bcast_sring_id]);
|
||||
wil_ipa_set_bcast_sring_id(wil,
|
||||
WIL6210_MAX_STATUS_RINGS);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
dma_free_coherent(dev, sz, (void *)ring->va, ring->pa);
|
||||
kfree(ring->ctx);
|
||||
|
|
@ -480,8 +513,8 @@ out:
|
|||
ring->ctx = NULL;
|
||||
}
|
||||
|
||||
static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
|
||||
int status_ring_id)
|
||||
int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
|
||||
int status_ring_id)
|
||||
{
|
||||
struct wil_ring *ring = &wil->ring_rx;
|
||||
int rc;
|
||||
|
|
@ -490,7 +523,7 @@ static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
|
|||
|
||||
ring->size = desc_ring_size;
|
||||
ring->is_rx = true;
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring);
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -611,6 +644,10 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
|
|||
sizeof(struct wil_rx_status_extended);
|
||||
int i;
|
||||
|
||||
if (wil->ipa_handle)
|
||||
/* in ipa offload, this is done as part of wil_ipa_start_ap */
|
||||
return 0;
|
||||
|
||||
/* In SW reorder one must use extended status messages */
|
||||
if (wil->use_compressed_rx_status && !wil->use_rx_hw_reordering) {
|
||||
wil_err(wil,
|
||||
|
|
@ -642,7 +679,7 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
|
|||
wil_dbg_misc(wil, "rx_init: allocate %d status rings\n",
|
||||
wil->num_rx_status_rings);
|
||||
|
||||
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len);
|
||||
rc = wil_wmi_cfg_def_rx_offload(wil, wil->rx_buf_len, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -658,11 +695,13 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order)
|
|||
sring_id);
|
||||
if (rc)
|
||||
goto err_free_status;
|
||||
|
||||
if (i == 0)
|
||||
wil->rx_sring_idx = sring_id;
|
||||
}
|
||||
|
||||
/* Allocate descriptor ring */
|
||||
rc = wil_init_rx_desc_ring(wil, desc_ring_size,
|
||||
WIL_DEFAULT_RX_STATUS_RING_ID);
|
||||
rc = wil_init_rx_desc_ring(wil, desc_ring_size, wil->rx_sring_idx);
|
||||
if (rc)
|
||||
goto err_free_status;
|
||||
|
||||
|
|
@ -703,6 +742,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
|
|||
int rc;
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
|
||||
u8 irq_mode = WMI_RING_ADD_IRQ_MODE_DISABLE;
|
||||
|
||||
lockdep_assert_held(&wil->mutex);
|
||||
|
||||
|
|
@ -712,7 +752,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
|
|||
|
||||
wil_tx_data_init(txdata);
|
||||
ring->size = size;
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring);
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring, true);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -721,12 +761,24 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
|
|||
if (!vif->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
|
||||
rc = wil_wmi_tx_desc_ring_add(vif, ring_id, cid, tid);
|
||||
/* in IPA mode, use interrupts from desc ring instead of sring */
|
||||
if (wil->ipa_handle)
|
||||
irq_mode = WMI_RING_ADD_IRQ_MODE_ENABLE;
|
||||
|
||||
rc = wil_wmi_tx_desc_ring_add(vif, ring_id, cid, tid, wil->tx_sring_idx,
|
||||
irq_mode);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
rc = wil_ipa_conn_client(wil->ipa_handle, cid, ring_id,
|
||||
wil->tx_sring_idx);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (txdata->dot1x_open && agg_wsize >= 0)
|
||||
wil_addba_tx_request(wil, ring_id, agg_wsize);
|
||||
|
||||
|
|
@ -1105,10 +1157,8 @@ void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota)
|
|||
wil_rx_refill_edma(wil);
|
||||
}
|
||||
|
||||
static int wil_tx_desc_map_edma(union wil_tx_desc *desc,
|
||||
dma_addr_t pa,
|
||||
u32 len,
|
||||
int ring_index)
|
||||
int wil_tx_desc_map_edma(union wil_tx_desc *desc, dma_addr_t pa, u32 len,
|
||||
int ring_index)
|
||||
{
|
||||
struct wil_tx_enhanced_desc *d =
|
||||
(struct wil_tx_enhanced_desc *)&desc->enhanced;
|
||||
|
|
@ -1540,18 +1590,32 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id,
|
|||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
int rc;
|
||||
int rc, sring_id = wil->tx_sring_idx;
|
||||
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
|
||||
|
||||
wil_dbg_misc(wil, "init bcast: ring_id=%d, sring_id=%d\n",
|
||||
ring_id, wil->tx_sring_idx);
|
||||
wil_dbg_misc(wil, "init bcast: ring_id=%d\n", ring_id);
|
||||
|
||||
lockdep_assert_held(&wil->mutex);
|
||||
|
||||
if (wil->ipa_handle) {
|
||||
/* alloc bcast status ring */
|
||||
sring_id = wil_find_free_sring(wil);
|
||||
if (sring_id < 0)
|
||||
return sring_id;
|
||||
|
||||
rc = wil_init_tx_sring(wil, WIL_IPA_BCAST_SRING_SIZE,
|
||||
sizeof(struct wil_ring_tx_status),
|
||||
sring_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
wil_ipa_set_bcast_sring_id(wil, sring_id);
|
||||
}
|
||||
|
||||
wil_tx_data_init(txdata);
|
||||
ring->size = size;
|
||||
ring->is_rx = false;
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring);
|
||||
rc = wil_ring_alloc_desc_ring(wil, ring, true);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1560,7 +1624,7 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id,
|
|||
if (!vif->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
|
||||
rc = wil_wmi_bcast_desc_ring_add(vif, ring_id);
|
||||
rc = wil_wmi_bcast_desc_ring_add(vif, ring_id, sring_id);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
|
|
@ -1574,16 +1638,28 @@ static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id,
|
|||
wil_ring_free_edma(wil, ring);
|
||||
|
||||
out:
|
||||
if (wil->ipa_handle) {
|
||||
wil_sring_free(wil, &wil->srings[sring_id]);
|
||||
wil_ipa_set_bcast_sring_id(wil, WIL6210_MAX_STATUS_RINGS);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_tx_fini_edma(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx];
|
||||
int i;
|
||||
|
||||
wil_dbg_misc(wil, "free TX sring\n");
|
||||
for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++) {
|
||||
struct wil_status_ring *sring = &wil->srings[i];
|
||||
|
||||
wil_sring_free(wil, sring);
|
||||
if (!sring->va || sring->is_rx)
|
||||
continue;
|
||||
|
||||
wil_dbg_misc(wil, "free TX sring %d\n", i);
|
||||
|
||||
wil_sring_free(wil, sring);
|
||||
}
|
||||
}
|
||||
|
||||
static void wil_rx_data_free(struct wil_status_ring *sring)
|
||||
|
|
@ -1600,6 +1676,10 @@ static void wil_rx_fini_edma(struct wil6210_priv *wil)
|
|||
struct wil_ring *ring = &wil->ring_rx;
|
||||
int i;
|
||||
|
||||
if (wil->ipa_handle)
|
||||
/* in ipa offload, this is done part of wil_ipa_uninit */
|
||||
return;
|
||||
|
||||
wil_dbg_misc(wil, "rx_fini_edma\n");
|
||||
|
||||
wil_ring_free_edma(wil, ring);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,6 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WIL6210_TXRX_EDMA_H
|
||||
|
|
@ -27,7 +16,6 @@
|
|||
#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (14)
|
||||
#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600)
|
||||
|
||||
#define WIL_DEFAULT_RX_STATUS_RING_ID 0
|
||||
#define WIL_RX_DESC_RING_ID 0
|
||||
#define WIL_RX_STATUS_IRQ_IDX 0
|
||||
#define WIL_TX_STATUS_IRQ_IDX 1
|
||||
|
|
@ -608,6 +596,15 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
|
|||
struct wil_status_ring *sring);
|
||||
void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota);
|
||||
void wil_init_txrx_ops_edma(struct wil6210_priv *wil);
|
||||
int wil_find_free_sring(struct wil6210_priv *wil);
|
||||
int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
|
||||
int status_ring_id);
|
||||
int wil_init_rx_sring(struct wil6210_priv *wil, u16 status_ring_size,
|
||||
size_t elem_size, u16 ring_id);
|
||||
void wil_sring_free(struct wil6210_priv *wil, struct wil_status_ring *sring);
|
||||
void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring);
|
||||
int wil_tx_desc_map_edma(union wil_tx_desc *desc, dma_addr_t pa, u32 len,
|
||||
int ring_index);
|
||||
|
||||
#endif /* WIL6210_TXRX_EDMA_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -336,8 +336,7 @@ struct RGF_ICR {
|
|||
|
||||
#define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8)
|
||||
|
||||
#define RGF_INT_CTRL_INT_GEN_CFG_0 (0x8bc000)
|
||||
#define RGF_INT_CTRL_INT_GEN_CFG_1 (0x8bc004)
|
||||
#define RGF_INT_CTRL_INT_GEN_CFG (0x8bc000)
|
||||
#define RGF_INT_GEN_TIME_UNIT_LIMIT (0x8bc0c8)
|
||||
|
||||
#define RGF_INT_GEN_CTRL (0x8bc0ec)
|
||||
|
|
@ -654,6 +653,7 @@ enum { /* for wil6210_priv.status */
|
|||
wil_status_suspending, /* suspend in progress */
|
||||
wil_status_suspended, /* suspend completed, device is suspended */
|
||||
wil_status_resuming, /* resume in progress */
|
||||
wil_status_pci_linkdown, /* pci linkdown occurred */
|
||||
wil_status_last /* keep last */
|
||||
};
|
||||
|
||||
|
|
@ -999,6 +999,7 @@ struct wil6210_priv {
|
|||
struct wil_status_ring srings[WIL6210_MAX_STATUS_RINGS];
|
||||
u8 num_rx_status_rings;
|
||||
int tx_sring_idx;
|
||||
int rx_sring_idx;
|
||||
u8 ring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
|
||||
struct wil_sta_info sta[WIL6210_MAX_CID];
|
||||
u32 ring_idle_trsh; /* HW fetches up to 16 descriptors at once */
|
||||
|
|
@ -1081,6 +1082,9 @@ struct wil6210_priv {
|
|||
|
||||
u32 max_agg_wsize;
|
||||
u32 max_ampdu_size;
|
||||
|
||||
struct work_struct pci_linkdown_recovery_worker;
|
||||
void *ipa_handle;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wiphy)
|
||||
|
|
@ -1317,6 +1321,8 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
|
|||
void wil_disable_irq(struct wil6210_priv *wil);
|
||||
void wil_enable_irq(struct wil6210_priv *wil);
|
||||
void wil6210_mask_halp(struct wil6210_priv *wil);
|
||||
irqreturn_t wil6210_irq_misc(int irq, void *cookie);
|
||||
irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie);
|
||||
|
||||
/* P2P */
|
||||
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
|
||||
|
|
@ -1386,6 +1392,9 @@ void wil_enable_tx_key_worker(struct work_struct *work);
|
|||
|
||||
void wil_init_txrx_ops(struct wil6210_priv *wil);
|
||||
|
||||
void wil_fw_recovery(struct wil6210_priv *wil);
|
||||
void wil_pci_linkdown_recovery_worker(struct work_struct *work);
|
||||
|
||||
/* TX API */
|
||||
int wil_ring_init_tx(struct wil6210_vif *vif, int cid);
|
||||
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
|
||||
|
|
@ -1479,14 +1488,15 @@ int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch);
|
|||
int reverse_memcmp(const void *cs, const void *ct, size_t count);
|
||||
|
||||
/* WMI for enhanced DMA */
|
||||
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id);
|
||||
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id, u8 irq_mode);
|
||||
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
|
||||
u16 max_rx_pl_per_desc);
|
||||
u16 max_rx_pl_per_desc, bool checksum);
|
||||
int wil_wmi_rx_sring_add(struct wil6210_priv *wil, u16 ring_id);
|
||||
int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id);
|
||||
int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
|
||||
int tid);
|
||||
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id);
|
||||
int tid, int sring_id, u8 irq_mode);
|
||||
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id,
|
||||
int sring_id);
|
||||
int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
|
||||
u8 tid, u8 token, u16 status, bool amsdu,
|
||||
u16 agg_wsize, u16 timeout);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,7 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2014-2017 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.
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __WIL_PLATFORM_H__
|
||||
|
|
@ -27,6 +17,10 @@ enum wil_platform_event {
|
|||
WIL_PLATFORM_EVT_POST_SUSPEND = 4,
|
||||
};
|
||||
|
||||
enum wil_platform_notif {
|
||||
WIL_PLATFORM_NOTIF_PCI_LINKDOWN = 0,
|
||||
};
|
||||
|
||||
enum wil_platform_features {
|
||||
WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0,
|
||||
WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1,
|
||||
|
|
@ -37,6 +31,7 @@ enum wil_platform_capa {
|
|||
WIL_PLATFORM_CAPA_RADIO_ON_IN_SUSPEND = 0,
|
||||
WIL_PLATFORM_CAPA_T_PWR_ON_0 = 1,
|
||||
WIL_PLATFORM_CAPA_EXT_CLK = 2,
|
||||
WIL_PLATFORM_CAPA_SMMU = 3,
|
||||
WIL_PLATFORM_CAPA_MAX,
|
||||
};
|
||||
|
||||
|
|
@ -52,6 +47,7 @@ struct wil_platform_ops {
|
|||
int (*notify)(void *handle, enum wil_platform_event evt);
|
||||
int (*get_capa)(void *handle);
|
||||
void (*set_features)(void *handle, int features);
|
||||
int (*pci_linkdown_recovery)(void *handle);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -63,10 +59,13 @@ struct wil_platform_ops {
|
|||
* @fw_recovery: start a firmware recovery process. Called as
|
||||
* part of a crash recovery process which may include other
|
||||
* related platform subsystems.
|
||||
* @notify: get notifications from the Platform driver, such as
|
||||
* pci linkdown
|
||||
*/
|
||||
struct wil_platform_rops {
|
||||
int (*ramdump)(void *wil_handle, void *buf, uint32_t size);
|
||||
int (*fw_recovery)(void *wil_handle);
|
||||
int (*notify)(void *wil_handle, enum wil_platform_notif notif);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "wmi.h"
|
||||
#include "trace.h"
|
||||
#include "ftm.h"
|
||||
#include "ipa.h"
|
||||
|
||||
/* set the default max assoc sta to max supported by driver */
|
||||
uint max_assoc_sta = WIL6210_MAX_CID;
|
||||
|
|
@ -2276,6 +2277,9 @@ int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (wil->ipa_handle && cmd.pcp_max_assoc_sta > WIL_IPA_MAX_ASSOC_STA)
|
||||
cmd.pcp_max_assoc_sta = WIL_IPA_MAX_ASSOC_STA;
|
||||
|
||||
if (disable_ap_sme &&
|
||||
!test_bit(WMI_FW_CAPABILITY_AP_SME_OFFLOAD_PARTIAL,
|
||||
wil->fw_capabilities)) {
|
||||
|
|
@ -2943,8 +2947,8 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
|
|||
.ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
|
||||
(agg_wsize << 6)),
|
||||
.ba_timeout = cpu_to_le16(timeout),
|
||||
/* route all the connections to status ring 0 */
|
||||
.status_ring_id = WIL_DEFAULT_RX_STATUS_RING_ID,
|
||||
/* route all the connections to same Rx status ring */
|
||||
.status_ring_id = wil->rx_sring_idx,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
|
|
@ -2956,7 +2960,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid,
|
|||
wil_dbg_wmi(wil,
|
||||
"ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s, sring_id %d\n",
|
||||
cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-",
|
||||
WIL_DEFAULT_RX_STATUS_RING_ID);
|
||||
cmd.status_ring_id);
|
||||
|
||||
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_EDMA_CMDID, mid, &cmd,
|
||||
sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply,
|
||||
|
|
@ -3908,7 +3912,7 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
|
||||
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id, u8 irq_mode)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
|
|
@ -3917,7 +3921,8 @@ int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
|
|||
.ring_cfg = {
|
||||
.ring_size = cpu_to_le16(sring->size),
|
||||
},
|
||||
.irq_index = WIL_TX_STATUS_IRQ_IDX
|
||||
.irq_index = WIL_TX_STATUS_IRQ_IDX,
|
||||
.irq_mode = irq_mode,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr hdr;
|
||||
|
|
@ -3948,7 +3953,8 @@ int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc)
|
||||
int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil,
|
||||
u16 max_rx_pl_per_desc, bool checksum)
|
||||
{
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
|
|
@ -3958,7 +3964,8 @@ int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc)
|
|||
.max_rx_pl_per_desc = cpu_to_le16(max_rx_pl_per_desc),
|
||||
.decap_trans_type = WMI_DECAP_TYPE_802_3,
|
||||
.l2_802_3_offload_ctrl = 0,
|
||||
.l3_l4_ctrl = 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS,
|
||||
.l3_l4_ctrl =
|
||||
(checksum ? 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS : 0),
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr hdr;
|
||||
|
|
@ -4070,10 +4077,9 @@ int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id)
|
|||
}
|
||||
|
||||
int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
|
||||
int tid)
|
||||
int tid, int sring_id, u8 irq_mode)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int sring_id = wil->tx_sring_idx; /* there is only one TX sring */
|
||||
int rc;
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
|
||||
|
|
@ -4090,7 +4096,9 @@ int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
|
|||
.schd_params = {
|
||||
.priority = cpu_to_le16(0),
|
||||
.timeslot_us = cpu_to_le16(0xfff),
|
||||
}
|
||||
},
|
||||
.irq_index = ring_id,
|
||||
.irq_mode = irq_mode,
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr hdr;
|
||||
|
|
@ -4123,7 +4131,8 @@ int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
|
||||
int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id,
|
||||
int sring_id)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wil_ring *ring = &wil->ring_tx[ring_id];
|
||||
|
|
@ -4134,7 +4143,7 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
|
|||
.ring_id = ring_id,
|
||||
},
|
||||
.max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
|
||||
.status_ring_id = wil->tx_sring_idx,
|
||||
.status_ring_id = sring_id,
|
||||
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
|
||||
};
|
||||
struct {
|
||||
|
|
|
|||
Loading…
Reference in a new issue